def query_entity(self):
        nmatcher = NodeMatcher(self.graph)
        rmatcher = RelationshipMatcher(self.graph)

        # 大通有哪些车
        a_node = nmatcher.match('品牌', name='上汽大通').first()
        b_node = nmatcher.match('车系').first()
        relation = rmatcher.match({a_node, b_node}).first()
        zz = self.graph.match((a_node, ), r_type=type(relation).__name__).all()
        result = []
        for z in zz:
            result.append(z.end_node.get('name'))
        print('大通具有:')
        print(result)
        # nodes = rmatcher.match({a_node, b_node}).all()
        # print(nodes[0])
        # print(nodes[0].start_node)
        # print(nodes[0].end_node)
        # print(nodes[0].nodes)
        # print(type(nodes[0]).__name__)

        #
        # A(实体)车的基本参数(实体)
        a_node = nmatcher.match('车型', name='2019款 2.0T柴油自动四驱精英型长厢高底盘').first()
        b_node = nmatcher.match('基本参数').first()
        relation = rmatcher.match({a_node, b_node}).first()
        print(relation)
        print(type(relation).__name__)
        print(dict(nmatcher.match(name='2019款 2.0T柴油自动四驱精英型长厢高底盘').first()))
        zz = self.graph.match(nodes=(relation.start_node, ),
                              r_type=type(relation).__name__).all()[0].end_node
        print(zz)
예제 #2
0
    def relationships(self):
        """ A :class:`.RelationshipMatcher` for this graph.

        This can be used to find relationships that match given criteria
        as well as efficiently count relationships.
        """
        return RelationshipMatcher(self)
예제 #3
0
def match():
    """这里的节点是正常的,它有两个属性name和age
    name是Liz age是34
    match("Person").where(age=34).first() 正常
    match("Person").where(name='Liz').first() 正常
    match("Person", name="Liz").first() 正常
    match("Person", age=34).first() 正常
    match("Person", age=34).where(name="Liz").first() None
    match("Person", name="Liz").where(age=34).first() None
    """
    matcher_1 = NodeMatcher(graph)
    matcher_2 = RelationshipMatcher(graph)
    # TODO: 这里的 age 属性使用后返回结果为 None
    node = matcher_1.match("Person", name="Liz").where(age=34).first()
    relation = matcher_2.match(r_type='FRIENDS')
    return list(relation), node, type(relation)
    def query_test(self):
        nmatcher = NodeMatcher(self.graph)
        rmatcher = RelationshipMatcher(self.graph)
        # A车的基本参数
        a_node = nmatcher.match('车型', name='2019款 2.0T柴油自动四驱精英型长厢高底盘').first()

        # relation = rmatcher.match({a_node, b_node}).first()
        relation = self.graph.match(nodes=(a_node, ), r_type='基本参数').all()
        print(dict(relation[0].end_node))
        # gg = self.graph.match(nodes=(relation.start_node, relation.end_node)).all()

        #
        b_node = nmatcher.match('车型基本参数', name='基本参数节点').first()
예제 #5
0
    def match(self, nodes=None, r_type=None, limit=None):
        """ Match and return all relationships with specific criteria.

        For example, to find all of Alice's friends::

            for rel in graph.match((alice, ), r_type="FRIEND"):
                print(rel.end_node["name"])

        :param nodes: Sequence or Set of start and end nodes (:const:`None` means any node);
                a Set implies a match in any direction
        :param r_type: type of relationships to match (:const:`None` means any type)
        :param limit: maximum number of relationships to match (:const:`None` means unlimited)
        """
        return RelationshipMatcher(self).match(nodes=nodes, r_type=r_type).limit(limit)
