Neo4j使用详解
目录
- 目录
- Q / A
- Neo4j
- 安装
- Basic concept
- Cypher Basic
- MATCH 查询
- WITH
- INDEX 索引
- 最短路径 Shortest path
- Movie Graph
- Create 创建
- Find 查找
- Query 查询
- Solve 最短路径 Bacon Path
- Recommend 推荐
- Clean up 删除电影数据
- LOAD CSV 加载 Persons Movies 数据
- Northwind Graph
- Northwind 数据表结构
- 加载 Product Catalog CSV 文件
- 创建 Product Catalog 关系图
- 加载 Customer Orders CSV 文件
- 创建 Customer Orders 关系图
- Order Detail CSV 文件
- Neo4j CQL 命令格式
- Neo4j CQL 简介
- CREATE
- MATCH
- RETURN
- WHERE
- DELETE
- REMOVE
- SET
- ORDER BY
- UNION
- AS
- LIMIT
- SKIP
- MERGE
- NULL 值
- IN
- ID 属性
- INDEX 索引
- UNIQUE 约束
- DISTINCT
- Neo4J CQL 函数
- String 字符串函数
- Aggregation 聚合函数
- Relationship 关系函数
- Neo4j 图形算法
- 链接
- 遍历和寻路算法
- Centrality Algorithms
- 社区发现算法
- APOC 存储过程库
- 介绍
- 算法介绍
- py2neo
- 链接
- Node Relation Property
- Node Relationship 的其他方法
- Subgraph 子图
- Walkable
- Graph
- Record
- Table
- Transaction
- Cursor
- Errors and Warnings
- Matching
- OGM
- Cypher
Q / A
- Q: AuthError: The client is unauthorized due to authentication failure
from py2neo import Graphg = Graph()AuthError: The client is unauthorized due to authentication failure.
A: 默认使用的用户名 / 密码是
neo4j / password
,需要匹配自己的用户名密码neo4j-client -u neo4j -p 123456 bolt://localhost:7687
g = Graph(auth=("neo4j", "123456"))
或通过
:server user add
添加新用户 - Q: TypeError: Parameters of type map are not supported
from py2neo import Graph, Nodeg = Graph("http://localhost:7474")a = Node('Person', name='Alice')g.create(a)TypeError: Parameters of type map are not supported
A: http 初始化的 graph 不能 create,必须用 bolt graph create 过 [ ??? ]
g2 = Graph("bolt://...", auth=(...))g2.create(a)g.create(a)
Neo4j
安装
- neo4j github
- Neo4j Graphs for Everyone
- Neo4j Desktop Debian Installation
- Neo4j Debian Packages
- The Neo4j Developer Manual
- Neo4j 中文社区
- Neo4j 中文手册
- Cypher 中文文档
- O’Reilly’s Graph Databases
- Neo4j and Apache Spark
- 安装 Neo4j
''' Neo4j 要求 JAVA 1.8 '''apt install maven openjdk-8-jdkapt install debhelper devscripts dos2unix dpkg make xmlstarletexport JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-amd64''' 方法1,Github 中的安装方法,启动一个安装程序,需要更多配置 '''# You will need a license for install4j, which is only needed for Neo4j Desktopcurl -O http://download-keycdn.ej-technologies.com/install4j/install4j_linux_6_1_4.debdpkg -i install4j_linux_6_1_4.deb''' 方法2,debian source list,E: The repository 'https://debian.neo4j.org/repo stable/ Release' does not have a Release file. '''wget -O - https://debian.neo4j.org/neotechnology.gpg.key | sudo apt-key add -echo 'deb https://debian.neo4j.org/repo stable/' | sudo tee -a /etc/apt/sources.list.d/neo4j.listsudo apt-get update''' 方法3,tar 文件 '''# https://neo4j.com/download/other-releases/#releaseswget https://go.neo4j.com/download-thanks.html?edition=community&release=3.4.1&flavour=unixtar xvf neo4j-community-3.4.1-unix.tar.gzcd neo4j-community-3.4.1cd bin./neo4j console# INFORemote interface available at http://localhost:7474/# Add bin to envirenment PATH
- 启动
neo4j start# Browse at http://localhost:7474/Default username / password: neo4j / neo4j
初次登录会要求修改密码
- 添加新用户
:server user add
Add a new user, and test with neo4j-client
# Username: neo4j-user-1, password: 123456neo4j-client -u neo4j-user-1 -p 123456 bolt://localhost:7687
- Hello world
CREATE (matrix:Movie { title:"The Matrix", released:1997 })CREATE (cloudAtlas:Movie { title:"Cloud Atlas", released:2012 })CREATE (forrestGump:Movie { title:"Forrest Gump", released:1994 })CREATE (keanu:Person { name:"Keanu Reeves", born:1964 })CREATE (robert:Person { name:"Robert Zemeckis", born:1951 })CREATE (tom:Person { name:"Tom Hanks", born:1956 })CREATE (tom)-[:ACTED_IN { roles: ["Forrest"]}]->(forrestGump)CREATE (tom)-[:ACTED_IN { roles: ['Zachry']}]->(cloudAtlas)CREATE (robert)-[:DIRECTED]->(forrestGump)RETURN matrix,cloudAtlas,forrestGump,keanu,robert,tom
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XTlvWKAD-1678944724459)(images/neo4j_hello_world.jpg)]
Basic concept
Graph 图 是表示对象与对象之间关系的方法
- 对象 又称 节点 Node / 顶点 Vertex / 实体 Entity,描述具体的一件事物
- 关系 又称 边 edge,描述对象之间的关系
- G=(V, E) 表示一张图,V 表示节点的集合,E 表示边集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0WkpHSMG-1678944724460)(images/neo4j_node_example.jpg)]
图的学习任务分类
- 社交网络 / 搜索排名 / 评分系统 / 推荐系统 / 知识图谱 / 风险控制
- 节点上的任务:利用图中节点的关系可以做包括分类(比如风险识别、价值排名等任务)、聚类(社群检测、用户画像等任务)
- 边上的任务:通过图中节点之间是否有边可以做比如推荐、知识推理等任务
- 图上的任务:图可以做像高分子分类、3D视觉分类等任务
Graph 图 基本组成
- Nodes 节点 数据的名称
(a) // actors(m) // movies( ) // some anonymous node
- Relationships 关系 节点之间的连接
-[r]-> //a relationship referred to as "r"(a)-[r]->(m) //actors having a relationship referred to as "r" to movies-[:ACTED_IN]-> //the relationship type is ACTED_IN(a)-[:ACTED_IN]->(m) //actors that ACTED_IN some movie(d)-[:DIRECTED]->(m) //directors that DIRECTED some movie
- 关系有特定的方向与类型
- 关系可以包含属性
- Properties 属性 键值队的形式存储数据值
(m {title:"The Matrix"}) //Movie with a title property(a {name:"Keanu Reeves",born:1964}) //Actor with name and born property(a)-[:ACTED_IN {roles:["Neo"]}]->(m) //Relationship ACTED_IN with roles property
- Label 标签 节点可以通过标签组合在一起
(a:Person) //a Person(a:Person {name:"Keanu Reeves"}) //a Person with properties(a:Person)-[:ACTED_IN]->(m:Movie) //a Person that ACTED_IN some movie
- 一个节点可以有 0 个或多个标签
- 标签没有属性
- Nodes 节点 数据的名称
Editor
- :help 查看命令的帮助信息
- :clear 清空
- :play 运行
// Guides:play intro:play concepts:play cypher// Examples:play movie graph:play northwind graph
- shift-enter Switch to multi-line editing
- ctrl-enter 运行
其他命令
:sysinfo:server:schema
节点和关系 建立之前最好先查找一下是否已经存在这个节点,如果已经存在,建立关系时使用查找到的节点,而不要新建,否则会出现一个新的节点
批量导入 一条条建立关系和节点速度并不快,条件合适应使用 Neo4j 的批量导入功能
数据内容
- 图数据库的本质是为了 方便查找节点之间关系的,而不是为了存储数据
- 因此向一个节点或者关系里面插入很多其余无关的数据是完全没有必要的,会很大程度浪费硬盘资源,在检索的时候也会消耗更多的时间
Cypher Basic
- Cypher Neo4j 图查询 / 创建语言,描述 找什么,而不是 怎么找
- CREATE 创建节点
// 语法规则CREATE (节点名: 标签 {节点属性})
CREATE (ee:Person { name: "Emil", from: "Sweden", klout: 99 })
- DELETE 删除当前所有节点 / 关系
MATCH(n:Person) DETACHDELETE n
- MATCH 查找节点或关系
// 语法规则MATCH (匹配出的变量名 : 匹配的标签) WHERE 过滤结果 RETURN 返回特定结果
MATCH (pp:Person) WHERE pp.name = "Emil" RETURN pp;
CREATE 后面直接用 MATCH 时,需要 WITH
create (ee:Person {name: "Emil", from: "Sweden", klout: 99})with eematch (pp:Person) where pp.name="Emil" return pp
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h76yqoFF-1678944724460)(images/neo4j_match.jpg)]
- CREATE relationships 创建关系
// 语法规则CREATE (节点名 1)-[:关系名 {关系属性}]->(节点名 2)
create (ee:Person {name: "Emil", from: "Sweden", klout: 99})create (et:Person {name: "et"})create (et)-[:KNOWS {by: "swimming"}]->(ee)return ee, et
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sojDwE7C-1678944724460)(images/neo4j_relation.jpg)]
- 创建多个节点以及关系
create (ee:Person {name: "Emil", from: "Sweden", klout: 99})WITH eeMATCH (pp:Person) WHERE pp.name="Emil"CREATE (js:Person {name: "Johan", from: "Sweden", learn: "surfing"}), (ir: Person {name: "Ian", from: "Belgium", title: "author"}), (rvb: Person {name: "Rik", from: "England", pet: "Orval"}), (ally: Person {name: "Allison", from: "California", hobby: "surfing"}), (ee)-[:KNOWS {since: 2001}]->(js), (ee)-[:KNOWS {rating: 5}]->(ir), (js)-[:KNOWS]->(ir), (js)-[:KNOWS]->(rvb), (ir)-[:KNOWS]->(js), (ir)-[:KNOWS]->(ally), (rvb)-[:KNOWS]->(ally)RETURN ee, js, ir, rvb, ally
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8EMfqLny-1678944724460)(images/neo4j_create_relations.jpg)]
- MATCH relationships 匹配关系
// 语法规则MATCH (匹配出的变量名 : 匹配的标签) -[:关系]-(匹配到的关系名)WHERE 过滤结果 RETURN 返回特定结果
// pattern can be used to find Emil's friendsMATCH (ee:Person)-[:KNOWS]-(friends)WHERE ee.name = "Emil" RETURN ee, friends
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TqZPrpm8-1678944724460)(images/neo4j_match_pattern_knows.jpg)]
- Recommendations 匹配关系进行推荐
// Recommd frind by "surfing"MATCH (js:Person)-[:KNOWS]-()-[:KNOWS]-(surfer)WHERE js.name = "Johan" AND surfer.hobby = "surfing"RETURN DISTINCT surfer
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SbzMvtJD-1678944724460)(images/neo4j_recommdation.jpg)]
- () empty 表示忽略这些匹配到的节点
- DISTINCT because more than one path will match the pattern
- EXPLAIN / PROFILE 显示匹配过程
PROFILE MATCH (js:Person)-[:KNOWS]-()-[:KNOWS]-(surfer)WHERE js.name = "Johan" AND surfer.hobby = "surfing"RETURN DISTINCT surfer
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hiD8k0ul-1678944724461)(images/neo4j_explain.jpg)]
MATCH 查询
- 匹配 Node
()(pp)(:Person)(pp:Person)(pp:Person {name: "Emil"})
- 匹配 Relationship
-->-[role]->-[:KNOWS]->-[role:KNOWS]->-[role:KNOWS {since: 2001}]->-[:KNOWS*2]-> // Length 2 relationship-[:KWONS*1..3]-> // Variable length relationships-[role:ACTED|:DIRECTED]-> // deprecated, use UNION instead
- 基本查询
// 查询所有节点MATCH (n) RETURN n// 查询所有有连接的节点MATCH (n)-->(m) RETURN n, m// 查询所有有外向连接的节点MATCH (n)-->( ) RETURN n// 查询所有关系类型MATCH ()-[rel]->() RETURN type(rel)// 查询所有用户名与所有的关系MATCH (aa)-[rr]->(bb) RETURN aa.name AS From, type(rr) AS Related, bb.name AS To
- 条件查询
// 查询指定用户的关系MATCH (aa:Person {name:"Emil"})-->(bb) RETURN aa, bb// 使用 WHERE 指定条件MATCH (aa:Person)-->(bb) WHERE aa.name="Emil" RETURN aa, bb// 名字中含有 "a"MATCH (aa:Person) WHERE aa.name =~ ".*a.*" RETURN aa// 查询关系长度 1 到 3 的节点MATCH (aa)-[:KNOWS*1..3]->(bb) WHERE aa.name="Emil" RETURN aa, bb// 查询 同时认识一个人,互相之间又不认识的人MATCH (aa)-[:KNOWS]->(bb)<-[:KNOWS]-(cc) WHERE NOT (aa)--(cc) RETURN aa, bb, cc// 等价写法MATCH (aa)-[:KNOWS]->(bb), (cc)-[:KNOWS]->(bb) WHERE NOT (aa)--(cc) RETURN aa, bb, cc // 删除没有 name 属性的节点MATCH (aa:Person) WHERE NOT exists(aa.name) DETACH DELETE aa
- 定义 path [ ??? ]
MATCH p=(a)-[:KNOWS]->(m)<-[:KNOWS]-(d) RETURN pMATCH p=(a)-[:KNOWS]->(m)<-[:KNOWS]-(d) RETURN NODES(p)MATCH p=(a)-[:KNOWS]->(m)<-[:KNOWS]-(d) RETURN RELS(p)MATCH p1=(a)-[:KNOWS]->(m), p2=(d)-[:KNOWS]->(m) RETURN p1, p2
- 可变长度关系查询
// 长度为 2 的关系MATCH p = (aa)-[:KNOWS*2]->(bb) RETURN aa.name, bb.name// 长度 1 到 3 的关系MATCH p = (aa)-[:KNOWS*1..3]->(bb) RETURN aa.name, bb.name// 不推荐将可变长度关系绑定到一个变量,使用 pathMATCH p = (aa)-[:KNOWS*1..3]->(bb) WITH *, relationships(p) AS rr RETURN rrMATCH p = (aa)-[:KNOWS*1..3]->(bb) WITH *, relationships(p) AS rr RETURN aa.name, size(rr), bb.nameMATCH p = (aa)-[:KNOWS*1..3]->(bb) WITH *, relationships(p) AS rr RETURN aa.name, length(rr), bb.name// 长度为 0 的关系,关系的起止是同一个节点MATCH (aa)-[:KNOWS*0..1]-(bb) RETURN aa
- MATCH – CREATE – RETURN
MATCH (ir:Person {name: "Ian"}), (em: Person {name: "Emil"})CREATE (ir)-[:KNOWS]->(em)RETURN ir, em
WITH
- WITH 将 上一个命令的输出 与 下一个命令的输入 结合起来,工作原理类似 RETURN,只是不返回结果
- CREATE – WITH – MATCH
CREATE (al:Person {name: "Alice", age: 21})CREATE (bb:Person {name: "Bob", age: 23})CREATE (al)-[:KNOWS]->(bb)WITH al, bbMATCH (n: Person {name: "Alice"}) RETURN n
- Actor – Movie 数据库中的应用
MATCH (person:Person)-[:ACTED_IN]->(m:Movie)WITH person, count(*) AS appearances, collect(m.title) AS moviesWHERE appearances > 1RETURN person.name, appearances, movies// Output+------------------------------------------------------------+| person.name | appearances | movies |+------------------------------------------------------------+| "Tom Hanks" | 2 | ["Cloud Atlas","Forrest Gump"] |+------------------------------------------------------------+1 row
INDEX 索引
- Neo4j 2.0 版本在标签的基础上引入了索引,可以对标签进行限制和索引
- 尽量使用 schema index,而不要使用旧版本的索引
- 索引可以很大程度上降低大规模数据的查询速度
- 最好在插入数据之前就建立好索引,否则索引的建立会很消耗时间
- 索引 和其他 RDBMS 的定义相类似,主要用于提升节点查询的性能,即有助于数据完整性检查,也有利于优化 Cypher
- 创建索引 索引建立后,随后的查询中出现具有索引的属性时,将自动使用索引
CREATE INDEX ON :<Label>(<Property>)
// 初始化数据,不使用索引查询CREATE (al:Person {name: "Alice", age: 21})CREATE (bb:Person {name: "Bob", age: 23})CREATE (al)-[:KNOWS {period_year: 6}]->(bb)PROFILE MATCH (n:Person) WHERE n.name="Alice" RETURN n
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zmUAnsgm-1678944724461)(images/neo4j_index_1.jpg)]
// 创建索引查询CREATE INDEX ON :Person(name)PROFILE MATCH (n:Person) WHERE n.name="Alice" RETURN n
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gFynTsM4-1678944724461)(images/neo4j_index_2.jpg)]
- :schema 显示当前的索引
:schemaCALL db.indexes// 显示图数据库中的元模型CALL db.schema
- 删除索引
DROP INDEX ON :<Label>(<Property>)
DROP INDEX ON :Person(name)
- USING INDEX 显式指定索引 必须首先创建索引才能显式指定
USING INDEX <name>:<Label>(Property)USING SCAN <name>:<Label>
MATCH (n:Person) USING INDEX n:Person(name) WHERE n.name="Alice" RETURN(n)MATCH (n:Person) USING SCAN n:Person WHERE n.name="Alice" RETURN(n)
最短路径 Shortest path
- Single shortest path 函数 shortestPath 查找两个节点间的一条最短路径
// 查找两个节点间的最短路径MATCH (aa:Person {name: "Ian"}), (bb:Person {name: "Rik"}), p=shortestpath((aa)-[*..5]-(bb)) RETURN p
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M8SDWS3P-1678944724461)(images/neo4j_shortestpath_single.jpg)]
- All shortest paths 函数 allShortestPaths 查找两个节点间的所有最短路径
// 查找两个节点间的所有最短路径MATCH (aa:Person {name: "Ian"}), (bb:Person {name: "Rik"}), p=allShortestPaths((aa)-[*..5]-(bb)) RETURN p
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gmUYYpuq-1678944724461)(images/neo4j_shortestpath_all.jpg)]
// 过滤 ANYMATCH (aa:Person {name: "Ian"}), (bb:Person {name: "Rik"}), p=allShortestPaths((aa)-[*..5]-(bb))WHERE ANY (r IN relationships(p) WHERE type(r)="KNOWS")RETURN p// 过滤 NONEMATCH (aa:Person {name: "Ian"}), (bb:Person {name: "Rik"}), p=allShortestPaths((aa)-[*..5]-(bb))WHERE NONE (r IN relationships(p) WHERE type(r)="KNOWS")RETURN p
Movie Graph
Create 创建
- Movie Graph 演员-电影 图数据库,演员参演电影的关系图
:play movie-graph
- neo4j_movie_graph.cypher
// 示例CREATE (YouveGotMail:Movie {title:"You've Got Mail", released:1998, tagline:'At odds in life... in love on-line.'})CREATE (ParkerP:Person {name:'Parker Posey', born:1968})CREATE (DaveC:Person {name:'Dave Chappelle', born:1973})CREATE (SteveZ:Person {name:'Steve Zahn', born:1967})CREATE (TomH:Person {name:'Tom Hanks', born:1956})CREATE (NoraE:Person {name:'Nora Ephron', born:1941})CREATE(TomH)-[:ACTED_IN {roles:['Joe Fox']}]->(YouveGotMail),(MegR)-[:ACTED_IN {roles:['Kathleen Kelly']}]->(YouveGotMail),(GregK)-[:ACTED_IN {roles:['Frank Navasky']}]->(YouveGotMail),(ParkerP)-[:ACTED_IN {roles:['Patricia Eden']}]->(YouveGotMail),(DaveC)-[:ACTED_IN {roles:['Kevin Jackson']}]->(YouveGotMail),(SteveZ)-[:ACTED_IN {roles:['George Pappas']}]->(YouveGotMail),(NoraE)-[:DIRECTED]->(YouveGotMail)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SeVe0uDA-1678944724461)(images/neo4j_movie_create.jpg)]
Find 查找
- 查找演员名 “Tom Hanks”
MATCH (tom {name: "Tom Hanks"}) RETURN tom
- 查找电影名 “Cloud Atlas”
MATCH (cloudAtlas {title: "Cloud Atlas"}) RETURN cloudAtlas
- 查找 10 个人
MATCH (people:Person) RETURN people.name LIMIT 10
- 查找 90 年代的电影
1990 <= released < 2000
MATCH (nineties:Movie) WHERE nineties.released >= 1990 AND nineties.released < 2000 RETURN nineties.title
Query 查询
- 列出 “Tom Hanks” 的所有电影
MATCH (tom:Person {name: "Tom Hanks"})-[:ACTED_IN]->(tomHanksMovies) RETURN tom, tomHanksMovies
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qsPqsO3b-1678944724462)(images/neo4j_movie_tom_hanks_movies.jpg)]
- “Cloud Atlas” 的导演
MATCH (cloudAtlas {title: "Cloud Atlas"})<-[:DIRECTED]-(directors) RETURN directors.nameMATCH (cloudAtlas:Movie {title: "Cloud Atlas"})<-[:DIRECTED]-(director) RETURN director, cloudAtlas
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hJ9l4Lxs-1678944724462)(images/neo4j_movie_ca_directors.jpg)]
- “Tom Hanks” 共同参演的演员
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) RETURN coActors.nameMATCH (tom:Person {name: "Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) RETURN tom, m, coActors
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xEL9UYbl-1678944724462)(images/neo4j_movie_tom_hanks_coa.jpg)]
- 电影 “Cloud Atlas” 的人员关系
MATCH (people:Person)-[relatedTo]-(:Movie {title: "Cloud Atlas"}) RETURN people.name, Type(relatedTo), relatedToMATCH (people:Person)-[relatedTo]-(ca:Movie {title: "Cloud Atlas"}) RETURN people, relatedTo, ca
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ipRL3sR-1678944724462)(images/neo4j_movie_ca_relation.jpg)]
Solve 最短路径 Bacon Path
- 与 “Kevin Bacon” 4 层关系以内的演员和电影
MATCH (bacon:Person {name:"Kevin Bacon"})-[*1..4]-(hollywood)RETURN DISTINCT hollywoodMATCH (bacon:Person {name:"Kevin Bacon"})-[*1..2]-(hollywood)RETURN DISTINCT hollywood, bacon
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J1WFtdCl-1678944724462)(images/neo4j_movie_becon_relation.jpg)]
- Bacon path “Kevin Bacon” 与 “Meg Ryan” 之间的最短路径
MATCH p=shortestPath((bacon:Person {name:"Kevin Bacon"})-[*]-(meg:Person {name:"Meg Ryan"}))RETURN p
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VDqiGas9-1678944724462)(images/neo4j_movie_becon_path.jpg)]
Recommend 推荐
- 为 “Tom Hanks” 推荐新的合作演员
- 查找 Tom Hanks 合作过的演员,新的合作演员与这些演员合作过
- Tom Hanks 没有与推荐的演员合作过
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors),(coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cocoActors)WHERE NOT (tom)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors) AND tom <> cocoActorsRETURN cocoActors.name AS Recommended, count(*) AS Strength ORDER BY Strength DESC
Recommended Strength “Tom Cruise” 5 “Zach Grenier” 5 “Cuba Gooding Jr.” 4 “Carrie Fisher” 3 “Frank Langella” 2 “Ben Miles” 1 “Natalie Portman” 1 - 查找能将 Tom Hanks 介绍给 Tom Cruise 的关系
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors),(coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cruise:Person {name:"Tom Cruise"})RETURN tom, m, coActors, m2, cruise
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RQsheinx-1678944724462)(images/neo4j_movie_recomm_tt.jpg)]
Clean up 删除电影数据
- 关系存在的时候不能删除节点,必须同时删除节点与关系
// Delete all Movie and Person nodes, and their relationshipsMATCH (n) DETACH DELETE n// Prove that the Movie Graph is goneMATCH (n) RETURN n
LOAD CSV 加载 Persons Movies 数据
- 导入 persons.csv
LOAD CSV WITH HEADERS FROM "http://neo4j.com/docs/developer-manual/3.4/csv/import/persons.csv" AS csvLineCREATE (p:Person { id: toInteger(csvLine.id), name: csvLine.name })
id name 1 Charlie Sheen 2 Oliver Stone 3 Michael Douglas 4 Martin Sheen 5 Morgan Freeman - 导入 movies.csv 使用 MERGE 避免创建重复数据
// 在使用 MERGE / MATCH 时,应首先创建索引CREATE INDEX ON :Country(name)
LOAD CSV WITH HEADERS FROM "http://neo4j.com/docs/developer-manual/3.4/csv/import/movies.csv" AS csvLineMERGE (country:Country { name: csvLine.country })CREATE (movie:Movie { id: toInteger(csvLine.id), title: csvLine.title, year:toInteger(csvLine.year)})CREATE (movie)-[:MADE_IN]->(country)
id title country year 1 Wall Street USA 1987 2 The American President USA 1995 3 The Shawshank Redemption USA 1994 - 创建索引 使用 id 作为索引,只在关联关系时使用,使用
CREATE CONSTRAINT ON ... ASSERT ... IS UNIQUE
创建 唯一性约束,同时会创建 唯一性索引CREATE CONSTRAINT ON (person:Person) ASSERT person.id IS UNIQUE
CREATE CONSTRAINT ON (movie:Movie) ASSERT movie.id IS UNIQUE
- 导入 roles.csv 创建关系,
USING PERIODIC COMMIT
在加载大型 csv 文件时,通知 Neo4j 会创建大量的数据USING PERIODIC COMMIT 500LOAD CSV WITH HEADERS FROM "https://neo4j.com/docs/developer-manual/3.4/csv/import/roles.csv" AS csvLineMATCH (person:Person { id: toInteger(csvLine.personId)}),(movie:Movie { id: toInteger(csvLine.movieId)})CREATE (person)-[:PLAYED { role: csvLine.role }]->(movie)
personId movieId role 1 1 Bud Fox 4 1 Carl Fox 3 1 Gordon Gekko 4 2 A.J. MacInerney 3 2 President Andrew Shepherd 5 3 Ellis Boyd ‘Red’ Redding - 删除临时索引 movie / person 的索引在创建完关系后不再需要
DROP CONSTRAINT ON (person:Person) ASSERT person.id IS UNIQUE
DROP CONSTRAINT ON (movie:Movie) ASSERT movie.id IS UNIQUE
MATCH (n)WHERE n:Person OR n:MovieREMOVE n.id
Northwind Graph
Northwind 数据表结构
RDBMS 关系数据库管理系统 Relational Database Management System
Northwind Graph 将一个传统的关系型数据库转化为图数据库
:play northwind-graph
Product Catalog 产品类别,包含了
产品 product - 类别 categories - 供应商 suppliers
的数据[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ml7VfklO-1678944724463)(images/neo4j_nw_product_cata.jpg)]
products.csv
productID productName supplierID categoryID quantityPerUnit unitPrice unitsInStock unitsOnOrder reorderLevel discontinued 1 Chai 1 1 10 boxes x 20 bags 18 39 0 10 0 2 Chang 1 1 24 – 12 oz bottles 19 17 40 25 0 3 Aniseed Syrup 1 2 12 – 550 ml bottles 10 13 70 25 0 categories.csv
categoryID categoryName description picture 1 Beverages Soft drinks, coffees, teas, beers, and ales 0x151… 2 Condiments Sweet and savory sauces, relishes, spreads, and seasonings 0x151… 3 Confections Desserts, candies, and sweet breads 0x151… suppliers.csv
supplierID companyName contactName contactTitle address city region postalCode country phone fax homePage 1 Exotic Liquids Charlotte Cooper Purchasing Manager 49 Gilbert St. London NULL EC1 4SD UK (171) 555-2222 NULL NULL 2 New Orleans Cajun Delights Shelley Burke Order Administrator P.O. Box 78934 New Orleans LA 70117 USA (100) 555-4822 NULL #CAJUN.HTM# 3 Grandma Kelly’s Homestead Regina Murphy Sales Representative 707 Oxford Rd. Ann Arbor MI 48104 USA (313) 555-5735 (313) 555-3349 NULL
Customer Orders 客户订单,包含了
Custom - Order
对应关系[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NWxJO1Di-1678944724463)(images/neo4j_nw_customor_orders.jpg)]
customers.csv
customerID companyName contactName … ALFKI Alfreds Futterkiste Maria Anders … ANATR Ana Trujillo Emparedados y helados Ana Trujillo … ANTON Antonio Moreno Taquería Antonio Moreno … orders.csv
orderID customerID employeeID orderDate … 10248 VINET 5 1996-07-04 00:00:00.000 … 10249 TOMSP 6 1996-07-05 00:00:00.000 … 10250 HANAR 4 1996-07-08 00:00:00.000 …
OrderDetail 包含了
Order - Product
的对应关系orderID productID unitPrice quantity discount 10248 11 14 12 0 10248 42 9.8 10 0 10248 72 34.8 5 0
加载 Product Catalog CSV 文件
- LOAD CSV
:help cypher LOAD CSV
- 加载 products.csv / categories.csv / suppliers.csv 文件
// products.csvLOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/products.csv" AS rowCREATE (n:Product)SET n = row,n.unitPrice = toFloat(row.unitPrice),n.unitsInStock = toInteger(row.unitsInStock), n.unitsOnOrder = toInteger(row.unitsOnOrder),n.reorderLevel = toInteger(row.reorderLevel), n.discontinued = (row.discontinued <> "0")
// categories.csvLOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/categories.csv" AS rowCREATE (n:Category)SET n = row
// suppliers.csvLOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/suppliers.csv" AS rowCREATE (n:Supplier)SET n = row
- Create indexes 创建索引
CREATE INDEX ON :Product(productID)
CREATE INDEX ON :Category(categoryID)
CREATE INDEX ON :Supplier(supplierID)
创建 Product Catalog 关系图
products / categories / suppliers 通过 ID 键值 联系起来
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NnXQ1NYY-1678944724463)(images/neo4j_nw_product_cata_relation.jpg)]
创建关系 relationships
:help cypher MATCH
MATCH (p:Product),(c:Category)WHERE p.categoryID = c.categoryIDCREATE (p)-[:PART_OF]->(c)
MATCH (p:Product),(s:Supplier)WHERE p.supplierID = s.supplierIDCREATE (s)-[:SUPPLIES]->(p)
查找每个供应商 supplier 提供的产品类别 categories
MATCH (s:Supplier)-->(:Product)-->(c:Category)RETURN s.companyName as Company, collect(distinct c.categoryName) as Categories
Company Categories “Lyngbysild” [“Seafood”] “G’day” [“Grains/Cereals”, “Meat/Poultry”, “Produce”] “Tokyo Traders” [“Meat/Poultry”, “Produce”, “Seafood”] 查找 “Produce” 类别的供应商
MATCH (c:Category {categoryName:"Produce"})<--(p:Product)<--(s:Supplier)RETURN DISTINCT s.companyName as ProduceSuppliersRETURN s, p, c
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vgIyAif6-1678944724463)(images/neo4j_nw_produce_relation.jpg)]
加载 Customer Orders CSV 文件
- 加载 customers.csv / orders.csv 文件
LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/customers.csv" AS rowCREATE (n:Customer)SET n = row
LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/orders.csv" AS rowCREATE (n:Order)SET n = row
- Create indexes 创建索引
CREATE INDEX ON :Customer(customerID)CREATE INDEX ON :Order(orderID)
创建 Customer Orders 关系图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3eWA2qBz-1678944724463)(images/neo4j_nw_customoe_order_relation.jpg)]
MATCH (c:Customer),(o:Order)WHERE c.customerID = o.customerIDCREATE (c)-[:PURCHASED]->(o)
Order Detail CSV 文件
- 加载 order-details.csv 文件,并将 Product 与 Order 关联起来
LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/order-details.csv" AS rowMATCH (p:Product), (o:Order)WHERE p.productID = row.productID AND o.orderID = row.orderIDCREATE (o)-[details:ORDERS]->(p)SET details = row,details.quantity = toInteger(row.quantity)
- 综合查询
MATCH (cust:Customer)-[:PURCHASED]->(:Order)-[o:ORDERS]->(p:Product),(p)-[:PART_OF]->(c:Category {categoryName:"Produce"})RETURN DISTINCT cust.contactName as CustomerName, SUM(o.quantity) AS TotalProductsPurchased
Neo4j CQL 命令格式
Neo4j CQL 简介
CQL代表Cypher查询语言,遵循SQL语法
常用的 Neo4j CQL 命令
CQL 命令 用法 CREATE 创建 创建节点,关系和属性 MATCH 匹配 检索有关节点,关系和属性数据 RETURN 返回 返回查询结果 WHERE 过滤 提供条件过滤检索数据 DELETE 删除 删除节点和关系 REMOVE 移除 删除节点和关系的属性 ORDER BY 以…排序 排序检索数据 SET 设置 添加或更新标签 常用的 Neo4j CQL 函数
定制列表功能 用法 String 字符串 用于使用 String 字面量 Aggregation 聚合 用于对 CQL 查询结果执行一些聚合操作 Relationship 关系 用于获取关系的细节,如 startnode,endnode 等 Neo4j CQL 数据类型
CQL数据类型 用法 boolean 布尔文字:true,false byte 8位整数 short 16位整数 int 32位整数 long 64位整数 float 32位浮点数 double 64位浮点数 char 16位字符 String 字符串
CREATE
- 创建 节点 / 关系 / 标签
// 创建没有属性的节点CREATE (<node-name>:<label-name>)// 创建多个标签的节点CREATE (<node-name>:<label-name1>:<label-name2>.....:<label-namen>)// 创建具有属性的节点CREATE ( <node-name>:<label-name> { <Property1-name>:<Property1-Value>........<Propertyn-name>:<Propertyn-Value> })// 创建节点间的关系CREATE (<node1-name>:<label1-name>)-[(<relationship-name>:<relationship-label-name>)]->(<node2-name>:<label2-name>)
- node-name 节点名,不能用来访问节点详细信息
- label-name 标签名,可以用来访问节点详细信息
MATCH
- 从数据库获取有关节点,关系和属性的数据
MATCH (<node-name>:<label-name>)MATCH (<node-name>:<label-name> {<property1-name>: <value>})// MATCH WHERE RETURN / DELETE / CREATE / ...MATCH (<node-name>:<label-name>) WHERE <condition> RETURN <node-name>.<property1-name>// Variable length relationshipsMATCH (<nade_1>)-[:TYPE*minHops..maxHops]->(<node_2>) RETURN <nade_1>, (<node_2>)
- 不能单独使用 MATCH 从数据库检索数据,配合使用 RETURN / DELETE / CREATE 等
RETURN
- 返回 节点 / 关系的 某些 / 全部 属性
RETURN <node-name>.<property1-name>, <node-name>.<propertyn-name>RETURN <node-name>.<property1-name> AS <name1>, <node-name>.<propertyn-name> AS <name2>
- 配合 MATCH 使用
- 可以配合使用 ORDER BY / AS / LIMIT / SKIP 等子句
WHERE
WHERE子句来过滤MATCH查询的结果
// 单一条件WHERE <property-name> <comparison-operator> <value>// 布尔运算符WHERE <condition> <boolean-operator> <condition>// MATCH WHERE CREATE,创建两个现有节点之间的关系MATCH (<node1-label-name>:<node1-name>),(<node2-label-name>:<node2-name>)WHERE <condition>CREATE (<node1-label-name>)-[<relationship-label-name>:<relationship-name> {<relationship-properties>}]->(<node2-label-name>)
正则表达式匹配
// 含有字母 aWHERE <property-name> =~ ".*a.*"
boolean-operator 布尔运算符
布尔运算符 描述 AND 与 OR 或 NOT 非 XOR 异或 comparison-operator 比较运算符
布尔运算符 描述 = 等于 不等于 < 小于 > 大于 <= 小于或等于 >= 大于或等于 =~ 正则表达式匹配 Predicate functions 判定函数 通常用于过滤一组结果
判定函数 描述 语法 All 所有都为 True all(variable IN list WHERE predicate) ANY 有一个为 True any(variable IN list WHERE predicate) EXISTS 存在 exists(pattern-or-property) NONE 所有都为 False none(variable IN list WHERE predicate) SINGLE 只有一个为 True single(variable IN list WHERE predicate) MATCH p =(a)-[*1..3]->(b)WHERE a.name = 'Alice' AND b.name = 'Daniel' AND ALL (x IN nodes(p) WHERE x.age > 30)RETURN pMATCH (a)WHERE a.name = 'Eskil' AND ANY (x IN a.array WHERE x = 'one')RETURN a.name, a.arrayMATCH (n)WHERE exists(n.name)RETURN n.name AS name, exists((n)-[:MARRIED]->()) AS is_marriedMATCH p =(n)-[*1..3]->(b)WHERE n.name = 'Alice' AND NONE (x IN nodes(p) WHERE x.age = 25)RETURN pMATCH p =(n)-->(b)WHERE n.name = 'Alice' AND SINGLE (var IN nodes(p) WHERE var.eyes = 'blue')RETURN p
DELETE
- 用于删除节点和关联关系
DELETE <node-name-list>DELETE <node1-name>,<node2-name>,<relationship-name>
- DETACH 删除节点同时删除相关关系
MATCH (<node-name>:<label-name> {<property1-name>: <value>})DETACH DELETE <node-name>
REMOVE
- 用于删除标签和属性
// 删除节点/关系的属性REMOVE <node-name>.<property1-name>, <node-name>.<property2-name>// 删除节点/关系的标签REMOVE <node-name>:<label1-name>, <node-name>:<label2-name>
SET
- 向现有 节点 / 关系 添加 / 更新 属性值
SET<node-label-name>.<property1-name>, <node-label-name>.<property2-name>
ORDER BY
- 对 MATC H查询返回的结果进行排序
// 默认按升序对行进行排序,DESC 指定降序排列ORDER BY<node-label-name>.<property1-name>, <node-label-name>.<property2-name> [DESC]
UNION
- UNION 将两组结果中的公共行组合并返回到一组结果中,不返回重复行
<MATCH Command1>UNION<MATCH Command2>
- UNION ALL 将两组结果中的公共行组合并返回到一组结果中,返回重复行
<MATCH Command1>UNION ALL<MATCH Command2>
- 限制 组合的两个结果集的名字必须匹配,列名称 与 列的数据类型 应该是相同的
- 可使用 AS 统一返回的列名称
AS
- 用于给一些列起别名,如 RETURN 的返回结果,或用于 UNION 时统一列名
MATCH (<node1-name>:<label1-name>)RETURN <node1-name>.<property1-name> AS <name1>,<node1-name>.<propertyn-name> AS <name2>UNIONMATCH (<node2-name>:<label2-name>)RETURN <node2-name>.<property2-name> AS <name1>,<node2-name>.<propertyn-name> AS <name2>
LIMIT
- 过滤或限制查询返回的行数,取 顶部 的 number 行
LIMIT <number>
SKIP
- 过滤或限制查询返回的行数,取 底部 的 number 行
SKIP <number>
MERGE
- MERGE 命令是 CREATE 命令和 MATCH 命令的组合
- 搜索给定模式,如果存在,则返回结果
- 如果不存在,则创建新的节点 / 关系并返回结果
MERGE (<node-name>:<label-name>{ <Property1-name>:<Pro<rty1-Value> ..... <Propertyn-name>:<Propertyn-Value>})
NULL 值
- NULL 空值,节点 / 关系的属性的 缺失值 或 未定义值
// 过滤 NULL 行WHERE IS NULLWHERE IS NOT NULL
IN
- 用于提供一组值的集合
IN [<Collection-of-values>]// MATCH WHERE IN RETURNMATCH (<node-name>:<label-name>)WHERE <node-name>.<property-name> IN [<value1>, <value2>, <value3>]RETURN <node-name>.<property1-name>, <node-name>.<property2-name>
ID 属性
- Id 是节点和关系的默认内部属性,当创建一个新的节点或关系时,Neo4j 数据库服务器将为内部使用分配一个数字,自动递增
INDEX 索引
- 为具有 相同标签名称 的所有 节点 / 关系 的属性创建索引,以提高应用程序的性能
- 创建索引 CREATE INDEX ON
// 在节点或关系的 CREATE INDEX ON :<label_name> (<property_name>)
- 删除索引 DROP INDEX ON
// 删除在节点或关系的 DROP INDEX ON :<label_name> (<property_name>)
UNIQUE 约束
- CREATE 命令始终创建新的节点或关系,即使使用相同的值,也会插入一个新行
- UNIQUE 约束 避免重复记录,强制执行数据完整性规则
- 创建 UNIQUE 约束 CREATE CONSTRAINT ON
CREATE CONSTRAINT ON (<label_name>)ASSERT <property_name> IS UNIQUE
- 使用
CREATE CONSTRAINT ON ... ASSERT ... IS UNIQUE
创建 唯一性约束,同时会创建 唯一性索引 - 删除 UNIQUE 约束 DROP CONSTRAINT ON
DROP CONSTRAINT ON (<label_name>)ASSERT <property_name> IS UNIQUE
DISTINCT
- DISTINCT 用于移除重复值
RETURN DISTINCT <node-name>.<property1-name>
Neo4J CQL 函数
String 字符串函数
字符串函数列表
功能 描述 语法 UPPER 所有字母更改为大写字母 UPPER() LOWER 所有字母改为小写字母 LOWER() SUBSTRING 获取给定String的子字符串 SUBSTRING(, ,) REPLACE 替换一个字符串的子字符串
Aggregation 聚合函数
聚合函数列表,类似于SQL中的GROUP BY子句
聚集功能 描述 语法 COUNT 统计由 MATCH 命令返回的行数 COUNT() MAX 返回一组属性中的最大值 MAX() MIN 返回一组属性中的最大值 MIN() SUM 返回 MATCH 结果中某一属性的和 AVG() AVG 返回 MATCH 结果中某一属性的平均值 SUM()
Relationship 关系函数
关系函数列表,获取 开始节点 / 结束节点等关系的细节
功能 描述 语法 STARTNODE 关系的开始节点 STARTNODE() ENDNODE 关系的结束节点 ENDNODE() ID 关系的 ID ID() TYPE 关系的 TYPE TYPE()
Neo4j 图形算法
链接
- Github Efficient Graph Algorithms for Neo4j
- The Neo4j Graph Algorithms User Guide
- 《Graph Learning》| 图传播算法(上)
- 《Graph learning》| 图传播算法(下)
- 浅析图卷积神经网络
遍历和寻路算法
- 广度优先算法 BFS
- 遍历树数据结构,探索最近的邻居和他们的次级邻居
- 用于定位连接,是许多其他图算法的前身
- 当树较不平衡或目标更接近起点时,BFS是首选
- 也可用于查找节点之间的最短路径或避免深度优先搜索的递归过程
- 广度优先搜索可用于定位像 BitTorrent 等对等网络中的邻居节点,GPS 系统可精确定位附近的位置,社交网络服务可在特定距离内查找人员
- 深度优先算法 DFS
- 遍历树数据结构,通过在回溯之前尽可能探索每个分支
- 用于深层次的数据,是许多其他图算法的前身
- 当树较平衡或目标更接近端点时,深度优先搜索是首选
- 深度优先算法通常用于游戏模拟,其中每个选择或动作引发另一个操作,从而扩展成可能性的树形图,它将遍历选择树,直到找到最佳解决方案路径(即胜利)
- 单源最短路径
- 计算节点与所有其他节点之间的路径,以及其与所有其他节点的总和值(成本,距离,时间或容量等关系的权重)并得出总和最小
- 单源最短路径通常用于自动获取物理位置之间的路线,例如通过 Google 地图获取驾车路线
- 在逻辑路由中也很重要,例如电话呼叫路由(最低成本路由)
- 全源最短路径
- 计算包含图中节点之间所有最短路径的最短路径森林(组)
- 当最短路径被阻塞或变得次优时,切换到新的最短路径,通常用于备用路由
- 用于评估备用路由,例如高速公路备份或网络容量
- 也是为逻辑路由提供多路径的关键,比如呼叫路由选择
- 最小生成树 MWST
- 计算与访问树中所有节点相关的最小值(如成本,时间或容量等关系的权重)的路径
- 用于逼近一些 NP 难题,如旅行商问题和随机或迭代舍入
- 最小生成树广泛用于网络设计:成本最低的逻辑或物理路由,如铺设电缆,最快的垃圾收集路线,供水系统容量,高效电路设计等等
- 还可用于滚动优化的实时应用程序,如化学炼油厂的过程或行驶路线修正
Centrality Algorithms
- PageRank
- 估计当前节点对其相邻节点的重要性,然后再从其邻居那里获得节点的重要性
- 一个节点的排名来源于其传递链接的数量和质量
- PageRank 虽然被谷歌抛弃了,但它还是被广泛认为是检测任何网络中有影响力的节点的常用方式
- PageRank 用于评估重要性和影响力,经常的用法是推荐推特账户以及一般的情绪分析
- PageRank也用于机器学习,以确定最有影响的提取特征
- 在生物学中,它被用来识别食物网中哪些物种的灭绝会导致物种死亡的最大连锁反应
- Degree Centrality
- 测量节点(或整个图表)所具有的关系数量,被分为流入和流出两个方向,关系具有指向性
- Degree Centrality 着眼于用途的直接连通性,例如评估患者接近病毒或听取信息的近期风险
- 在社会研究中,可以用来预估人气或者其它情感
- Closeness Centrality
- 衡量一个节点对其集群内所有邻居的集中程度
- 假定到所有其他节点的路径都是最短的,那么该节点就能够以最快的速度到达整个组
- Closeness Centrality 适用于多种资源、交流和行为分析,尤其是当交互速度显着时
- 在新公共服务中,被用于确定最大可访问性的位置
- 在社交网络分析中,用于找到具有理想社交网络位置的人,以便更快地传播信息
- Betweenness Centrality
- 测量通过节点的最短路径的数量(首先通过广度优先算法找到)
- 出现在最短路径上次数最多的节点具有较高的介数中心性,并且是不同集群之间的桥梁
- 通常与控制资源和信息的流动有关
- Betweenness Centrality 适用于网络科学中的各种问题,用于查明通信和交通网络中的瓶颈或可能的攻击目标
- 在基因组学中,被用于了解控制某些基因在蛋白质网络中的改进,例如更好的药物 / 疾病靶向
- Betweenness Centrality 也被用来评估多人在线游戏玩家和共享医师专业知识的信息流
社区发现算法
- 也被称为 聚类算法 或 分区算法
- Label Propagation
- 基于邻域多数的标签作为推断集群的手段
- 这种极其快速的图形分割需要很少的先验信息,并且被广泛地应用于大规模的社区检测网络中
- 是理解图组织的一个关键方法,通常是其他分析的主要步骤
- Label Propagation 具有不同的应用,例如了解社会团体中的共识形成、识别在生物网络的过程(功能模块)中所涉及的蛋白质集合等等
- 还可以用于半监督和无监督的机器学习作为初始的预处理步骤
- Strongly Connected
- 定位节点组,其中每个节点可从同一组中的所有其他节点按照关系的方向到达,常被应用于深度优先算法
- Strongly Connected 通常用于在识别的集群上独立运行其他算法
- 作为有向图的预处理步骤,它有助于快速识别不连通的集群
- 在零售推荐中,它有助于识别具有强亲和性的组,然后将向那些尚未购买商品的群体推荐首选商品
- Union-Find / Connected Components / Weakly Connected
- 查找节点组,其中每个节点可从同一组中的任何其他节点到达,而不考虑关系的方向
- 提供几乎恒定的时间操作(独立于输入大小)来添加新的组,合并现有的组,并确定两个节点是否在同一组中
- Union-find / connected 经常与其他算法结合使用,特别是对于高性能分组
- 作为无向图的预处理步骤,它有助于快速识别断开的组
- Louvain Modularity
- 通过比较它的关系密度与适当定义的随机网络来测量社团分组的质量(即假定的准确性)
- 通常用于评估复杂网络的组织和社区层次结构,这对于无监督机器学习中的初始数据预处理也是有用的
- Louvain 用于评估 Twitter / LinkedIn / YouTube 上的社交结构
- 用于欺诈分析,以评估一个组织是只存在一些不良行为,还是背后一个连环欺诈
- Louvain 在比利时电信网络中揭示了一个六级客户层级
- Local Clustering Coefficient / Node Clustering Coefficient
- 对于一个特定的节点,量化了其到邻居节点的距离 (每个节点都直接连接到其他节点)
- 例如,如果您的所有朋友都直接了解对方,那么您的本地集群系数将是 1
- 集群的小值表明尽管存在一个分组,但节点之间并没有紧密连接
- Local cluster coefficient 通过理解群体相关性或碎片化的可能性,对估计弹性具有重要意义
- 用这种方法对欧洲电网的分析发现,与稀疏连接的节点相比,集群更能抵御普遍的故障
- Triangle-Count and Average Clustering Coefficient
- 测量有多少节点具有三角形以及节点倾向于聚集在一起的程度
- 平均聚类系数为 1 时表明有一个分组,0 时没有连接
- 为使聚类系数有意义,它应该明显高于网络中所有关系随机的版本
- 平均聚类系数通常用于估计网络是否可能展现基于紧密集群的“小世界”行为
- 也是集群稳定性和弹性的一个因素
- 流行病学家使用平均聚类系数来帮助预测不同社区的各种感染率
APOC 存储过程库
介绍
- APOC User Guide
- APOC 用户指南 3.4.0.1
- APOC Awesome Procedures On Cypher
- APOC Java 存储过程库,可以方便地在 Cypher 中调用,实现复杂和高性能的图遍历
算法介绍
- 文本和查找索引
CALL apoc.index.*
- Neo4j使用 Apache的Lucene库来进行文本处理
- 文本索引过程用来对属性的文本内容进行自然语言处理并创建索引
- 支持快速的对节点和关系属性值的全文 本查询
- 手工索引方式,需要随数据更新而定期更新
- 如果加载中文分词库,也能够实现中文文本的索引
- 功能函数
CALL apoc.text.* / date.* / number.*
- 字符串处理
- 时间戳
- 数字类型及其格式
- 日期
- 大数/科学计数法
- 图论算法 algo.community 社区检测 / 社团划分 Community Detection
CALL apoc.algo.community()
- 标签传播 Label Propagation
- 可自定义的迭代层数和权重
- 对网络实施分区 Partition
CALL apoc.algo.community(25,null,'partition','X', 'OUTGOING','weight',10000)
- 图论算法 path 路径扩展 / 图的遍历
CALL apoc.path.*
- 宽度优先 vs 无重复的关系路径
- 可自定义遍历规则: 起始节点 / 层级 / 包含关系及方向等等
- 按照节点类型进行过滤: 排除 blacklist / 终止 termination / 结束 end / 包含 whitelist
- 最大节点 / 关系数限制
- 子图遍历
- 生成树 spanning tree 遍历
- 图论算法 algo.closeness / betweenness 中心性 Centrality algorithm
CALL apoc.algo.closeness() / betweenness()
- 紧密中心性 Closeness Centrality
- 间接中心性 Betweenness Centrality
- 计算节点在网络中处于核心地位的程度
- 发现社交网络中的重要人物
- 发现欺诈团伙中的核心 / 老大
- 图论算法 algo.pageRank 页面排行 Page Rank
CALL apoc.algo.pageRank()
- 用来计算节点在整个网络中的重要性
- 可以指定参与计算的节点
- 目前计算是基于全网中的所有指定节点
CALL apoc.algo.pageRank(nodes) YIELD node,score
- 地理空间函数
CALL apoc.spatial.*
- 根据地址返回地球坐标
- 计算直线距离
- 按照距离远近排序节点
CALL apoc.spatial.feocodeOnce(node.address) YIELD location
- 数据集成
CALL apoc.load.*
- 加载JSON数据: 调用 RESTful API
- 加载关系数据库数据: 通过 JDBC
- 流式化数据到 Gephi
- 集成 Elastic Search
- 加载 XML 文档
- Cypher 查询
CALL apoc.cypher.*
- 可以动态构造查询语句
- 控制查询的执行时间
- 条件化查询分支: when, case
- 更灵活的查询执行任务控制: 批次大小, 并行执行, 重试等等
- 虚拟图
CALL apoc.create.*
- apoc 支持创建虚拟 Virtual 的节点和关系,从而构成虚拟路径和子图
- 虚拟图类似关系数据库中视图 View 的概念: 它们可以被查询并返回数据,但是并不物理地存储在数据库中
- 虚拟图使某些查询更加灵活和高效: 创建数据库中并不存在的节点和关系缩小查询的相关子图规模控制遍历的路径
- 虚拟节点和关系的 ID 都是负数
- 内存管理
- 重构 / 优化图 对已有的图进行转换操作以实现重构 Refactoring
CALL apoc.refactoring.*
- 复制节点及其属性,包括 / 不包括关系
- 合并节点
- 重建关系到新的节点
- 改变关系类型
- 将关系转换成节点
- 将节点转换成关系
- 将属性转换成分类节点,并与相关的节点建立关系
- 并行节点查询
CALL apoc.search.*
- 在可能的情况下并行查找结点
- 结果可以是全部匹配节点,或者去除重复后的节点
- 可以使用JSON格式定义要查询节点的属性集
- 支持多种匹配类型:“”, “=”, “”, “⇐”, “>=”, “=~”
- 其他数据库特性
- 触发器 Trigger
- 写入锁 Write lock
- 显示数据库元模型 metadata
- 数据轮廓 Data profiling
- 管理索引和限制
- 对节点和关系并发操作的支持:原子性
py2neo
链接
- The Py2neo Handbook
- py2neo github
Node Relation Property
- Neo4j 里面最重要的两个数据结构就是 节点 Node 和 关系 Relationship,可以通过 Node 或 Relationship 对象创建
class Node(Entity)__init__(self, *labels, **properties)class Relationship(Entity)__init__(self, *nodes, **properties)
- Relationship 类 创建关系
from py2neo import Node, Relationshipa = Node('Person', name='Alice')b = Node('Person', name='Bob')r = Relationship(a, 'KNOWS', b)print(a, b, r)# (:Person {name: 'Alice'}) (:Person {name: 'Bob'}) (Alice)-[:KNOWS {}]->(Bob)
指定 type
WORKS_WITH = Relationship.type('WORKS_WITH')ab = WORKS_WITH(a, b)ab# Out[12]: (Alice)-[:WORKS_WITH {}]->(Bob)
类继承
c = Node("Person", name="Carol")class WorkWith(Relationship): passac = WorkWith(a, c)ac# Out[8]: (Alice)-[:WorkWith {}]->(Carol)type(ac)# Out[9]: __main__.WorkWith
- Node 和 Relationship 都继承了 PropertyDict 类,它可以赋值很多属性,类似于字典的形式
a['age'] = 20b['age'] = 21r['time'] = '2017/08/31'print(a, b, r)# (:Person {age: 20, name: 'Alice'}) (:Person {age: 21, name: 'Bob'}) (Alice)-[:KNOWS {time: '2017/08/31'}]->(Bob)len(a)# Out[32]: 2len(r)# Out[33]: 1dict(a)# Out[35]: {'name': 'Alice', 'age': 20}dict(r)# Out[36]: {'time': '2017/08/31'}
Node Relationship 的其他方法
- Node 标签操作 labels / add_label / remove_label / clear_labels / update_labels / has_label
a.labels# Out[37]: :Persona.add_label('MAN')a.labels# Out[51]: :MAN:Persona.clear_labels()a.update_labels(['WOMAN', 'PERSON'])a.labels# Out[61]: :PERSON:WOMAN
- setdefault 方法赋值默认属性
a.setdefault('location', 'Bei Jing')print(a)# (:Person {age: 20, location: 'Bei Jing', name: 'Alice'})
赋值 location 属性,覆盖默认属性
a['location'] = 'Shang Hai'a.setdefault('location', 'Bei Jing')print(a)# (:Person {age: 20, location: 'Shang Hai', name: 'Alice'})
- update 方法对属性批量更新
data = {'name': 'Amy','age': 21}a.update(data)print(a)# (:Person {age: 21, location: 'Shang Hai', name: 'Amy'})
Subgraph 子图
- Subgraph 子图 是 Node 和 Relationship 的集合,最简单的构造子图的方式是通过关系运算符
from py2neo import Node, Relationships = ab | acprint(list(s.nodes))# [(:PERSON:WOMAN {age: 21, location: 'Bei Jing', name: 'Amy'}), (:Person {name: 'Carol'}), (:Person {age: 21, name: 'Bob'})]print(list(s.relationships))# [(Amy)-[:WorkWith {}]->(Carol), (Amy)-[:WORKS_WITH {}]->(Bob)]
- | / & / – / ^ 取 Subgraph 的并集 / 交集 / 差集 / 异或
ss = ab & acprint(list(ss.nodes))# [(:PERSON:WOMAN {age: 21, location: 'Bei Jing', name: 'Amy'})]print(list(ss.relationships))# []
- labels / nodes / relationships / keys() / types() 分别获取 Subgraph 的属性值
s = a | b | rprint(s.keys())# frozenset({'name', 'age', 'location'})print(list(s.labels))# ['PERSON', 'Person', 'WOMAN']print(list(s.nodes))# [(:PERSON:WOMAN {age: 21, location: 'Bei Jing', name: 'Amy'}), (:Person {name: 'Carol'}), (:Person {age: 21, name: 'Bob'})]print(list(s.relationships))# [(Amy)-[:WorkWith {}]->(Carol), (Amy)-[:WORKS_WITH {}]->(Bob)]print(s.types())# frozenset({'WorkWith', 'WORKS_WITH'})
Walkable
- Walkable 增加了遍历信息的 Subgraph,通过 + 构建一个 Walkable 对象
from py2neo import Node, Relationshipa = Node('Person', name='Alice')b = Node('Person', name='Bob')c = Node('Person', name='Mike')ab = Relationship(a, "KNOWS", b)ac = Relationship(a, "KNOWS", c)w = ab + Relationship(b, "LIKES", c) + acprint(type(w))# print(w.nodes)# ((:Person {name: 'Alice'}), (:Person {name: 'Bob'}), (:Person {name: 'Mike'}), (:Person {name: 'Alice'}))print(w.relationships)# ((Alice)-[:KNOWS {}]->(Bob), (Bob)-[:LIKES {}]->(Mike), (Alice)-[:KNOWS {}]->(Mike))
- walk 方法实现遍历
from py2neo import walkfor item in walk(w):print(item)# (:Person {name: 'Alice'})# (Alice)-[:KNOWS {}]->(Bob)# (:Person {name: 'Bob'})# (Bob)-[:LIKES {}]->(Mike)# (:Person {name: 'Mike'})# (Alice)-[:KNOWS {}]->(Mike)# (:Person {name: 'Alice'})
- start_node / end_node / nodes / relationships 获取 Walkable 的属性值
print(w.start_node)# (:Person {name: 'Alice'})print(w.end_node)# (:Person {name: 'Alice'})print(w.nodes)# ((:Person {name: 'Alice'}), (:Person {name: 'Bob'}), (:Person {name: 'Mike'}), (:Person {name: 'Alice'}))print(w.relationships)# ((Alice)-[:KNOWS {}]->(Bob), (Bob)-[:LIKES {}]->(Mike), (Alice)-[:KNOWS {}]->(Mike))
- start_node 与 end_node 是同一个
Graph
Graph 代表了 Neo4j 的图数据库,提供了许多方法来操作 Neo4j 数据库
默认连接参数
bolt://localhost:7687
neo4j / password
Keyword Description Type Default auth A 2-tuple of (user, password) tuple (‘neo4j’, ‘password’) host Database server host name str ‘localhost’ password Password to use for authentication str ‘password’ port Database server port int 7687 scheme Use a specific URI scheme str ‘bolt’ secure Use a secure connection (TLS) bool False user User to authenticate as str ‘neo4j’ user_agent User agent to send for all connections str (depends on URI scheme) 初始化 使用默认的连接,匹配自己的用户名密码
neo4j-client -u neo4j -p 123456 bolt://localhost:7687
用户名
neo4j
密码123456
from py2neo import Graph# Boltgraph_1 = Graph(auth=('neo4j', '123456'))graph_2 = Graph("bolt://localhost:7687", auth=('neo4j', '123456'))graph_3 = Graph(scheme='bolt', host='localhost', port=7687, user='neo4j', password='123456')graph_1.database# Out[121]:
# http 初始化的 graph 不能 create,必须用 bold graph create 过graph_4 = Graph("http://localhost:7474")graph_5 = Graph(scheme='http', host="localhost", port=7474)
begin 创建一个新的 Transaction,Graph 很多方法实际执行的是 Transaction 方法
from py2neo import Node, Relationship, Grapha = Node('Person', name='Alice')b = Node('Person', name='Bob')c = Node('Person', name='Carol')ab = Relationship(a, 'KNOWS', b)ac = Relationship(a, 'KNOWS', c)bc = Relationship(b, 'KNOWS', c)s = ab | ac | bc# 使用 Transaction.createtx = graph.begin()tx.create(s)tx.commit()
create 方法传入 Subgraph 对象来将关系图添加到数据库中
# 使用 Graph.creategraph = Graph(auth=('neo4j', '123456'))graph.create(s)
delete / delete_all 删除子图,实际执行
Transaction.delete
- 删除 节点 同时会删除所有对应的 关系
- 删除 关系 同时会删除所有对应的 节点
aa = graph.nodes.match("Person", name="Alice").first()ar = graph.relationships.match(nodes=[aa], r_type="KNOWS").first()graph.delete(ar)graph.delete(aa)graph.delete_all()list(graph.nodes.match())
清除 清除后如果要重新创建,需要重新初始化 Node / Relationship
graph.run('MATCH (p:Person) DETACH DELETE p')
exists 检验存在一个节点,实际执行
Transaction.exists
graph.exists(ab)# Out[8]: Truegraph.match_one(r_type='KNOWS')# Out[9]: (Alice)-[:KNOWS {}]->(Bob)[tt.data() for tt in graph.run('MATCH (p:Person) return p')]# Out[43]: [{'p': (_4299:Person {name: 'Alice'})},# {'p': (_4300:Person {name: 'Carol'})},# {'p': (_4301:Person {name: 'Bob'})}]
match / match_one 匹配并返回所有 / 一个 Relationship
match(nodes=None, r_type=None, limit=None)match_one(nodes=None, r_type=None)# Nodes must be supplied as a Sequence or a Set
alice = graph.nodes.match('Person', name='Alice').first()for rel in graph.match((alice, ), r_type="KNOWS"):print(rel.end_node["name"])# Bob# Carolgraph.match_one(r_type='KNOWS')# Out[89]: (Alice)-[:KNOWS {}]->(Bob)
nodes.match 查找 Node
# py2neo.matching.NodeMatcher 的实例match(*labels, **properties)
graph.nodes.match("Person", name="Alice").first()# Out[152]: (_4299:Person {name: 'Alice'})
nodes.get 根据 ID 获取节点
graph.nodes[4299]# Out[153]: (_4299:Person {name: 'Alice'})graph.nodes.get(4299)# Out[154]: (_4299:Person {name: 'Alice'})
relationships.match 查找 Relationship
# py2neo.matching.RelationshipMatcher 的实例match(nodes=None, r_type=None, **properties)
list(graph.relationships.match(r_type="KNOWS"))# Out[97]: [(Alice)-[:KNOWS {}]->(Bob),# (Alice)-[:KNOWS {}]->(Carol),# (Bob)-[:KNOWS {}]->(Carol)]# nodes is a listalice = graph.nodes.match('Person', name='Alice').first()graph.relationships.match(nodes=[alice], r_type="KNOWS").first()# Out[108]: (Alice)-[:KNOWS {}]->(Bob)
pull / push 获取 / 更新 Node 属性
aa = graph.nodes.match("Person", name="Alice").first()aa["age"] = 21graph.push(aa)graph.nodes.match("Person", name="Alice").first()# Out[123]: (_4299:Person {age: 21, name: 'Alice'})
run 直接执行 CQL 命令
[tt.data() for tt in graph.run('MATCH (p:Person) return p')]# Out[43]: [{'p': (_77:Person {name: 'Alice'})}, {'p': (_102:Person {name: 'Bob'})}]from py2neo import Graphgraph_1 = Graph(auth=('neo4j', '123456'))graph_1.run("UNWIND range(1, 3) as n RETURN n, n * n as n_sq").to_table()# Out[109]:#n | n_sq# ---|------#1 |1#2 |4#3 |9
separate 删除关系,实际执行
Transaction.separate
aa = graph.nodes.match("Person", name="Alice").first()ar = graph.relationships.match(nodes=[aa], r_type="KNOWS").first()graph.separate(ar)
Record
- Record 记录,表示匹配到的一条数据,扩展的元组与字典
- len 记录的长度
# run 执行 cypher 命令返回 Cursorrr = graph.run('MATCH (n) RETURN n')type(rr)# Out[363]: py2neo.database.Cursor# 遍历 rr 的值是 recordrr.forward()# Out[364]: 1tt = rr.currenttype(tt)# Out[366]: py2neo.data.Recordlen(tt)# Out[371]: 1
- dict / data 转化为字典
dict(tt)# Out[372]: {'n': (_4324:Person {name: 'Bob'})}tt.data()# Out[376]: {'n': (_4324:Person {name: 'Bob'})}
- keys / values / items / get 类似字典方法
tt.keys()# Out[377]: ['n']tt.values()# Out[378]: [(_4324:Person {name: 'Bob'})]tt.items()# Out[379]: [('n', (_4324:Person {name: 'Bob'}))]tt.get('n')# Out[380]: (_4324:Person {name: 'Bob'})
- to_subgrapth 转化为子图
tt.to_subgraph()# Out[381]: (_4324:Person {name: 'Bob'})aa = tt.to_subgraph()aa['name']# Out[383]: 'Bob'
Table
- Table 表,包含 record 的集合,通常是 cypher 请求的返回值,扩展的列表
tt = graph.run('MATCH (n) RETURN n.name, n.age').to_table()tt# Out[468]:#n.name | n.age# --------|-------#Bob|null#Carol|null#Alice|null
- write / write_html / write_separated_values / write_csv / write_tsv 将数据写入到文件
Transaction
- transaction 是多条 cypher 命令的包装组合,graph 的许多方法需要调用到 transaction
from py2neo import Graph, Node, Relationshipg = Graph()tx = g.begin()a = Node("Person", name="Alice")tx.create(a)b = Node("Person", name="Bob")ab = Relationship(a, "KNOWS", b)tx.create(ab)tx.commit()g.exists(ab)# Out[181]: True
- finished 返回该 transaction 是否已执行完成
tx.finished()# Out[182]: True
- rollback 回滚上次 transaction 的操作
Cursor
- Cursor 游标,Record 记录的流式处理,所有的 cursor 都是
forward-only
,从第一个节点之前开始,只能前向遍历rr = graph.run('MATCH (n) RETURN n')type(rr)# Out[404]: py2neo.database.Cursorfor tt in rr:print('type = %s, name = %s' % (type(tt), tt['n']['name']))# type = , name = Bob# type = , name = Carol# type = , name = Alice
- forward 与 current,用于遍历 cursor,
forward
有值返回 1,否则返回 0,current
表示当前的 recordrr = graph.run('MATCH (n) RETURN n')while rr.forward():print(rr.current['n']['name'])# Bob# Carol# Alice
- next 遍历,python 内置方法
rr = graph.run('MATCH ()-[rr:KNOWS]-() RETURN rr')next(rr)['rr']# Out[427]: (Alice)-[:KNOWS {}]->(Bob)
- evaluate 判断是否有下一条,并返回
rr = graph.run('MATCH (n) RETURN n')rr.evaluate()# Out[452]: (_4324:Person {name: 'Bob'})rr.evaluate()# Out[453]: (_4325:Person {name: 'Carol'})rr.evaluate()# Out[454]: (_4357:Person {name: 'Alice'})rr.evaluate() == None# Out[456]: True
- data 返回所有数据,字典格式
graph.run('MATCH (n) RETURN n.name, n.age').data()# Out[441]:# [{'n.name': 'Bob', 'n.age': None},#{'n.name': 'Carol', 'n.age': None},#{'n.name': 'Alice', 'n.age': None}]
- to_data_frame / to_series / to_ndarray / to_subgraph / to_table 转化为 dataframe / series / array / 子图 / table
graph.run('MATCH (n) RETURN n.name, n.age').to_data_frame()# Out[460]:# n.age n.name# 0NoneBob# 1NoneCarol# 2NoneAlice
Errors and Warnings
class py2neo.database.GraphError(*args, **kwargs)[source]class py2neo.database.ClientError(*args, **kwargs)[source]# The Client sent a bad request - changing the request might yield a successful outcome.class py2neo.database.DatabaseError(*args, **kwargs)[source]# The database failed to service the request.class py2neo.database.TransientError(*args, **kwargs)[source]# The database cannot service the request right now, retrying later might yield a successful outcome.class py2neo.database.TransactionFinished(*args, **kwargs)[source]# Raised when actions are attempted against a Transaction that is no longer available for use.
Matching
NodeMatcher 匹配节点,支持 WHERE 子句 支持的条件
from py2neo import NodeMatchermatcher = NodeMatcher(graph)matcher.match('Person', name='Alice').first()# Out[194]: (_4299:Person {age: 21, name: 'Alice'})
后缀操作符
Description Suffix Operator Example Explicit Equal __exact
= matcher.match(“Person”, name__exact=”Kevin Bacon”)
–MATCH (_:Person) WHERE name = “Kevin Bacon” RETURN _
Not Equal __not
matcher.match(“Person”, name__not=”Rick Astley”)
–MATCH (_:Person) WHERE _.name “Rick Astley” RETURN _
Greater than __gt
> matcher.match(“Person”, born__gt=1985)
–MATCH (_:Person) WHERE _.born > 1985 RETURN _
Greater than or equal to __gte
>= matcher.match(“Person”, born__gte=1965)
–MATCH (_:Person) WHERE _.born >= 1965 RETURN _
Less than __lt
< matcher.match(“Person”, born__lt=1965)
–MATCH (_:Person) WHERE _.born < 1965 RETURN _
Less than or equal to __lte
<= matcher.match(“Person”, born__lte=1965)
–MATCH (_:Person) WHERE _.born <= 1965 RETURN _
Starts with __startswith
STARTS WITH matcher.match(“Person”, name__startswith=”Kevin”)
–MATCH (_:Person) WHERE _.name STARTS WITH “Kevin” RETURN _
Ends with __endswith
ENDS WITH matcher.match(“Person”, name__endswith=”Smith”)
–MATCH (_:Person) WHERE _.name ENDS WITH “Smith” RETURN _
Contains __contains
CONTAINS matcher.match(“Person”, name__contains=”James”)
–MATCH (_:Person) HWERE _.name CONTAINS “James” RETURN _
NodeMatch.where 过滤结果
list(matcher.match('Person').where('_.name=~"A.*"'))# Out[197]: [(_4299:Person {age: 21, name: 'Alice'}), (_4324:Person {name: 'Alice'})]list(matcher.match('Person').where('_.name=~"A.*"').order_by('_.name').limit(1))# Out[201]: [(_4299:Person {age: 21, name: 'Alice'})]len(matcher.match('Person').where('_.name=~"A.*"'))# Out[204]: 2
NodeMatcher 的其他方法
- first 返回匹配的第一个结果
- limit 限制匹配到的数量,选取匹配的前 n 个
- order_by 排序
- skip 限制匹配到的数量,选取匹配的后 n 个
RelationshipMatcher 匹配关系,支持与
NodeMatcher
类似的方法from py2neo import RelationshipMatchermatcher = RelationshipMatcher(graph)matcher.match(r_type='KNOWS').first()# Out[209]: (Alice)-[:KNOWS {}]->(Bob)list(matcher.match(r_type='KNOWS').order_by('startnode(_).name'))# Out[216]:# [(Alice)-[:KNOWS {}]->(Bob),#(Alice)-[:KNOWS {}]->(Carol),#(Alice)-[:KNOWS {}]->(Bob),#(Bob)-[:KNOWS {}]->(Carol)]
OGM
- OGM Object Graph Mapping,类似于 ORM,可以实现一个对象和 Node 的关联,类继承
GraphObject
,并指定Property
/Label
属性,以及关系RelatedTo
/RelatedFrom
from py2neo.ogm import GraphObject, Property, Label, RelatedTo, RelatedFromclass Movie(GraphObject):__primarykey__ = 'title'title = Property()tag_line = Property("tagline")released = Property()actors = RelatedFrom('Person', 'ACTED_IN')directors = RelatedFrom('Person', 'DIRECTED')producers = RelatedFrom('Person', 'PRODUCED')class Person(GraphObject):__primarykey__ = 'name'name = Property()born = Property()acted_in = RelatedTo('Movie')directed = RelatedTo('Movie')produced = RelatedTo('Movie')
- Properties 定义一个与节点映射的属性
class Person(GraphObject):name = Property()alice = Person()alice.name = 'Alice Smith'alice.name# Out[262]: 'Alice Smith'
- Labels 定义一个与节点映射的标签,调用结果为
bool
型,表示是否存在该标签class Food(GraphObject):hot = Label()pizza = Food()pizza.hot# Out[265]: Falsepizza.hot = Truepizza.hot# Out[268]: True
- match / where 结合 Graph 查询
# GraphObject.matchmatch(graph, primary_value=None)where(*conditions, **properties)
''' 初始化数据 '''from py2neo import Graph, Node, Relationshipfrom py2neo.ogm import GraphObject, Propertya = Node("Person", name="Alice")b = Node("Person", name="Bob")c = Node('Person', name='Carol')ab = Relationship(a, "KNOWS", b)ac = Relationship(a, 'KNOWS', c)s = ab | acgraph = Graph(auth=('neo4j', "123456"))graph.create(s)aa = graph.nodes.match("Person").first()aa['age'] = 21graph.push(aa)''' Object 与 Node 映射 '''class Person(GraphObject):__primarykey__ = 'name'name = Property()age = Property()location = Property()pp = Person.match(graph).where(age=21).first()print("pp = %s, pp.name = %s, pp.age = %d" % (pp, pp.name, pp.age))# pp = , pp.name = Carol, pp.age = 21''' 使用 Object 更新数据 '''pp.__ogm__.node# Out[5]: (_114:Person {age: 21, name: 'Carol'})pp.age = 22pp.location="Qing Dao"pp.__ogm__.node# Out[7]: (_114:Person {age: 22, location: 'Qing Dao', name: 'Carol'})graph.push(pp)graph.nodes.match("Person").first()# Out[9]: (_114:Person {age: 22, location: 'Qing Dao', name: 'Carol'})
- RelatedTo / RelatedFrom / Related 查看 / 设置 outgoing / incoming / no-direction 关系
from py2neo.ogm import RelatedToclass Person(GraphObject):__primarykey__ = 'name'name = Property()age = Property()location = Property()knows = RelatedTo('Person', 'KNOWS')pp = Person.match(graph).where(age=22).first()list(pp.knows)# Out[26]: []''' add 创建新的 RelatedTo '''new_person = Person()new_person.name = "James"new_person.age = 28new_person.location = "Qing Dao"new_person.knows.add(pp)pp.knows.add(new_person)list(pp.knows)# Out[28]: [, ]''' 此时只是 Object 更新了,需要同步到数据库 '''# 更新关系会同时更新新加的节点graph.push(pp)graph.nodes.match("Person").first()# Out[32]: (_78:Person {age: 28, location: 'Qing Dao', name: 'James'})graph.push(new_person)''' remove 删除 RelatedTo '''pp.knows.remove(new_person)list(pp.knows)# Out[36]: []
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qckNWgqJ-1678944724463)(images/neo4j_py2neo_ogm.jpg)]
- GraphObject 其他操作方法
- pull 根据数据库中的数据更新 GraphObject 中的数据
- push 更新数据库中的数据
- delete 删除数据库中的节点
Cypher
- cypher_escape cypher 转义,将字符串中的特殊字符转义成 cypher 需要的格式
from py2neo.cypher import cypher_escapecypher_escape("simple_identifier")# Out[270]: 'simple_identifier'cypher_escape("identifier with spaces")# Out[271]: "'identifier with spaces'"cypher_escape("identifier with `backticks`")# Out[272]: "'identifier with `backticks`'""MATCH (a:{label}) RETURN id(a)".format(label=cypher_escape("Employee of the Month"))# Out[273]: "MATCH (a:'Employee of the Month') RETURN id(a)"
- CypherLexer 用于解析 cypher 命令,基于
Pygments lexer framework
from py2neo.cypher.lexer import CypherLexerlist(lexer.get_tokens("MATCH (a:Person)-[:KNOWS]->(b) RETURN a"))# Out[290]:# [(Token.Keyword, 'MATCH'),#(Token.Text.Whitespace, ' '),#(Token.Punctuation, '('),#(Token.Name.Variable, 'a'),#(Token.Punctuation, ':'),#(Token.Name.Label, 'Person'),#(Token.Punctuation, ')-['),#(Token.Punctuation, ':'),#(Token.Name.Label, 'KNOWS'),#(Token.Punctuation, ']->('),#(Token.Name.Variable, 'b'),#(Token.Punctuation, ')'),#(Token.Text.Whitespace, ' '),#(Token.Keyword, 'RETURN'),#(Token.Text.Whitespace, ' '),#(Token.Name.Variable, 'a'),#(Token.Text.Whitespace, '\n')]list(lexer.get_statements("CREATE (:Person {name:'Alice'}); MATCH (a:Person {name:'Alice'}) RETURN id(a)"))# Out[291]:# ["CREATE (:Person {name:'Alice'})",#"MATCH (a:Person {name:'Alice'}) RETURN id(a)"]