Cypher Query
This section covers some specifics on how the Graph is structured and returned to the end user.
Buyer Query Structure
MATCH (o:Organization)<-[e:hasBuyer]-(n:Release)-[e2:hasContracts|:hasAwards|:hasTender]->(n2)-[e3*0..2]-(o3:Organization)
WHERE o.id = $id AND n.date >= '{start_date}' AND n.date < '{end_date}'
OPTIONAL MATCH (o)-[i:isSameAs]->(o2:Organization)
WHERE i.probability > {match_probability}
RETURN o, e, n, e2, n2, i, o2, e3, o3 SKIP {skip} LIMIT {limit}
Components Explained
Primary Match Criteria:
- Identifies a Release where 'o' is a buyer Organization.
(o:Organization)<-[e:hasBuyer]-(n:Release)
- Connects Release to an entity 'n2' (e.g. Contract, Award, or Tender).
(n)-[e2:hasContracts|:hasAwards|:hasTender]->(n2)
- Optionally connects 'n2' to another organization 'o3' via up to two intermediate relationships or nodes, allowing for secondary or indirect relationships.
(n2)-[e3*0..2]-(o3:Organization)
Filtering Conditions:
- Filters are applied to ensure that only data matching the given organization ID and within the specified date range is considered.
- An additional filter applies to the optional matching of organization aliases based on a probability threshold.
Optional Match:
- Attempts to identify and include any potential duplicate or synonymous organizations to 'o' (designated as 'o2'), provided the match probability exceeds a specified threshold.
Return Statement:
- The query returns the following elements:
- o, o2 (Organizations): The primary organization and any potentially matched synonymous organization.
- e (hasBuyer Relationship): The relationship showing the organization as the buyer of a release.
- n (Release): The procurement release node.
- e2 (Transaction Relationships): Relationships indicating the type of transaction (contract, award, or tender).
- n2 (Transaction Entity): The node representing the transaction.
- i (isSameAs Relationship): The relationship, if any, indicating that 'o' is the same as 'o2'.
- e3 (Intermediate Relationships): Any relationships connecting 'n2' to 'o3'.
- o3 (Secondary Organizations): Other organizations potentially connected to the transaction indirectly.
Pagination:
SKIP {skip}
andLIMIT {limit}
control the pagination of the results, allowing developers to fetch data in manageable chunks.
Supplier Query Structure
Primary Match Criteria
- Identifies a Release that has Award(s) that are related to supplier Organization 'supplierOrg'.
(supplierOrg:Organization)<-[supplierRel:hasSuppliers]-(awardNode:Award)<-[awardRel:hasAwards]-(releaseNode:Release)
- Connects Release to an entity 'transactionNode' (e.g. Contract, Award, or Tender).
(releaseNode:Release)-[transactionRel:hasContracts|hasAwards|hasTender]->(transactionNode)
- Optionally connects 'transactionNode' to another organization 'relatedOrg' through up to two intermediate relationships or nodes, allowing for secondary or indirect relationships.
(transactionNode)-[orgRel*0..2]-(relatedOrg:Organization)
Other Sections
- Other sections are the same as the buyer query, so please refer back to buyer query.
Graph Endpoint Function
The Graph function has multiple parameters that allow users to:
- get graph based on Organizations ID
- filter results by date
- limit the size of the returned results
- skip certain number of results they want returned
async def get_organization_graph(
id: uuid.UUID,
start_date: datetime.date = None,
end_date: datetime.date = None,
match_probability: float = 0.75,
limit: int = 400,
skip: int = 0,
...,
):
In a case where a user doesn't provide a specific start and end date, the function sets 'end_date' to today and 'start_date' to a date one year before today.
if end_date is None:
end_date = datetime.date.today()
if start_date is None:
start_date = datetime.date(end_date.year - 1, end_date.month, end_date.day)
The function then retrieves the organization based on provided ID, and saves it to a variable. That variable is later used to allow the function to select if the supplier or buyer query needs to be executed.
# Find out whether the organization is a buyer or a supplier
organization = await get_organization(id, conn)
...
...
if "buyer" in organization.roles ...
elif organization.roles == "supplier": ...
Results of the query are then processed to OCDSGraph and an OCDSGraph is returned by the function.