Neo4j-简单使用

 

官网:

Graph Data Platform | Graph Database Management System | Neo4j

入门教程:

Getting Started Guide - Getting Started

Cypher文档:

Introduction - Neo4j Cypher Manual

Cypher参考卡:

Neo4j Cypher Refcard 4.2

Neo4j操作手册:

Introduction - Operations Manual

驱动手册:

Neo4j documentation - Neo4j Documentation

在neo4j的ui界面处也有这些对应链接:

Neo4j-简单使用_第1张图片

一、Cypher简单使用

Cypher 是一种声明式图查询语言,它允许对图进行表达性和高效的查询、更新。

创建

  • 创建节点

CREATE (:Movie {title: 'The Matrix', released: 1997})

Movie是节点label, 后面是节点属性, 节点id是无法指定的,只能自动生成

CREATE (p:Person {name: 'Keanu Reeves', born: 1964})

RETURN p

  • 创建点边
CREATE (a:Per {name: 'Tom Hanks'})-[r:ACTED_IN {roles: 'Forrest'}]->(m:Movie {title: 'Forrest Gump', released: 1994})

  • 多点边创建
CREATE (a:Person {name: 'Tom Hanks', born: 1956})-[r:ACTED_IN {roles: ['Forrest']}]->(m:Movie {title: 'Forrest Gump', released: 1994})
CREATE (d:Person {name: 'Robert Zemeckis', born: 1951})-[:DIRECTED]->(m)
RETURN a, d, r, m

查询

  • 查询点
MATCH (m:Movie {title: 'The Matrix'})
RETURN m
MATCH (m:Movie)
WHERE m.title = 'The Matrix'
RETURN m
MATCH (m:Movie) --> (p)
WHERE m.title = 'The Matrix'
RETURN m,p
  • 查询边 
MATCH ()-[r:ACTED_IN]->()
WHERE  'Neo' IN r.roles
RETURN r
  • 查询点边
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE p.name = 'K' OR m.released > 2000 OR 'Neo' IN r.roles
RETURN p, r, m
  • 去重
MATCH (n)
RETURN DISTINCT n.age AS Labels
  • 关键属性查询
MATCH (n)-[l]->(v)  
WHERE id(n) = 68 and type(l)='belong' and labels(v) = ['per']
return id(n) as id ,type(l) as type ,labels(v) as labels
MATCH (n)-[l]->(v)  
WHERE id(n) = 68 and type(l)='belong' and  'per' in labels(v)
return id(n) as id ,type(l) as type ,labels(v) as labels

return:

id type labels
68 "belong" ["per"]

注意:

节点的 label是一个数组, 关系的type是一个字符串

修改

MATCH (n {name: 'Andy'})
SET n.surname = 'Taylor'
RETURN n.name, n.surname
MATCH (n )
WHERE n.name = 'Andy'
SET n.surname = 'Taylor'
RETURN n.name, n.surname

也可以用 set 去删除属性: 将属性的值设为 null。在neo4j中属性值为null属性就消失:

MATCH (n {name: 'Andy'})
SET n.name = null
RETURN n.name, n.age

修改label:

MATCH (n {name: 'Stefan'})
SET n:German
RETURN n.name, labels(n) AS labels



MATCH (n {name: 'George'})
SET n:Swedish:Bossman
RETURN n.name, labels(n) AS labels

删除

  • 删除节点
MATCH (n:Person {name: 'UNKNOWN'})
DELETE n

注意: 当要删除的节点存在边的时候节点删除不会成功,所以需要同时删除节点的边

MATCH (n:Person {name: 'UNKNOWN'})-[l]-()
DELETE n,l

官方提供一个关键词 DETACH, 可以删除节点的同时先删除该节点有关的边,就不用想上面手动指定:

MATCH (n {name: 'Andy'})
DETACH DELETE n
  • 删除关系
MATCH (n {name: 'Andy'})-[r:KNOWS]->()
DELETE r

批量操作

  • 批量插入

插入点: 

UNWIND [{age:9,name:'xiaoming'},{age:10,name:'zhangsan'}] AS row
CREATE (n: person) SET n = row

 等于 

UNWIND [{age:9,name:'xiaoming'},{age:10,name:'zhangsan'}] AS row
CREATE (n: person) SET n.name = row.name, n.age=row.age

插入边:

UNWIND [{from_name:'xiaoming',to_name: 'zhangsan',prop: {distance: '3000m'} }] AS row