예제 #6
0
파일: json.py 프로젝트: drahnreb/py2neo
 def hydrate_object(obj, inst=None):
     from py2neo.data import Node, Relationship, Path
     from py2neo.client.packstream import Structure
     if isinstance(obj, Structure):
         tag = obj.tag
         fields = obj.fields
         if tag == ord(b"N"):
             return Node.hydrate(self.graph, fields[0], fields[1], hydrate_object(fields[2]), into=inst)
         elif tag == ord(b"R"):
             return Relationship.hydrate(self.graph, fields[0],
                                              fields[1], fields[2],
                                              fields[3], hydrate_object(fields[4]), into=inst)
         elif tag == ord(b"P"):
             # Herein lies a dirty hack to retrieve missing relationship
             # detail for paths received over HTTP.
             nodes = [hydrate_object(node) for node in fields[0]]
             u_rels = []
             typeless_u_rel_ids = []
             for r in fields[1]:
                 u_rel = self.unbound_relationship(*map(hydrate_object, r))
                 assert u_rel.type is None
                 typeless_u_rel_ids.append(u_rel.id)
                 u_rels.append(u_rel)
             if typeless_u_rel_ids:
                 r_dict = {r.identity: r for r in RelationshipMatcher(graph).get(typeless_u_rel_ids)}
                 for i, u_rel in enumerate(u_rels):
                     if u_rel.type is None:
                         u_rels[i] = self.unbound_relationship(
                             u_rel.id,
                             type(r_dict[u_rel.id]).__name__,
                             u_rel.properties
                         )
             sequence = fields[2]
             return Path.hydrate(self.graph, nodes, u_rels, sequence)
         else:
             try:
                 f = self.hydration_functions[tag]
             except KeyError:
                 # If we don't recognise the structure type, just return it as-is
                 return obj
             else:
                 return f(*map(hydrate_object, obj.fields))
     elif isinstance(obj, list):
         return list(map(hydrate_object, obj))
     elif isinstance(obj, dict):
         return {key: hydrate_object(value) for key, value in obj.items()}
     else:
         return obj
예제 #7
0
파일: json.py 프로젝트: timgates42/py2neo
 def hydrate_object(self, obj):
     log.debug("Hydrating object %r", obj)
     from py2neo.data import Node, Relationship, Path
     if isinstance(obj, Structure):
         tag = obj.tag
         fields = obj.fields
         if tag == ord(b"N"):
             obj = Node.ref(self.graph, fields[0])
             if fields[1] is not None:
                 obj._remote_labels = frozenset(fields[1])
                 obj.clear_labels()
                 obj.update_labels(fields[1])
             if fields[2] is not None:
                 obj.clear()
                 obj.update(self.hydrate_object(fields[2]))
             return obj
         elif tag == ord(b"R"):
             start_node = Node.ref(self.graph, fields[1])
             end_node = Node.ref(self.graph, fields[2])
             obj = Relationship.ref(self.graph, fields[0], start_node,
                                    fields[3], end_node)
             if fields[4] is not None:
                 obj.clear()
                 obj.update(self.hydrate_object(fields[4]))
             return obj
         elif tag == ord(b"P"):
             # Herein lies a dirty hack to retrieve missing relationship
             # detail for paths received over HTTP.
             nodes = [self.hydrate_object(node) for node in fields[0]]
             u_rels = []
             typeless_u_rel_ids = []
             for r in fields[1]:
                 u_rel = self.unbound_relationship(
                     *map(self.hydrate_object, r))
                 assert u_rel.type is None
                 typeless_u_rel_ids.append(u_rel.id)
                 u_rels.append(u_rel)
             if typeless_u_rel_ids:
                 r_dict = {
                     r.identity: r
                     for r in RelationshipMatcher(self.graph).get(
                         typeless_u_rel_ids)
                 }
                 for i, u_rel in enumerate(u_rels):
                     if u_rel.type is None:
                         u_rels[i] = self.unbound_relationship(
                             u_rel.id,
                             type(r_dict[u_rel.id]).__name__,
                             u_rel.properties)
             sequence = fields[2]
             return Path.hydrate(self.graph, nodes, u_rels, sequence)
         else:
             try:
                 f = self.hydration_functions[tag]
             except KeyError:
                 # If we don't recognise the structure type, just return it as-is
                 return obj
             else:
                 return f(*map(self.hydrate_object, obj.fields))
     elif isinstance(obj, list):
         return list(map(self.hydrate_object, obj))
     elif isinstance(obj, dict):
         return {
             key: self.hydrate_object(value)
             for key, value in obj.items()
         }
     else:
         return obj
# coding:utf-8
from py2neo import Graph, Node, data, Path, Relationship
from py2neo.matching import \
    NodeMatcher, RelationshipMatcher, \
    EQ, NE, LT, LE, GT, GE, \
    STARTS_WITH, ENDS_WITH, CONTAINS, LIKE, \
    IN, AND, OR, XOR

import pandas as pd

graph = Graph('http://localhost:7474', username='******', password='******')
graphMather = RelationshipMatcher(graph=graph)

data = pd.read_excel('./data/test3.xlsx', index_col=0)

