[Neo4j系列十四]Neo4j的python操作库Neomodel

neo4j 3月前 ⋅ 408 阅读

neomodel是neo4j数据库的OGM(Object Graph Mapper)的python库,基于neo4j_driver开发。当在开发过程中需要查询节点的属性时,用这个库就会非常方便,也使代码简洁流畅。

    1. 安装neonodel的Python包

      • pypi源安装

        pip install neomodel
      • 从github安装

        pip install git+git://github.com/neo4j-contrib/neomodel.git@HEAD#egg=neomodel-dev
    2. 连接neo4j数据库

      • config配置

        from neomodel import config
        config.DATABASE_URL = 'bolt://neo4j:neo4j@localhost:7687'  # default
      • db配置

        from neomodel import db
        db.set_connection('bolt://neo4j:neo4j@localhost:7687')
    3. Nodes

      • 通过StructuredNode构建映射节点类

        from neomodel import (config, StructuredNode, StringProperty, IntegerProperty,
        UniqueIdProperty, RelationshipTo, RelationshipFrom)
        config.DATABASE_URL = 'bolt://neo4j:password@localhost:7687'
        class Country(StructuredNode):    code = StringProperty(unique_index=True, required=True)# traverse incoming IS_FROM relation, inflate to Person objects    inhabitant = RelationshipFrom('Person', 'IS_FROM')
        class Person(StructuredNode):    uid = UniqueIdProperty()    name = StringProperty(unique_index=True)    age = IntegerProperty(index=True, default=0)
        # traverse outgoing IS_FROM relations, inflate to Country objects
        country = RelationshipTo(Country, 'IS_FROM')

        Country和Person节点类都是继承StructuredNode构建的,节点类的属性通过实例化不同的数据类构建,这些属性也只是我们自己创建的节点属性,与neo4j自己生成的节点属性无关,比如id,labels等。

      • Create, Save, Delete操作
        实例化节点、属性赋值、保存、删除、重载、等

        jim = Person(name='Jim', age=3).save()
        jim.age = 4jim.save() 
        # validation happens here
        jim.delete() jim.refresh()
        # reload properties from neo
        jim.id
        # neo4j internal id
      • 查找节点
        使用“.nodes”类属性查找节点,根据条件筛选节点

        # raises Person.DoesNotExist if no match
        jim = Person.nodes.get(name='Jim')
        # Will return None unless bob exists
        someone = Person.nodes.get_or_none(name='bob')
        # Will return the first Person node with the name bob. This raises Person.DoesNotExist if there's no match.
        someone = Person.nodes.first(name='bob')
        # Will return the first Person node with the name bob or None if there's no match
        someone = Person.nodes.first_or_none(name='bob')
        # Return set of nodes
        people = Person.nodes.filter(age__gt=3)
    4. Relationships

      • 使用StructuredRel构建映射边的类

        class FriendRel(StructuredRel):
            since = DateTimeProperty(
            default=lambda: datetime.now(pytz.utc)
        )
            met = StringProperty()
      • class Person(StructuredNode):
            name = StringProperty()
            friends = RelationshipTo('Person', 'FRIEND', model=FriendRel)
        rel = jim.friends.connect(bob)
        rel.since # datetime object

        通过Relationship构建两个类之间无向的关系,通过RelationshipTo或RelationshipFrom构建类之间有向关系,通过model指定关系实例继承的类,继承相关的属性。

      • 基数限制
        如果对边加上基数限制,需要在边的两个方向上分别去做定义,对cardinality作设置。

        class Person(StructuredNode):
           car = RelationshipTo('Car', 'OWNS', cardinality=One)
        class Car(StructuredNode):
           owner = RelationshipFrom('Person', 'OWNS', cardinality=One)
      • 实例化及常用方法

        rel = jim.friends.connect(bob,
                             {'since': yesterday, 'met': 'Paris'})
        print(rel.start_node().name) 
        # jim
        print(rel.end_node().name)
        # bob
        rel.met = "Amsterdam"rel.save()

        通过connect方法实例化一条边,还可以指定属性筛选;
        通过start_node、end_node可以查看边的属性;
        还可以对边进行赋值,并保存。
        此外,当两个节点存在一种关系时,则可以使用relationship这种方法

        rel = jim.friends.relationship(bob)
    5. Property types

属性默认值设置,可以是具体值,也可以是函数

from uuid import uuid4
my_id = StringProperty(unique_index=True, default=uuid4)
my_datetime = DateTimeProperty(default=lambda: datetime.now(pytz.utc))

StringProperty 的Choices