MATCH (from)
where  from.name= row.from_name

MATCH (to)
where  to.name= row.to_name

CREATE (from)-[rel:KNOW]->(to)
SET rel = row.prop

  • 批量修改
UNWIND [{age:18,name:'xiaoming'}] AS row
MATCH(n: person) 
WHERE n.name = 'xiaoming'
SET n.age= row.age

注意: 元素的id,  节点的label, 关系的type 如果想在参数中指定的话,只能通过 id(n) = row.xxx, labels(n)= [row.xxx], type(l) = row.xxx 等方式指定, 无法直接 (n: row.xxx) 的方式指定

其次,在创建和修改节点的 label和type时, 也是不能使用  labels(n)= [row.xxx], type(l) = row.xxx 的, 查询的时候可以用

二、索引使用

Indexes for search performance - Neo4j Cypher Manual

索引只是加快搜索,不具备唯一性, 唯一性实现需要定义约束

  • 创建单属性索引

CREATE INDEX index_name FOR (n:Person) ON (n.surname)

index_name 也就是索引名必须是唯一的

  • 仅当单属性索引尚不存在时才创建该索引
CREATE INDEX index_name IF NOT EXISTS FOR (n:Person) ON (n.surname)

已存在具有相同名称和/或相同架构的索引,则不会创建索引。

  • 创建复合索引

CREATE INDEX index_name FOR (n:Person) ON (n.age, n.country)

  • 删除索引
DROP INDEX missing_index_name IF EXISTS

  • 查看索引
SHOW INDEXES

三、约束的使用

Constraints - Neo4j Cypher Manual

创建约束会自动创建对应索引,再手动创建相应索引会失败;

删除约束时会同时删除对应索引,还需要索引需要手动创建

约束类型有四种:

  • 唯一节点属性约束

唯一属性约束可确保属性值对于具有特定标签的所有节点都是唯一的。唯一约束并不意味着所有节点都必须具有唯一的属性值 — 没有属性的节点不受此规则的约束。

  • 节点属性存在约束

节点属性存在约束可确保具有特定标签的所有节点都存在一个属性。尝试创建指定标签的新节点但没有此属性的查询将失败。对于尝试删除必需属性的查询也是如此。

  • 关系属性存在约束

属性存在约束可确保具有特定类型的所有关系都存在属性。尝试创建指定类型的关系但没有此属性的所有查询都将失败。对于尝试删除必需属性的查询也是如此。

  • 节点键约束

节点键约束确保对于给定的标签和属性集:

  1. 所有属性都存在于具有该标签的所有节点上。

  2. 属性值的组合是唯一的。

不过后面三种约束功能只在商用版neo4j中有,所以只介绍唯一节点属性约束使用

  • 创建唯一节点属性约束
CREATE CONSTRAINT constraint_name ON (book:Book) ASSERT book.isbn IS UNIQUE

  • 仅当唯一约束尚不存在时才创建唯一约束
CREATE CONSTRAINT constraint_name IF NOT EXISTS ON (book:Book) ASSERT book.isbn IS UNIQUE

  • 删除约束
DROP CONSTRAINT missing_constraint_name IF EXISTS

  • 查看约束
SHOW CONSTRAINTS

四、python驱动使用

api: API Documentation — Neo4j Python Driver 4.4


Get started - Neo4j Python Driver Manual

安装:

pip install neo4j

from neo4j import GraphDatabase


driver = GraphDatabase.driver(uri, auth=(user, password))

driver.close()

查询

query_str = "MATCH (n:Person) where n.name = $my_name   RETURN n"
params = {"my_name": "lvh"}

# 1
with driver.session() as session:
   result = session.read_transaction(lambda tx: list(tx.run(query_str, params)))
   print(result)

'''
[
>,
>
]
'''

        query_str = "MATCH (n:Person) where n.name = $my_name   RETURN n"
        params = {"my_name": "lvh"}

        def query_func(tx,query_str, params):
            return list(tx.run(query_str, params))

        with driver.session() as session:
            result = session.read_transaction(query_func,query_str,params)
        for record  in result:
            node = record['n']
            print(type(node))
            print(node)
        '''
        
        
        
        
        '''
  # 3
        query_str = "MATCH (n:Person)-[l]->(v) where n.name = $my_name   RETURN n,l, v.name as other_name"
        params = {"my_name": "lvh"}

        with driver.session() as session:
            result = session.read_transaction(lambda tx: list(tx.run(query_str, params)))
        for record in result:
            node = record["n"]
            print(node)
            l = record["l"]
            print(l)
            other_name = record["other_name"]
            print(other_name)

        '''
            
            , ) type='KNOWS' properties={}>
            y
            
            , ) type='KNOWS' properties={}>
            d
        '''