for index in data.index:
    content = data.loc[index].dropna()

    #### 创建车系节点 ##########################################################
    car_series_node = graph.nodes.match('车系', name=content['车系1']).first()
    if car_series_node == None:
        car_series_node = Node('车系', name=content['车系1'])
        graph.create(car_series_node)
    ##############################################################

    #### 创建车型节点 ###########################################
    car_model_node = Node('车型', name=content['车型'])
    graph.create(car_model_node)
    ###############################################

    #### 创建车系车型边######################################
예제 #9
0
 def hydrate_object(obj, inst=None):
     from py2neo.data import Path
     if isinstance(obj, Structure):
         tag = obj.tag
         fields = obj.fields
         if tag == b"N":
             return self.hydrate_node(inst, fields[0], fields[1], hydrate_object(fields[2]))
         elif tag == b"R":
             return self.hydrate_relationship(inst, fields[0],
                                              fields[1], fields[2],
                                              fields[3], hydrate_object(fields[4]))
         elif tag == b"P":
             # Herein lies a dirty hack to retrieve missing relationship
             # detail for paths received over HTTP.
             nodes = [hydrate_object(node) for node in fields[0]]
             u_rels = []
             typeless_u_rel_ids = []
             for r in fields[1]:
                 u_rel = self.unbound_relationship(*map(hydrate_object, r))
                 assert u_rel.type is None
                 typeless_u_rel_ids.append(u_rel.id)
                 u_rels.append(u_rel)
             if typeless_u_rel_ids:
                 r_dict = {r.identity: r for r in RelationshipMatcher(graph).get(typeless_u_rel_ids)}
                 for i, u_rel in enumerate(u_rels):
                     if u_rel.type is None:
                         u_rels[i] = self.unbound_relationship(
                             u_rel.id,
                             type(r_dict[u_rel.id]).__name__,
                             u_rel.properties
                         )
             sequence = fields[2]
             last_node = nodes[0]
             steps = [last_node]
             for i, rel_index in enumerate(sequence[::2]):
                 next_node = nodes[sequence[2 * i + 1]]
                 if rel_index > 0:
                     u_rel = u_rels[rel_index - 1]
                     rel = self.hydrate_relationship(None, u_rel.id,
                                                     last_node.identity, next_node.identity,
                                                     u_rel.type, u_rel.properties)
                 else:
                     u_rel = u_rels[-rel_index - 1]
                     rel = self.hydrate_relationship(None, u_rel.id,
                                                     next_node.identity, last_node.identity,
                                                     u_rel.type, u_rel.properties)
                 steps.append(rel)
                 # steps.append(next_node)
                 last_node = next_node
             return Path(*steps)
         else:
             try:
                 f = self.hydration_functions[obj.tag]
             except KeyError:
                 # If we don't recognise the structure type, just return it as-is
                 return obj
             else:
                 return f(*map(hydrate_object, obj.fields))
     elif isinstance(obj, list):
         return list(map(hydrate_object, obj))
     elif isinstance(obj, dict):
         return {key: hydrate_object(value) for key, value in obj.items()}
     else:
         return obj
예제 #10
0
 def __init__(self):
     self.tx = g.begin()
     self.schema = Schema(g)
     self.n_matcher = NodeMatcher(g)
     self.r_matcher = RelationshipMatcher(g)
예제 #11
0
 def __post_init__(self):
     self.nmatcher = NodeMatcher(self.graph)
     self.rmatcher = RelationshipMatcher(self.graph)
예제 #12
0
class NLMGraph:
    """
    The Memory Graph.

    Parameters
    -----------
    graph: Graph
        The Neo4j Graph instance.
    """

    graph: Graph

    def __post_init__(self):
        self.nmatcher = NodeMatcher(self.graph)
        self.rmatcher = RelationshipMatcher(self.graph)

    @raise_customized_error(Exception, DatabaseError)
    def push_graph(self, subgraph: Subgraph) -> bool:
        """
        Push a subgraph (node, relationship, subgraph) to the Neo database.
        """
        tx = self.graph.begin()
        tx.create(subgraph)
        tx.commit()
        return tx.finished()

    def add_node(self, label: str, name: str, props: dict) -> Node:
        """
        Add a Node to database.

        Parameters
        ------------
        label: Node label
        name: Node name
        props: Node property

        Returns
        --------
        out: a Node.
        """
        node = Node(label, name=name, **props)
        self.push_graph(node)
        return node

    def check_update_node(self,
                          nlmgn: GraphNode,
                          update_props: bool = False) -> Node:
        """
        Check whether the given node is already in the graph.

        Parameters
        ------------
        nlmgn: GraphNode
            The defined Node data type.
            Includes name, labels and properties.
        
        Returns
        --------
        out: Node
            Whether it is already in the graph.
            If is, update with the new properties, if necessary and return the updated node.
            If not, return the created Node (and need to commit to the graph).
        """
        label, name, props = nlmgn.label, nlmgn.name, nlmgn.props
        neogn = self.nmatcher.match(label, name=name).first()
        if neogn:
            if update_props:
                node = self.update_property(neogn, props)
            else:
                node = neogn
        else:
            node = self.add_node(label, name, props)
        return node

    @raise_customized_error(Exception, DatabaseError)
    def update_property(self, neog_oj, props: dict):
        """
        Update a neo graph node or relationship.

        Parameters
        ------------
        neog_oj: neo graph object, Node or Relationship

        Returns
        --------
        out: updated  Node or Relationship
        """
        neog_oj_props = dict(neog_oj)
        if props and props != neog_oj_props:
            # make sure new props is behind the exisited props.
            neog_oj.update({**neog_oj_props, **props})
            # only can be pushed when neog_oj is already in the graph
            # so we do not need push_graph function here
            self.graph.push(neog_oj)
        return neog_oj

    def add_relationship(self, start: Node, end: Node, kind: str,
                         props: dict) -> Relationship:
        """
        Add a Relationship to database.

        Parameters
        ------------
        start: start Node
        end: end Node
        kind: Relationship kind
        props: Relationship property

        Returns
        --------
        out: a Relationship.
        """
        relation = Relationship(start, kind, end, **props)
        self.push_graph(relation)
        return relation

    def check_update_relationship(self,
                                  nlmgr: GraphRelation,
                                  update_props: bool = False) -> Relationship:
        """
        Parameters
        ------------
        nlmgr: GraphRelation
            The defined Relationship data type.
            Includes kind, start, end and properties.

        Returns
        --------
        out: Relationship
        """
        kind, props = nlmgr.kind, nlmgr.props
        start = self.check_update_node(nlmgr.start, update_props)
        end = self.check_update_node(nlmgr.end, update_props)
        neogr = self.rmatcher.match((start, end), r_type=kind).first()
        if neogr:
            if update_props:
                relation = self.update_property(neogr, props)
            else:
                relation = neogr
        else:
            relation = self.add_relationship(start, end, kind, props)
        return relation

    def add(self, gin: GraphRelation
            or GraphNode) -> Node or List[Node] or Relationship:
        """
        Add a Node or Relationship to the database.

        Parameters
        ------------
        gin: A GraphNode or GraphRelation (kind could be None)

        Returns
        --------
        out: A Node or Relationship.
        """
        if isinstance(gin, GraphNode):
            return self.add_node(gin.label, gin.name, gin.props)
        elif isinstance(gin, GraphRelation) and gin.kind:
            start = self.check_update_node(gin.start)
            end = self.check_update_node(gin.end)
            return self.add_relationship(start, end, gin.kind, gin.props)
        elif isinstance(gin, GraphRelation) and gin.kind == None:
            start = self.check_update_node(gin.start)
            end = self.check_update_node(gin.end)
            return (start, end)
        else:
            raise InputError

    def update(
            self, gin: GraphRelation
        or GraphNode) -> Node or List[Node] or Relationship:
        """
        Update the property of a Node or Relationship to the database.

        Parameters
        ------------
        gin: A GraphNode or GraphRelation (kind could be None)

        Returns
        --------
        out: A Node or Relationship.
        """
        if isinstance(gin, GraphNode):
            return self.check_update_node(gin, update_props=True)
        elif isinstance(gin, GraphRelation) and gin.kind:
            return self.check_update_relationship(gin, update_props=True)
        elif isinstance(gin, GraphRelation) and gin.kind == None:
            start = self.check_update_node(gin.start, update_props=True)
            end = self.check_update_node(gin.end, update_props=True)
            return (start, end)
        else:
            raise InputError

    def query(self, qin, topn=1, limit=10, fuzzy=False) -> list:
        """
        Query by user given.
        
        Parameters
        -----------
        qin: could be GraphNode, GraphRelation, or just Cypher.

        Returns
        ---------
        out: queried Nodes or Relationships.

        """
        if isinstance(qin, GraphNode):
            ret = self._query_by_node(qin, topn, limit, fuzzy)
        elif isinstance(qin, GraphRelation):
            ret = self._query_by_relation(qin, topn, limit, fuzzy)
        elif isinstance(qin, str):
            ret = self._query_by_cypher(qin)
        else:
            raise InputError
        return ret

    def _sort_matched(self, matched_nodes: list, props: dict) -> list:
        """
        Sort matched nodes by comparing their properties with the given props.
        """
        ret = []
        for node in matched_nodes:
            nprops = dict(node)
            num = 0
            for k, v in props.items():
                if k in nprops and nprops[k] == v:
                    num += 1
            ret.append((node, num))
        sorted_ret = sorted(ret, key=lambda x: x[1], reverse=True)
        return [n for (n, _) in sorted_ret]

    @raise_customized_error(Exception, QueryError)
    def _query_by_node(self, gn: GraphNode, topn: int, limit: int,
                       fuzzy: bool) -> List[Node]:
        """
        Query node by given label and name.
        If None, then by those nodes whose nodes contains the given name
        """
        label, name, props = gn.label, gn.name, gn.props
        nmatch = self.nmatcher.match(label)
        nodes = nmatch.where(name=name).limit(limit)
        if fuzzy and nodes.first() == None:
            nodes = nmatch.where(name__contains=name).limit(limit)
        nmlst = list(nodes)
        return self.__from_match_to_return(nmlst, props, topn)

    @raise_customized_error(Exception, QueryError)
    def _query_by_relation(self, gr: GraphRelation, topn: int, limit: int,
                           fuzzy: bool) -> List[Relationship]:
        """
        Query relations by given start, end and kind.
        If start and end are None, return [].
        If start or end is None, then by kind and start or end.

        If result is None, then by start or end, or by both.
        """
        starts = self._query_by_node(gr.start, topn=1, limit=5, fuzzy=fuzzy)
        ends = self._query_by_node(gr.end, topn=1, limit=5, fuzzy=fuzzy)
        start = starts[0] if starts else None
        end = ends[0] if ends else None
        kind, props = gr.kind, gr.props
        # print("start: ", start)
        # print("end:", end)
        if not start and not end:
            return []
        # start, end could be None
        # r_type could be None
        relations = self.rmatcher.match((start, end), r_type=kind).limit(limit)
        if relations.first() == None and start and end:
            relations = self.rmatcher.match((start, end)).limit(limit)
        rmlst = list(relations)
        return self.__from_match_to_return(rmlst, props, topn)

    def _query_by_cypher(self, cypher: str) -> types.GeneratorType:
        """
        Return a generator, the content depends on your query input.
        """
        pattern_match = re.compile(r'^ ?MATCH')
        pattern_limit = re.compile(r'LIMIT \d')
        if not pattern_match.search(cypher):
            raise OverstepError
        searched_limit = pattern_limit.search(cypher)
        topn = int(searched_limit.group().split()[-1]) if searched_limit else 5
        try:
            cursor = self.graph.run(cypher)
            res = []
            n = 0
            for item in cursor:
                res.append(item.data())
                n += 1
                if n == topn:
                    return res
        except Exception as e:
            raise QueryError

    def __from_match_to_return(self, matched_list: list, props: dict,
                               topn: int) -> list:
        if not matched_list:
            return []
        if len(matched_list) > 1 and props:
            ret = self._sort_matched(matched_list, props)[:topn]
        else:
            ret = matched_list[:topn]
        return ret

    @property
    def labels(self) -> frozenset:
        """all labels"""
        return self.graph.schema.node_labels

    @property
    def relationship_types(self) -> frozenset:
        """all relation types"""
        return self.graph.schema.relationship_types

    @property
    def nodes_num(self) -> int:
        """all nodes amounts"""
        return len(self.graph.nodes)

    @property
    def relationships_num(self) -> int:
        """all relations amounts"""
        return len(self.graph.relationships)

    @property
    def nodes(self) -> types.GeneratorType:
        """all nodes (a generator)"""
        return iter(self.graph.nodes.match())

    @property
    def relationships(self) -> types.GeneratorType:
        """all relations (a generator)"""
        return iter(self.graph.relationships.match())

    def excute(self, cypher) -> dict:
        """
        Be careful to use this function.
        Especially when you're updating the database.
        This function will not check the duplicated nodes or relationships.
        """
        try:
            run = self.graph.run(cypher)
            return dict(run.stats())
        except Exception as e:
            raise InputError