From 2e5696ab7db453d6cbd6b66968efc408c397248b Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Mon, 8 Jul 2024 12:43:10 -0400 Subject: [PATCH 01/13] Add an endpoint and a method for the client to add a relation to the dkg --- mira/dkg/api.py | 110 +++++++++++++++++++++++++++++++++++++++++++++ mira/dkg/client.py | 9 ++++ 2 files changed, 119 insertions(+) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index 596e00540..3836dc9ed 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -329,6 +329,116 @@ def get_relations( return [RelationResponse(subject=s, predicate=p, object=o) for s, p, o in records] +@api_blueprint.post( + "/add_relation", + response_model=list[dict[str, str]], + tags=["relations"], +) +def add_relation( + request: Request, + relation_query: RelationQuery = Body( + ..., + examples={ + "source type query": { + "summary": "Query relations with a given source node type", + "value": { + "source_type": "vo", + "limit": 2, + }, + }, + "target type query": { + "summary": "Query relations with a given target node type", + "value": { + "target_type": "stmp", + "limit": 2, + }, + }, + "source/target types query": { + "summary": "Query relations with given source/target types", + "value": { + "source_type": "doid", + "target_type": "symp", + "limit": 2, + }, + }, + "source query": { + "summary": "Query relations with given source node, by CURIE", + "value": { + "source_node": "doid:946", + }, + }, + "target query": { + "summary": "Query relations with given target node, by CURIE", + "value": { + "target_node": "symp:0000570", + }, + }, + "single relation type query": { + "summary": "Query relations with given single relation type", + "value": {"relation": "rdfs:subClassOf", "limit": 2}, + }, + "multiple relation type query": { + "summary": "Query relations with given relation types", + "value": {"relation": ["rdfs:subClassOf", "bfo:0000050"], + "limit": 2}, + }, + "increase path length of query": { + "summary": "Query a given fixed number of hops", + "value": { + "source_curie": "bfo:0000002", + "relation": "rdfs:subClassOf", + "relation_max_hops": 2, + "limit": 2, + }, + }, + "any path length allowed": { + "summary": "Query a variable number of hops", + "description": "Distinct is given as true since there might be multiple paths from the source to each given target.", + "value": { + "source_curie": "bfo:0000002", + "relation": "rdfs:subClassOf", + "relation_max_hops": 0, + "limit": 2, + "distinct": True, + }, + }, + "full results with single relation": { + "summary": "Example query with a single predicate returning full data", + "value": { + "target_curie": "symp:0000570", + "limit": 2, + "full": True, + }, + }, + "full results with multiple relations relation": { + "summary": "Example query with multiple predicates returning full data", + "value": { + "source_curie": "bfo:0000002", + "relation": "rdfs:subClassOf", + "relation_max_hops": 0, + "limit": 2, + "distinct": True, + "full": True, + }, + }, + }, + ), +): + source_curie = relation_query.source_curie + target_curie = relation_query.target_curie + relations = relation_query.relations + if not isinstance(relations, list): + relations = [relations] + request.app.state.client.create_relation(source_curie, target_curie, + relations) + response = [ + {"source_curie": source_curie, "relation": relation, "target_curie": + target_curie} for relation in relations + ] + + return response + + class IsOntChildResult(BaseModel): """Result of a query to /is_ontological_child""" diff --git a/mira/dkg/client.py b/mira/dkg/client.py index d8101f1f5..a5cd59f9e 100644 --- a/mira/dkg/client.py +++ b/mira/dkg/client.py @@ -307,6 +307,15 @@ def create_tx(self, query: str, **query_params): query, **query_params) + def create_relation(self, source_curie, target_curie, relations): + for relation in relations: + query = ( + f"MATCH(source_node {{curie: '{source_curie}'}}), " + f"(target_node {{curie: '{target_curie}' }})" + f"MERGE (source_node)-[:{relation}]->(target_node)" + ) + self.create_tx(query) + def create_single_property_node_index( self, index_name: str, From 543428ece76e5182f09d4f878b3a3c2abe7d3ebb Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Mon, 8 Jul 2024 13:01:00 -0400 Subject: [PATCH 02/13] Remove example for endpoint header and create source and target nodes --- mira/dkg/api.py | 89 +--------------------------------------------- mira/dkg/client.py | 10 ++++-- 2 files changed, 9 insertions(+), 90 deletions(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index 3836dc9ed..48a3fa467 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -336,93 +336,7 @@ def get_relations( ) def add_relation( request: Request, - relation_query: RelationQuery = Body( - ..., - examples={ - "source type query": { - "summary": "Query relations with a given source node type", - "value": { - "source_type": "vo", - "limit": 2, - }, - }, - "target type query": { - "summary": "Query relations with a given target node type", - "value": { - "target_type": "stmp", - "limit": 2, - }, - }, - "source/target types query": { - "summary": "Query relations with given source/target types", - "value": { - "source_type": "doid", - "target_type": "symp", - "limit": 2, - }, - }, - "source query": { - "summary": "Query relations with given source node, by CURIE", - "value": { - "source_node": "doid:946", - }, - }, - "target query": { - "summary": "Query relations with given target node, by CURIE", - "value": { - "target_node": "symp:0000570", - }, - }, - "single relation type query": { - "summary": "Query relations with given single relation type", - "value": {"relation": "rdfs:subClassOf", "limit": 2}, - }, - "multiple relation type query": { - "summary": "Query relations with given relation types", - "value": {"relation": ["rdfs:subClassOf", "bfo:0000050"], - "limit": 2}, - }, - "increase path length of query": { - "summary": "Query a given fixed number of hops", - "value": { - "source_curie": "bfo:0000002", - "relation": "rdfs:subClassOf", - "relation_max_hops": 2, - "limit": 2, - }, - }, - "any path length allowed": { - "summary": "Query a variable number of hops", - "description": "Distinct is given as true since there might be multiple paths from the source to each given target.", - "value": { - "source_curie": "bfo:0000002", - "relation": "rdfs:subClassOf", - "relation_max_hops": 0, - "limit": 2, - "distinct": True, - }, - }, - "full results with single relation": { - "summary": "Example query with a single predicate returning full data", - "value": { - "target_curie": "symp:0000570", - "limit": 2, - "full": True, - }, - }, - "full results with multiple relations relation": { - "summary": "Example query with multiple predicates returning full data", - "value": { - "source_curie": "bfo:0000002", - "relation": "rdfs:subClassOf", - "relation_max_hops": 0, - "limit": 2, - "distinct": True, - "full": True, - }, - }, - }, - ), + relation_query: RelationQuery ): source_curie = relation_query.source_curie target_curie = relation_query.target_curie @@ -435,7 +349,6 @@ def add_relation( {"source_curie": source_curie, "relation": relation, "target_curie": target_curie} for relation in relations ] - return response diff --git a/mira/dkg/client.py b/mira/dkg/client.py index a5cd59f9e..78fd5e496 100644 --- a/mira/dkg/client.py +++ b/mira/dkg/client.py @@ -308,13 +308,19 @@ def create_tx(self, query: str, **query_params): **query_params) def create_relation(self, source_curie, target_curie, relations): + source_node_query = f"MERGE (n {{curie: {source_curie} }})" + target_node_query = f"MERGE (n {{curie: {target_curie} }})" + + self.create_tx(source_node_query) + self.create_tx(target_node_query) + for relation in relations: - query = ( + relation_query = ( f"MATCH(source_node {{curie: '{source_curie}'}}), " f"(target_node {{curie: '{target_curie}' }})" f"MERGE (source_node)-[:{relation}]->(target_node)" ) - self.create_tx(query) + self.create_tx(relation_query) def create_single_property_node_index( self, From 3b696e29963f4015f898084676fd0fe3d0770de8 Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Mon, 8 Jul 2024 14:12:52 -0400 Subject: [PATCH 03/13] Set reponse model to none for testing and add more informative variable names --- mira/dkg/api.py | 4 ++-- mira/dkg/client.py | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index 48a3fa467..c5dbce2ca 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -331,7 +331,7 @@ def get_relations( @api_blueprint.post( "/add_relation", - response_model=list[dict[str, str]], + response_model=None, tags=["relations"], ) def add_relation( @@ -349,7 +349,7 @@ def add_relation( {"source_curie": source_curie, "relation": relation, "target_curie": target_curie} for relation in relations ] - return response + class IsOntChildResult(BaseModel): diff --git a/mira/dkg/client.py b/mira/dkg/client.py index 78fd5e496..b4b699a54 100644 --- a/mira/dkg/client.py +++ b/mira/dkg/client.py @@ -308,19 +308,19 @@ def create_tx(self, query: str, **query_params): **query_params) def create_relation(self, source_curie, target_curie, relations): - source_node_query = f"MERGE (n {{curie: {source_curie} }})" - target_node_query = f"MERGE (n {{curie: {target_curie} }})" + create_source_node_query = f"MERGE (n {{curie: {source_curie} }})" + create_target_node_query = f"MERGE (n {{curie: {target_curie} }})" - self.create_tx(source_node_query) - self.create_tx(target_node_query) + self.create_tx(create_source_node_query) + self.create_tx(create_target_node_query) for relation in relations: - relation_query = ( - f"MATCH(source_node {{curie: '{source_curie}'}}), " - f"(target_node {{curie: '{target_curie}' }})" + create_relation_query = ( + f"MATCH (source_node {{curie: '{source_curie}'}}), " + f"(target_node {{curie: '{target_curie}'}}) " f"MERGE (source_node)-[:{relation}]->(target_node)" ) - self.create_tx(relation_query) + self.create_tx(create_relation_query) def create_single_property_node_index( self, From 2a86f44270e51271309934f42f13b096b618a69c Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Mon, 8 Jul 2024 14:45:31 -0400 Subject: [PATCH 04/13] Change response model to a list of dicts --- mira/dkg/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index c5dbce2ca..90e8dfae7 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -331,7 +331,7 @@ def get_relations( @api_blueprint.post( "/add_relation", - response_model=None, + response_model=list[dict], tags=["relations"], ) def add_relation( @@ -349,7 +349,7 @@ def add_relation( {"source_curie": source_curie, "relation": relation, "target_curie": target_curie} for relation in relations ] - + return response class IsOntChildResult(BaseModel): From 69ebaef8821d4afe6f35cb7fa505b26b247446d9 Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Mon, 8 Jul 2024 14:51:48 -0400 Subject: [PATCH 05/13] Change response model to List for type hinting --- mira/dkg/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index 90e8dfae7..f243a9053 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -331,7 +331,7 @@ def get_relations( @api_blueprint.post( "/add_relation", - response_model=list[dict], + response_model=List[dict[str,str]], tags=["relations"], ) def add_relation( From e34673926bdd9ee7b2b87dc00c821bd60564f5e7 Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Mon, 8 Jul 2024 14:57:46 -0400 Subject: [PATCH 06/13] Add Dict type hinting --- mira/dkg/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index f243a9053..4c36c4e64 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -1,7 +1,7 @@ """API endpoints.""" import itertools as itt -from typing import Any, List, Mapping, Optional, Union +from typing import Any, List, Mapping, Optional, Union, Dict import pydantic from fastapi import APIRouter, Body, HTTPException, Path, Query, Request @@ -331,7 +331,7 @@ def get_relations( @api_blueprint.post( "/add_relation", - response_model=List[dict[str,str]], + response_model=List[Dict[str, str]], tags=["relations"], ) def add_relation( From 93760ec178b6465a2314714634200210f850641b Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Mon, 8 Jul 2024 15:23:16 -0400 Subject: [PATCH 07/13] Add docstrings, examples and quotes to node creation query --- mira/dkg/api.py | 7 ++++++- mira/dkg/client.py | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index 4c36c4e64..3825379a7 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -336,8 +336,13 @@ def get_relations( ) def add_relation( request: Request, - relation_query: RelationQuery + relation_query: RelationQuery = Body( + ..., example={"source_curie": "vo:0000022", + "relations": "vo:0001243", + "target_curie": "ncbitaxon:644"} + ) ): + """Add a relation to the DKG""" source_curie = relation_query.source_curie target_curie = relation_query.target_curie relations = relation_query.relations diff --git a/mira/dkg/client.py b/mira/dkg/client.py index b4b699a54..7e70c8393 100644 --- a/mira/dkg/client.py +++ b/mira/dkg/client.py @@ -308,8 +308,19 @@ def create_tx(self, query: str, **query_params): **query_params) def create_relation(self, source_curie, target_curie, relations): - create_source_node_query = f"MERGE (n {{curie: {source_curie} }})" - create_target_node_query = f"MERGE (n {{curie: {target_curie} }})" + """Add a list of relations to the DKG + + Parameters + ---------- + source_curie : + The curie of the source of the relations to add. + target_curie : + The curie of the target of the relations to add. + relations : + The list containing the predicates to add. + """ + create_source_node_query = f"MERGE (n {{curie: '{source_curie}' }})" + create_target_node_query = f"MERGE (n {{curie: '{target_curie}' }})" self.create_tx(create_source_node_query) self.create_tx(create_target_node_query) From fceb51eddc4cba3c5b6c5d03b36abdad93a7ba96 Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Mon, 8 Jul 2024 15:45:10 -0400 Subject: [PATCH 08/13] Add env variable to turn off endpoint --- mira/dkg/api.py | 54 ++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index 3825379a7..692b0a345 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -1,6 +1,7 @@ """API endpoints.""" import itertools as itt +import os from typing import Any, List, Mapping, Optional, Union, Dict import pydantic @@ -329,32 +330,35 @@ def get_relations( return [RelationResponse(subject=s, predicate=p, object=o) for s, p, o in records] -@api_blueprint.post( - "/add_relation", - response_model=List[Dict[str, str]], - tags=["relations"], -) -def add_relation( - request: Request, - relation_query: RelationQuery = Body( - ..., example={"source_curie": "vo:0000022", - "relations": "vo:0001243", - "target_curie": "ncbitaxon:644"} +active_add_relation_endpoint = os.getenv('MIRA_ADD_RELATION_ENDPOINT') + +if active_add_relation_endpoint: + @api_blueprint.post( + "/add_relation", + response_model=List[Dict[str, str]], + tags=["relations"], ) -): - """Add a relation to the DKG""" - source_curie = relation_query.source_curie - target_curie = relation_query.target_curie - relations = relation_query.relations - if not isinstance(relations, list): - relations = [relations] - request.app.state.client.create_relation(source_curie, target_curie, - relations) - response = [ - {"source_curie": source_curie, "relation": relation, "target_curie": - target_curie} for relation in relations - ] - return response + def add_relation( + request: Request, + relation_query: RelationQuery = Body( + ..., example={"source_curie": "vo:0000022", + "relations": "vo:0001243", + "target_curie": "ncbitaxon:644"} + ) + ): + """Add a relation to the DKG""" + source_curie = relation_query.source_curie + target_curie = relation_query.target_curie + relations = relation_query.relations + if not isinstance(relations, list): + relations = [relations] + request.app.state.client.create_relation(source_curie, target_curie, + relations) + response = [ + {"source_curie": source_curie, "relation": relation, "target_curie": + target_curie} for relation in relations + ] + return response class IsOntChildResult(BaseModel): From a36f211ed79aa3827a73257642744ebc1af49844 Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Mon, 8 Jul 2024 16:51:25 -0400 Subject: [PATCH 09/13] Use 'has_parameter' relationship type when creating edges --- mira/dkg/api.py | 15 ++++----------- mira/dkg/client.py | 22 ++++++++++++---------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index 692b0a345..589498b07 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -335,7 +335,7 @@ def get_relations( if active_add_relation_endpoint: @api_blueprint.post( "/add_relation", - response_model=List[Dict[str, str]], + response_model=Dict[str, str], tags=["relations"], ) def add_relation( @@ -349,16 +349,9 @@ def add_relation( """Add a relation to the DKG""" source_curie = relation_query.source_curie target_curie = relation_query.target_curie - relations = relation_query.relations - if not isinstance(relations, list): - relations = [relations] - request.app.state.client.create_relation(source_curie, target_curie, - relations) - response = [ - {"source_curie": source_curie, "relation": relation, "target_curie": - target_curie} for relation in relations - ] - return response + request.app.state.client.create_relation(source_curie, target_curie) + return {"source_curie": source_curie, "relation": "has_parameter", + "target_curie": target_curie} class IsOntChildResult(BaseModel): diff --git a/mira/dkg/client.py b/mira/dkg/client.py index 7e70c8393..b9c47b901 100644 --- a/mira/dkg/client.py +++ b/mira/dkg/client.py @@ -307,7 +307,7 @@ def create_tx(self, query: str, **query_params): query, **query_params) - def create_relation(self, source_curie, target_curie, relations): + def create_relation(self, source_curie, target_curie): """Add a list of relations to the DKG Parameters @@ -316,8 +316,6 @@ def create_relation(self, source_curie, target_curie, relations): The curie of the source of the relations to add. target_curie : The curie of the target of the relations to add. - relations : - The list containing the predicates to add. """ create_source_node_query = f"MERGE (n {{curie: '{source_curie}' }})" create_target_node_query = f"MERGE (n {{curie: '{target_curie}' }})" @@ -325,13 +323,17 @@ def create_relation(self, source_curie, target_curie, relations): self.create_tx(create_source_node_query) self.create_tx(create_target_node_query) - for relation in relations: - create_relation_query = ( - f"MATCH (source_node {{curie: '{source_curie}'}}), " - f"(target_node {{curie: '{target_curie}'}}) " - f"MERGE (source_node)-[:{relation}]->(target_node)" - ) - self.create_tx(create_relation_query) + create_relation_query = ( + f"MATCH (source_node {{curie: '{source_curie}'}}), " + f"(target_node {{curie: '{target_curie}'}}) " + f"MERGE (source_node)-[rel:has_parameter]->(target_node)" + f"SET rel.pred = 'probonto:c0000062'" + f"SET rel.source = 'probonto'" + f"SET rel.version = '2.5'" + f"SET rel.graph = 'https://raw.githubusercontent.com/probonto/ontology/master/probonto4ols.owl'" + ) + + self.create_tx(create_relation_query) def create_single_property_node_index( self, From 217caf86e7bac65b3bded8c11751b6f10c442422 Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Tue, 9 Jul 2024 11:16:52 -0400 Subject: [PATCH 10/13] Remove relation entry from example --- mira/dkg/api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index 589498b07..013f15adf 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -342,7 +342,6 @@ def add_relation( request: Request, relation_query: RelationQuery = Body( ..., example={"source_curie": "vo:0000022", - "relations": "vo:0001243", "target_curie": "ncbitaxon:644"} ) ): From cc13288eeb4300df1e824513040119a929373c45 Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Tue, 9 Jul 2024 13:14:06 -0400 Subject: [PATCH 11/13] Add a add_nodes endpoint that accepts a list of askem entities or entities --- mira/dkg/api.py | 34 +++++++++++++++++----------- mira/dkg/client.py | 55 +++++++++++++++++++++++++++++----------------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index 013f15adf..7ac8b5f01 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -334,23 +334,31 @@ def get_relations( if active_add_relation_endpoint: @api_blueprint.post( - "/add_relation", - response_model=Dict[str, str], + "/add_nodes", + response_model=Union[AskemEntity,Entity], tags=["relations"], ) - def add_relation( + def add_nodes( request: Request, - relation_query: RelationQuery = Body( - ..., example={"source_curie": "vo:0000022", - "target_curie": "ncbitaxon:644"} - ) + node_list: List[Union[AskemEntity, Entity]] + ): + """Add a list of nodes to the DKG""" + for entity in node_list: + request.app.state.client.add_node(entity) + return node_list[0] + + @api_blueprint.post( + "/add_relations", + response_model=None, + tags=["relations"], + ) + def add_relations( + request: Request, + relation_list: List[Dict[str, Any]] ): - """Add a relation to the DKG""" - source_curie = relation_query.source_curie - target_curie = relation_query.target_curie - request.app.state.client.create_relation(source_curie, target_curie) - return {"source_curie": source_curie, "relation": "has_parameter", - "target_curie": target_curie} + """Add a list of relations to the DKG""" + for relation in relation_list: + request.app.state.client.relation(relation) class IsOntChildResult(BaseModel): diff --git a/mira/dkg/client.py b/mira/dkg/client.py index b9c47b901..37cf00dd5 100644 --- a/mira/dkg/client.py +++ b/mira/dkg/client.py @@ -307,33 +307,48 @@ def create_tx(self, query: str, **query_params): query, **query_params) - def create_relation(self, source_curie, target_curie): - """Add a list of relations to the DKG + def add_node(self, entity): + """Add a node to the DKG Parameters ---------- - source_curie : - The curie of the source of the relations to add. - target_curie : - The curie of the target of the relations to add. + entity: + The node that will be added to the DKG """ - create_source_node_query = f"MERGE (n {{curie: '{source_curie}' }})" - create_target_node_query = f"MERGE (n {{curie: '{target_curie}' }})" + curie = entity.id + name = entity.name + type = entity.type + obsolete = entity.obsolete + description = entity.description + synonyms = entity.synonyms + alts = entity.alts + xrefs = entity.xrefs + labels = entity.labels + + create_source_node_query = ( + f"MERGE (n {{curie: '{curie}', " + f"name: '{name}', " + f"type: '{type}', " + f"obsolete: {obsolete}, " + f"description: '{description}', " + f"synonyms: {synonyms}, " + f"alts: {alts}, " + f"xrefs: {xrefs}, " + f"labels: {labels} }} )" + ) self.create_tx(create_source_node_query) - self.create_tx(create_target_node_query) - - create_relation_query = ( - f"MATCH (source_node {{curie: '{source_curie}'}}), " - f"(target_node {{curie: '{target_curie}'}}) " - f"MERGE (source_node)-[rel:has_parameter]->(target_node)" - f"SET rel.pred = 'probonto:c0000062'" - f"SET rel.source = 'probonto'" - f"SET rel.version = '2.5'" - f"SET rel.graph = 'https://raw.githubusercontent.com/probonto/ontology/master/probonto4ols.owl'" - ) - self.create_tx(create_relation_query) + def add_relation(self, relation_dict): + """Add a relation to the DKG + + Parameters + ---------- + relation_dict: + The dictionary containing the relationship information + """ + + pass def create_single_property_node_index( self, From da24cffe73a340cc8f0950a5ef158bbe46446b4a Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Tue, 9 Jul 2024 13:43:35 -0400 Subject: [PATCH 12/13] Add add_relation endpoint processing Relationship object models --- mira/dkg/api.py | 9 ++++----- mira/dkg/client.py | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/mira/dkg/api.py b/mira/dkg/api.py index 7ac8b5f01..c109beb1f 100644 --- a/mira/dkg/api.py +++ b/mira/dkg/api.py @@ -11,7 +11,7 @@ from scipy.spatial import distance from typing_extensions import Literal -from mira.dkg.client import AskemEntity, Entity +from mira.dkg.client import AskemEntity, Entity, Relation from mira.dkg.utils import DKG_REFINER_RELS __all__ = [ @@ -335,7 +335,7 @@ def get_relations( if active_add_relation_endpoint: @api_blueprint.post( "/add_nodes", - response_model=Union[AskemEntity,Entity], + response_model=None, tags=["relations"], ) def add_nodes( @@ -345,7 +345,6 @@ def add_nodes( """Add a list of nodes to the DKG""" for entity in node_list: request.app.state.client.add_node(entity) - return node_list[0] @api_blueprint.post( "/add_relations", @@ -354,11 +353,11 @@ def add_nodes( ) def add_relations( request: Request, - relation_list: List[Dict[str, Any]] + relation_list: List[Relation] ): """Add a list of relations to the DKG""" for relation in relation_list: - request.app.state.client.relation(relation) + request.app.state.client.add_relation(relation) class IsOntChildResult(BaseModel): diff --git a/mira/dkg/client.py b/mira/dkg/client.py index 37cf00dd5..7411b5a38 100644 --- a/mira/dkg/client.py +++ b/mira/dkg/client.py @@ -41,6 +41,17 @@ TxResult: TypeAlias = Optional[List[List[Any]]] +class Relation(BaseModel): + """A relationship between two entities in the DKG""" + source_curie: str + target_curie: str + type: str + pred: str + source: str + graph: str + version: str + + class Entity(BaseModel): """An entity in the domain knowledge graph.""" @@ -313,7 +324,7 @@ def add_node(self, entity): Parameters ---------- entity: - The node that will be added to the DKG + The node object that will be added to the DKG """ curie = entity.id name = entity.name @@ -339,16 +350,34 @@ def add_node(self, entity): self.create_tx(create_source_node_query) - def add_relation(self, relation_dict): + def add_relation(self, relation): """Add a relation to the DKG Parameters ---------- - relation_dict: - The dictionary containing the relationship information + relation: + The relation object that will be added to the DKG """ + source_curie = relation.source_curie + target_curie = relation.target_curie + type = relation.type + pred = relation.pred + source = relation.source + version = relation.version + graph = relation.graph + + create_relation_query = ( + f"MATCH (source_node {{curie: '{source_curie}'}}), " + f"(target_node {{curie: '{target_curie}'}}) " + f"MERGE (source_node)-[rel:{type}]->(target_node)" + f"SET rel.pred = '{pred}'" + f"SET rel.source = '{source}'" + f"SET rel.version = '{version}'" + f"SET rel.graph = '{graph}'" + ) + + self.create_tx(create_relation_query) - pass def create_single_property_node_index( self, From 7c07b5e2b94ca26a99caf6874b821fada801272c Mon Sep 17 00:00:00 2001 From: nanglo123 Date: Tue, 9 Jul 2024 14:03:56 -0400 Subject: [PATCH 13/13] Add description and examples for properties of the Relation class --- mira/dkg/client.py | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/mira/dkg/client.py b/mira/dkg/client.py index 7411b5a38..7b9e2d162 100644 --- a/mira/dkg/client.py +++ b/mira/dkg/client.py @@ -43,13 +43,30 @@ class Relation(BaseModel): """A relationship between two entities in the DKG""" - source_curie: str - target_curie: str - type: str - pred: str - source: str - graph: str - version: str + source_curie: str = Field( + description="The curie of the source node", example="probonto:k0000000" + ) + target_curie: str = Field( + description="The curie of the target node", example="probonto:k0000007" + ) + type: str = Field( + description="The type of the relation", example="has_parameter" + ) + pred: str = Field( + description="The curie of the relation type", + example="probonto:c0000062" + ) + source: str = Field( + description="The prefix of the relation curie", example="probonto" + ) + graph: str = Field( + description="The URI of the relation", + example="https://raw.githubusercontent.com/probonto" + "/ontology/master/probonto4ols.owl" + ) + version: str = Field( + description="The version number", example="2.5" + ) class Entity(BaseModel):