result中每条记录是 Record, Record类似字典,k是 查询语句中 RETURN 的字段

详细的结构可以看api文档

批量插入:

batches = [
            {
                
                "node_name": "比亚迪"
            },
            {
               
                "node_name": "小米"
            },
            {
                
                "node_name": "大众"
            }]

user_label = "Ner"

node_insert_cql = 'UNWIND $batches as row  ' \
                    'CREATE (n: {_label}) SET n = row'


with driver.session() as session:
        session.write_transaction(lambda tx:         
          tx.run(node_insert_cql.format(_label=user_label), {"batches": batches}))

插入和修改label时不能通过参数指定

简单工具类:

from neo4j import GraphDatabase
from neo4j.graph import Node, Relationship
import threading
import time
import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class Neo4jDb:
    _instance_lock = threading.Lock()

    def __init__(self, uri, user, password):
        self.driver = GraphDatabase.driver(uri, auth=(user, password))

    @classmethod
    def instance(cls, uri, user, password):

        if not hasattr(Neo4jDb, "_instance"):
            with Neo4jDb._instance_lock:
                if not hasattr(Neo4jDb, "_instance"):
                    Neo4jDb._instance = Neo4jDb(uri, user, password)
                    logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 创建 Neo4jDb._instance")
        return Neo4jDb._instance

    def close(self):
        # Don't forget to close the driver connection when you are finished with it
        self.driver.close()

    def get_db(self):
        return self.driver.session()

    def batchinto_entity(self, cql_str, Entity_batches=None):
        with self.get_db() as session:
            logger.debug("Neo4j write cql: %s", cql_str)
            session.write_transaction(lambda tx: tx.run(cql_str, Entity_batches))

    # return  Map{"node":[{}], "relationship":[{}]}
    def query_entity(self, cql_str, params=None):
        with self.get_db() as session:
            logger.debug("Neo4j query cql: %s", cql_str)
            results_list = session.read_transaction(lambda tx: list(tx.run(cql_str, params)))
            return results_list

    # 自动划分点、边对象,分别放入列表
    def partition_entity(self, result_list):
        if len(result_list) == 0:
            return {"node": [], "relationship": []}

        node_list = {}
        rel_list = {}

        node_keys = []
        rel_keys = []

        first_record = result_list[0]
        for k, v in first_record.items():
            if isinstance(v, Node):
                node_keys.append(k)
            elif isinstance(v, Relationship):
                rel_keys.append(k)
            else:
                logger.error("the value of  {k} is not Node or Relationship", k=k)

        for key in node_keys:
            for record in result_list:
                if  record[key].id not in node_list:
                    node_list[record[key].id] = self._entity_to_dict(record[key])

        for key in rel_keys:
            for record in result_list:
                if record[key].id not in node_list:
                    rel_list[record[key].id] = self._entity_to_dict(record[key])

        return {"node": list(node_list.values()), "relationship": list(rel_list.values())}

    # 点边对象转换成字段结构
    def _entity_to_dict(self, entity):
        attr_dict = {}

        attr_dict['_id'] = entity.id

        if (isinstance(entity, Node)):
            label_str = ','.join([label for label in entity.labels])
            if ('' != label_str):
                attr_dict['_label'] = label_str
        elif (isinstance(entity, Relationship)):
            type_str = entity.type
            if ('' != type_str):
                attr_dict['_type'] = type_str
            attr_dict['_startId'] = entity.start_node.id
            attr_dict['_endId'] = entity.end_node.id
        else:
            logger.error("entity is not node or relationship")

        attr_dict.update(entity.items())

        return attr_dict

这是官方的驱动,还有一个官方推荐的第三方驱动,对neo4j的业务操作比较复杂的话推荐用这个第三方驱动:

The Py2neo Handbook — py2neo 2021.1

pip install --upgrade py2neo

 五、java驱动使用

api: Neo4j Java Driver 4.3 API


Using Neo4j from Java - Developer Guides

maven:


    
        org.neo4j.driver
        neo4j-java-driver
        4.4.0
    

Gradle:

compile 'org.neo4j.driver:neo4j-java-driver:4.4.0'

你可能感兴趣的:(Neo4j,数据库)