class Person(StructuredNode):
   SEXES = {'F': 'Female', 'M': 'Male', 'O': 'Other'}
   sex = StringProperty(required=True, choices=SEXES)
tim = Person(sex='M').save()
tim.sex # M
tim.get_sex_display() # 'Male'
    • Array Properties

      class Person(StructuredNode):
        names = ArrayProperty(StringProperty(), required=True) bob = Person(names=['bob', 'rob', 'robert']).save()
    • UniqueIdProperty

      class Person(StructuredNode):
         uid = UniqueIdProperty() Person.nodes.get(uid='a12df...')
    • Dates and times
      DateTimeProperty 对应 UTC epoch value
      DateProperty 对应‘YYYY-MM-DD’

      created = DateTimeProperty(default_now=True)

      -Aliasing properties
      依赖属性支持节点属性设置

      class Person(StructuredNode):
         full_name = StringProperty(index=True)    name = AliasProperty(to='full_name') Person.nodes.filter(name='Jim') # just works
    • 独特属性名
      使用db_property去创建属性,类似于创建类属性

      class Person(StructuredNode):
         name_ = StringProperty(db_property='name')
         @property
         def name(self):        return self.name_.lower() if self.name_ else None
         @name.setter
         def name(self, value):        self.name_ = value
    • Other properties
      EmailProperty、RegexProperty、NormalProperty

  1. Advanced queries

    • 节点集合与过滤
      通过nodes属性获得节点集合,通过filter过滤节点

      class SupplierRel(StructuredRel):
         since = DateTimeProperty(default=datetime.now)
      class Supplier(StructuredNode):
         name = StringProperty()    delivery_cost = IntegerProperty()    coffees = RelationshipTo('Coffee', 'SUPPLIES')
      class Coffee(StructuredNode):
         name = StringProperty(unique_index=True)    price = IntegerProperty()    suppliers = RelationshipFrom(Supplier, 'SUPPLIES', model=SupplierRel)
      # nodes with label Coffee whose price is greater than 2Coffee.nodes.filter(price__gt=2)
      try:    java = Coffee.nodes.get(name='Java')
      except Coffee.DoesNotExist:
         print "Couldn't find coffee 'Java'"

      过滤的方法有以下:
      lt - less than
      gt - greater than
      lte - less than or equal to
      gte - greater than or equal to
      ne - not equal
      in - item in list
      isnull - True IS NULL, False IS NOT NULL
      exact - string equals
      iexact - string equals, case insensitive
      contains - contains string value
      icontains - contains string value, case insensitive
      startswith - starts with string value
      istartswith - starts with string value, case insensitive
      endswith - ends with string value
      iendswith - ends with string value, case insensitive
      regex - matches a regex expression
      iregex - matches a regex expression, case insensitive

    • 查看具有关系
      利用has方法查看节点是否有一种或多种方法,True 为有,False为无

      Coffee.nodes.has(suppliers=True)
    • 迭代性、切片、计数等

      # Iterable
      for coffee in Coffee.nodes:
         print coffee.name
      # Sliceable using python slice syntax
      coffee = Coffee.nodes.filter(price__gt=2)[2:]
      # Count with __len__
      print len(Coffee.nodes.filter(price__gt=2))
      if Coffee.nodes:
         print "We have coffee nodes!"
  • 过滤关系
    使用match方法过滤关系

    nescafe = Coffee.nodes.get(name="Nescafe")
    for supplier in nescafe.suppliers.match(since_lt=january):  
       print supplier.name
    • 通过属性排序
      使用order_by方法排序,加’-‘倒排

      # Ascending sort
      for coffee in Coffee.nodes.order_by('price'):
         print coffee, coffee.price
      # Descending sort
      for supplier in Supplier.nodes.order_by('-delivery_cost'):
         print supplier, supplier.delivery_cost
    • 指定None则不排序,使用’?’随机排序

      # Sort in descending order
      suppliers = Supplier.nodes.order_by('-delivery_cost')
      # Don't order; yield nodes in the order neo4j returns them
      suppliers = suppliers.order_by(None)
      Coffee.nodes.order_by('?')

7. Cypher queries

    • 通过StructuredNode的inflate类方法实现cypher查询

      class Person(StructuredNode):
        def friends(self):
            results, columns = self.cypher("MATCH (a) WHERE id(a)={self} MATCH (a)-[:FRIEND]->(b) RETURN b")      
           return [self.inflate(row[0]) for row in results]
    • StructuredNode外构建cypher

      # for standalone queries
      from neomodel import db results, meta = db.cypher_query(query, params) people = [Person.inflate(row[0]) for row in results]

      参考链接:https://neomodel.readthedocs.io/en/latest/index.html

更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: