示例#1
0
    def _answer_query_for_kps_who_dont_like_lists(self, query_graph: QueryGraph) -> Tuple[QGOrganizedKnowledgeGraph, Dict[str, Dict[str, str]]]:
        """
        TRAPI 1.0 says qnode.category and qedge.predicate can both be strings OR lists, but many KPs don't support
        them being lists. So this function pings such KPs one by one for each possible
        subj_category--predicate--obj_category combination.
        """
        qg_copy = eu.copy_qg(query_graph)  # Use a copy of the QG so we don't modify the original
        qnodes = qg_copy.nodes
        qedge_key = next(qedge_key for qedge_key in qg_copy.edges)
        qedge = qg_copy.edges[qedge_key]
        subject_categories = qnodes[qedge.subject].category if qnodes[qedge.subject].category else [None]
        object_categories = qnodes[qedge.object].category if qnodes[qedge.object].category else [None]
        predicates = qedge.predicate if qedge.predicate else [None]
        possible_triples = [(subject_category, predicate, object_category) for subject_category in subject_categories
                            for predicate in predicates for object_category in object_categories]
        answer_kg = QGOrganizedKnowledgeGraph()
        edge_to_nodes_map = dict()
        for possible_triple in possible_triples:
            current_subject_category = possible_triple[0]
            current_predicate = possible_triple[1]
            current_object_category = possible_triple[2]
            # Modify the QG so it's asking only for the current category--predicate--category triple
            qg_copy.nodes[qedge.subject].category = current_subject_category
            qg_copy.nodes[qedge.object].category = current_object_category
            qg_copy.edges[qedge_key].predicate = current_predicate
            self.log.debug(f"Current triple is: {current_subject_category}--{current_predicate}--{current_object_category}")
            sub_kg, sub_edge_to_nodes_map = self._answer_query_using_kp(qg_copy)
            # Merge the answers for this triple into our answers received thus far
            edge_to_nodes_map.update(sub_edge_to_nodes_map)
            answer_kg = eu.merge_two_kgs(sub_kg, answer_kg)

        return answer_kg, edge_to_nodes_map
示例#2
0
    def answer_one_hop_query(self, query_graph: QueryGraph) -> Tuple[QGOrganizedKnowledgeGraph, Dict[str, Dict[str, str]]]:
        """
        This function answers a one-hop (single-edge) query using the specified KP.
        :param query_graph: A TRAPI query graph.
        :return: A tuple containing:
            1. An (almost) TRAPI knowledge graph containing all of the nodes and edges returned as
           results for the query. (Organized by QG IDs.)
            2. A map of which nodes fulfilled which qnode_keys for each edge. Example:
              {'KG1:111221': {'n00': 'DOID:111', 'n01': 'HP:124'}, 'KG1:111223': {'n00': 'DOID:111', 'n01': 'HP:126'}}
        """
        log = self.log
        final_kg = QGOrganizedKnowledgeGraph()
        edge_to_nodes_map = dict()
        qg_copy = eu.copy_qg(query_graph)  # Create a copy so we don't modify the original

        # Verify this query graph is valid, preprocess it for the KP's needs, and make sure it's answerable by the KP
        self._verify_is_one_hop_query_graph(qg_copy)
        if log.status != 'OK':
            return final_kg, edge_to_nodes_map
        qg_copy = self._preprocess_query_graph(qg_copy)
        if log.status != 'OK':
            return final_kg, edge_to_nodes_map
        if not self.kp_name.endswith("KG2"):  # Skip for KG2 for now since predicates/ isn't symmetric yet
            self._verify_qg_is_accepted_by_kp(qg_copy)
        if log.status != 'OK':
            return final_kg, edge_to_nodes_map

        # Answer the query using the KP and load its answers into our object model
        if self.kp_name.endswith("KG2"):
            # Our KPs can handle batch queries (where qnode.id is a list of curies)
            final_kg, edge_to_nodes_map = self._answer_query_using_kp(qg_copy)
        else:
            # Otherwise we need to search for curies one-by-one (until TRAPI includes a batch querying method)
            qedge = next(qedge for qedge in qg_copy.edges.values())
            subject_qnode_curies = eu.convert_to_list(qg_copy.nodes[qedge.subject].id)
            subject_qnode_curies = subject_qnode_curies if subject_qnode_curies else [None]
            object_qnode_curies = eu.convert_to_list(qg_copy.nodes[qedge.object].id)
            object_qnode_curies = object_qnode_curies if object_qnode_curies else [None]
            curie_combinations = [(curie_subj, curie_obj) for curie_subj in subject_qnode_curies for curie_obj in object_qnode_curies]
            # Query KP for all pairs of subject/object curies (pairs look like ("curie1", None) if one has no curies)
            for curie_combination in curie_combinations:
                subject_curie = curie_combination[0]
                object_curie = curie_combination[1]
                qg_copy.nodes[qedge.subject].id = subject_curie
                qg_copy.nodes[qedge.object].id = object_curie
                self.log.debug(f"Current curie pair is: subject: {subject_curie}, object: {object_curie}")
                if self.kp_supports_category_lists and self.kp_supports_predicate_lists:
                    sub_kg, sub_edge_to_nodes_map = self._answer_query_using_kp(qg_copy)
                else:
                    sub_kg, sub_edge_to_nodes_map = self._answer_query_for_kps_who_dont_like_lists(qg_copy)
                edge_to_nodes_map.update(sub_edge_to_nodes_map)
                final_kg = eu.merge_two_kgs(sub_kg, final_kg)

        return final_kg, edge_to_nodes_map
示例#3
0
    def answer_single_node_query(self, single_node_qg: QueryGraph) -> QGOrganizedKnowledgeGraph:
        """
        This function answers a single-node (edge-less) query using the specified KP.
        :param single_node_qg: A TRAPI query graph containing a single node (no edges).
        :return: An (almost) TRAPI knowledge graph containing all of the nodes and edges returned as
           results for the query. (Organized by QG IDs.)
        """
        log = self.log
        final_kg = QGOrganizedKnowledgeGraph()
        qg_copy = eu.copy_qg(single_node_qg)

        # Verify this query graph is valid, preprocess it for the KP's needs, and make sure it's answerable by the KP
        self._verify_is_single_node_query_graph(qg_copy)
        if log.status != 'OK':
            return final_kg
        qg_copy = self._preprocess_query_graph(qg_copy)
        if log.status != 'OK':
            return final_kg

        # Answer the query using the KP and load its answers into our object model
        final_kg, _ = self._answer_query_using_kp(qg_copy)
        return final_kg