from py2neo import Graph
g = 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
添加新用户from py2neo import Graph, Node
g = 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 要求 JAVA 1.8 '''
apt install maven openjdk-8-jdk
apt install debhelper devscripts dos2unix dpkg make xmlstarlet
export 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 Desktop
curl -O http://download-keycdn.ej-technologies.com/install4j/install4j_linux_6_1_4.deb
dpkg -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.list
sudo apt-get update
''' 方法3,tar 文件 '''
# https://neo4j.com/download/other-releases/#releases
wget https://go.neo4j.com/download-thanks.html?edition=community&release=3.4.1&flavour=unix
tar xvf neo4j-community-3.4.1-unix.tar.gz
cd neo4j-community-3.4.1
cd bin
./neo4j console
# INFO Remote 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: 123456
neo4j-client -u neo4j-user-1 -p 123456 bolt://localhost:7687
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)]Graph 图 是表示对象与对象之间关系的方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0WkpHSMG-1678944724460)(images/neo4j_node_example.jpg)]
图的学习任务分类
Graph 图 基本组成
(a) // actors
(m) // movies
( ) // some anonymous node
-[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
(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
(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
Editor
// Guides
:play intro
:play concepts
:play cypher
// Examples
:play movie graph
:play northwind graph
其他命令
:sysinfo
:server
:schema
节点和关系 建立之前最好先查找一下是否已经存在这个节点,如果已经存在,建立关系时使用查找到的节点,而不要新建,否则会出现一个新的节点
批量导入 一条条建立关系和节点速度并不快,条件合适应使用 Neo4j 的批量导入功能
数据内容
// 语法规则
CREATE (节点名: 标签 {节点属性})
CREATE (ee:Person { name: "Emil", from: "Sweden", klout: 99 })
MATCH(n:Person) DETACH
DELETE n
// 语法规则
MATCH (匹配出的变量名 : 匹配的标签) WHERE 过滤结果 RETURN 返回特定结果
MATCH (pp:Person) WHERE pp.name = "Emil" RETURN pp;
CREATE 后面直接用 MATCH 时,需要 WITHcreate (ee:Person {name: "Emil", from: "Sweden", klout: 99})
with ee
match (pp:Person) where pp.name="Emil" return pp
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h76yqoFF-1678944724460)(images/neo4j_match.jpg)]// 语法规则
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 ee
MATCH (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 (匹配出的变量名 : 匹配的标签) -[:关系]-(匹配到的关系名)
WHERE 过滤结果 RETURN 返回特定结果
// pattern can be used to find Emil's friends
MATCH (ee:Person)-[:KNOWS]-(friends)
WHERE ee.name = "Emil" RETURN ee, friends
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TqZPrpm8-1678944724460)(images/neo4j_match_pattern_knows.jpg)]// 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)]
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)]()
(pp)
(:Person)
(pp:Person)
(pp:Person {name: "Emil"})
-->
-[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
MATCH p=(a)-[:KNOWS]->(m)<-[:KNOWS]-(d) RETURN p
MATCH 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
// 不推荐将可变长度关系绑定到一个变量,使用 path
MATCH p = (aa)-[:KNOWS*1..3]->(bb) WITH *, relationships(p) AS rr RETURN rr
MATCH p = (aa)-[:KNOWS*1..3]->(bb) WITH *, relationships(p) AS rr RETURN aa.name, size(rr), bb.name
MATCH 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 (ir:Person {name: "Ian"}), (em: Person {name: "Emil"})
CREATE (ir)-[:KNOWS]->(em)
RETURN ir, em
CREATE (al:Person {name: "Alice", age: 21})
CREATE (bb:Person {name: "Bob", age: 23})
CREATE (al)-[:KNOWS]->(bb)
WITH al, bb
MATCH (n: Person {name: "Alice"}) RETURN n
MATCH (person:Person)-[:ACTED_IN]->(m:Movie)
WITH person, count(*) AS appearances, collect(m.title) AS movies
WHERE appearances > 1
RETURN person.name, appearances, movies
// Output
+------------------------------------------------------------+
| person.name | appearances | movies |
+------------------------------------------------------------+
| "Tom Hanks" | 2 | ["Cloud Atlas","Forrest Gump"] |
+------------------------------------------------------------+
1 row
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
CALL db.indexes
// 显示图数据库中的元模型
CALL db.schema
DROP INDEX ON :<Label>(<Property>)
DROP INDEX ON :Person(name)
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)
// 查找两个节点间的最短路径
MATCH (aa:Person {name: "Ian"}), (bb:Person {name: "Rik"}), p=shortestpath((aa)-[*..5]-(bb)) RETURN p
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M8SDWS3P-1678944724461)(images/neo4j_shortestpath_single.jpg)]// 查找两个节点间的所有最短路径
MATCH (aa:Person {name: "Ian"}), (bb:Person {name: "Rik"}), p=allShortestPaths((aa)-[*..5]-(bb)) RETURN p
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gmUYYpuq-1678944724461)(images/neo4j_shortestpath_all.jpg)]// 过滤 ANY
MATCH (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
// 过滤 NONE
MATCH (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
:play movie-graph
// 示例
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)]
MATCH (tom {name: "Tom Hanks"}) RETURN tom
MATCH (cloudAtlas {title: "Cloud Atlas"}) RETURN cloudAtlas
MATCH (people:Person) RETURN people.name LIMIT 10
1990 <= released < 2000
MATCH (nineties:Movie) WHERE nineties.released >= 1990 AND nineties.released < 2000 RETURN nineties.title
MATCH (tom:Person {name: "Tom Hanks"})-[:ACTED_IN]->(tomHanksMovies) RETURN tom, tomHanksMovies
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qsPqsO3b-1678944724462)(images/neo4j_movie_tom_hanks_movies.jpg)]MATCH (cloudAtlas {title: "Cloud Atlas"})<-[:DIRECTED]-(directors) RETURN directors.name
MATCH (cloudAtlas:Movie {title: "Cloud Atlas"})<-[:DIRECTED]-(director) RETURN director, cloudAtlas
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hJ9l4Lxs-1678944724462)(images/neo4j_movie_ca_directors.jpg)]MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) RETURN coActors.name
MATCH (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)]MATCH (people:Person)-[relatedTo]-(:Movie {title: "Cloud Atlas"}) RETURN people.name, Type(relatedTo), relatedTo
MATCH (people:Person)-[relatedTo]-(ca:Movie {title: "Cloud Atlas"}) RETURN people, relatedTo, ca
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ipRL3sR-1678944724462)(images/neo4j_movie_ca_relation.jpg)]MATCH (bacon:Person {name:"Kevin Bacon"})-[*1..4]-(hollywood)
RETURN DISTINCT hollywood
MATCH (bacon:Person {name:"Kevin Bacon"})-[*1..2]-(hollywood)
RETURN DISTINCT hollywood, bacon
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J1WFtdCl-1678944724462)(images/neo4j_movie_becon_relation.jpg)]MATCH p=shortestPath(
(bacon:Person {name:"Kevin Bacon"})-[*]-(meg:Person {name:"Meg Ryan"})
)
RETURN p
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VDqiGas9-1678944724462)(images/neo4j_movie_becon_path.jpg)]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 <> cocoActors
RETURN 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 |
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)]// Delete all Movie and Person nodes, and their relationships
MATCH (n) DETACH DELETE n
// Prove that the Movie Graph is gone
MATCH (n) RETURN n
LOAD CSV WITH HEADERS FROM "http://neo4j.com/docs/developer-manual/3.4/csv/import/persons.csv" AS csvLine
CREATE (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 |
// 在使用 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 csvLine
MERGE (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 |
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
USING PERIODIC COMMIT
在加载大型 csv 文件时,通知 Neo4j 会创建大量的数据USING PERIODIC COMMIT 500
LOAD CSV WITH HEADERS FROM "https://neo4j.com/docs/developer-manual/3.4/csv/import/roles.csv" AS csvLine
MATCH (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 |
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:Movie
REMOVE n.id
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 |
:help cypher LOAD CSV
// products.csv
LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/products.csv" AS row
CREATE (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.csv
LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/categories.csv" AS row
CREATE (n:Category)
SET n = row
// suppliers.csv
LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/suppliers.csv" AS row
CREATE (n:Supplier)
SET n = row
CREATE INDEX ON :Product(productID)
CREATE INDEX ON :Category(categoryID)
CREATE INDEX ON :Supplier(supplierID)
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.categoryID
CREATE (p)-[:PART_OF]->(c)
MATCH (p:Product),(s:Supplier)
WHERE p.supplierID = s.supplierID
CREATE (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 ProduceSuppliers
RETURN s, p, c
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vgIyAif6-1678944724463)(images/neo4j_nw_produce_relation.jpg)]
LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/customers.csv" AS row
CREATE (n:Customer)
SET n = row
LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/orders.csv" AS row
CREATE (n:Order)
SET n = row
CREATE INDEX ON :Customer(customerID)
CREATE INDEX ON :Order(orderID)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3eWA2qBz-1678944724463)(images/neo4j_nw_customoe_order_relation.jpg)]
MATCH (c:Customer),(o:Order)
WHERE c.customerID = o.customerID
CREATE (c)-[:PURCHASED]->(o)
LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/order-details.csv" AS row
MATCH (p:Product), (o:Order)
WHERE p.productID = row.productID AND o.orderID = row.orderID
CREATE (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
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 (<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>)
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 relationships
MATCH (<nade_1>)-[:TYPE*minHops..maxHops]->(<node_2>) RETURN <nade_1>, (<node_2>)
RETURN <node-name>.<property1-name>, <node-name>.<propertyn-name>
RETURN <node-name>.<property1-name> AS <name1>, <node-name>.<propertyn-name> AS <name2>
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>)
正则表达式匹配
// 含有字母 a
WHERE <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 p
MATCH (a)
WHERE a.name = 'Eskil' AND ANY (x IN a.array WHERE x = 'one')
RETURN a.name, a.array
MATCH (n)
WHERE exists(n.name)
RETURN n.name AS name, exists((n)-[:MARRIED]->()) AS is_married
MATCH p =(n)-[*1..3]->(b)
WHERE n.name = 'Alice' AND NONE (x IN nodes(p) WHERE x.age = 25)
RETURN p
MATCH p =(n)-->(b)
WHERE n.name = 'Alice' AND SINGLE (var IN nodes(p) WHERE var.eyes = 'blue')
RETURN p
DELETE <node-name-list>
DELETE <node1-name>,<node2-name>,<relationship-name>
MATCH (<node-name>:<label-name> {<property1-name>: <value>})
DETACH DELETE <node-name>
// 删除节点/关系的属性
REMOVE <node-name>.<property1-name>, <node-name>.<property2-name>
// 删除节点/关系的标签
REMOVE <node-name>:<label1-name>, <node-name>:<label2-name>
SET <node-label-name>.<property1-name>, <node-label-name>.<property2-name>
// 默认按升序对行进行排序,DESC 指定降序排列
ORDER BY <node-label-name>.<property1-name>, <node-label-name>.<property2-name> [DESC]
<MATCH Command1>
UNION
<MATCH Command2>
<MATCH Command1>
UNION ALL
<MATCH Command2>
MATCH (<node1-name>:<label1-name>)
RETURN <node1-name>.<property1-name> AS <name1>,
<node1-name>.<propertyn-name> AS <name2>
UNION
MATCH (<node2-name>:<label2-name>)
RETURN <node2-name>.<property2-name> AS <name1>,
<node2-name>.<propertyn-name> AS <name2>
LIMIT <number>
SKIP <number>
MERGE (<node-name>:<label-name>
{
<Property1-name>:<Pro<rty1-Value>
.....
<Propertyn-name>:<Propertyn-Value>
})
// 过滤 NULL 行
WHERE IS NULL
WHERE IS NOT NULL
IN [<Collection-of-values>]
// MATCH WHERE IN RETURN
MATCH (<node-name>:<label-name>)
WHERE <node-name>.<property-name> IN [<value1>, <value2>, <value3>]
RETURN <node-name>.<property1-name>, <node-name>.<property2-name>
// 在节点或关系的 的 上创建一个新索引
CREATE INDEX ON :<label_name> (<property_name>)
// 删除在节点或关系的 的 上创建的现有索引
DROP INDEX ON :<label_name> (<property_name>)
CREATE CONSTRAINT ON (<label_name>)
ASSERT <property_name> IS UNIQUE
CREATE CONSTRAINT ON ... ASSERT ... IS UNIQUE
创建 唯一性约束,同时会创建 唯一性索引DROP CONSTRAINT ON (<label_name>)
ASSERT <property_name> IS UNIQUE
RETURN DISTINCT <node-name>.<property1-name>
字符串函数列表
功能 | 描述 | 语法 |
---|---|---|
UPPER | 所有字母更改为大写字母 | UPPER() |
LOWER | 所有字母改为小写字母 | LOWER() |
SUBSTRING | 获取给定String的子字符串 | SUBSTRING(, ,) |
REPLACE | 替换一个字符串的子字符串 |
聚合函数列表,类似于SQL中的GROUP BY子句
聚集功能 | 描述 | 语法 |
---|---|---|
COUNT | 统计由 MATCH 命令返回的行数 | COUNT() |
MAX | 返回一组属性中的最大值 | MAX() |
MIN | 返回一组属性中的最大值 | MIN() |
SUM | 返回 MATCH 结果中某一属性的和 | AVG() |
AVG | 返回 MATCH 结果中某一属性的平均值 | SUM() |
关系函数列表,获取 开始节点 / 结束节点等关系的细节
功能 | 描述 | 语法 |
---|---|---|
STARTNODE | 关系的开始节点 | STARTNODE() |
ENDNODE | 关系的结束节点 | ENDNODE() |
ID | 关系的 ID | ID() |
TYPE | 关系的 TYPE | TYPE() |
CALL apoc.index.*
CALL apoc.text.* / date.* / number.*
CALL apoc.algo.community()
CALL apoc.algo.community(25,null,'partition','X', 'OUTGOING','weight',10000)
CALL apoc.path.*
CALL apoc.algo.closeness() / betweenness()
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.*
CALL apoc.cypher.*
CALL apoc.create.*
CALL apoc.refactoring.*
CALL apoc.search.*
class Node(Entity)
__init__(self, *labels, **properties)
class Relationship(Entity)
__init__(self, *nodes, **properties)
from py2neo import Node, Relationship
a = 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)
指定 typeWORKS_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): pass
ac = WorkWith(a, c)
ac
# Out[8]: (Alice)-[:WorkWith {}]->(Carol)
type(ac)
# Out[9]: __main__.WorkWith
a['age'] = 20
b['age'] = 21
r['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]: 2
len(r)
# Out[33]: 1
dict(a)
# Out[35]: {'name': 'Alice', 'age': 20}
dict(r)
# Out[36]: {'time': '2017/08/31'}
a.labels
# Out[37]: :Person
a.add_label('MAN')
a.labels
# Out[51]: :MAN:Person
a.clear_labels()
a.update_labels(['WOMAN', 'PERSON'])
a.labels
# Out[61]: :PERSON:WOMAN
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'})
data = {
'name': 'Amy',
'age': 21
}
a.update(data)
print(a)
# (:Person {age: 21, location: 'Shang Hai', name: 'Amy'})
from py2neo import Node, Relationship
s = ab | ac
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)]
ss = ab & ac
print(list(ss.nodes))
# [(:PERSON:WOMAN {age: 21, location: 'Bei Jing', name: 'Amy'})]
print(list(ss.relationships))
# []
s = a | b | r
print(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'})
from py2neo import Node, Relationship
a = 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) + ac
print(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))
from py2neo import walk
for 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'})
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))
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
# Bolt
graph_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, Graph
a = 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.create
tx = graph.begin()
tx.create(s)
tx.commit()
create 方法传入 Subgraph 对象来将关系图添加到数据库中
# 使用 Graph.create
graph = 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]: True
graph.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
# Carol
graph.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 list
alice = 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"] = 21
graph.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 Graph
graph_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)
# run 执行 cypher 命令返回 Cursor
rr = graph.run('MATCH (n) RETURN n')
type(rr)
# Out[363]: py2neo.database.Cursor
# 遍历 rr 的值是 record
rr.forward()
# Out[364]: 1
tt = rr.current
type(tt)
# Out[366]: py2neo.data.Record
len(tt)
# Out[371]: 1
dict(tt)
# Out[372]: {'n': (_4324:Person {name: 'Bob'})}
tt.data()
# Out[376]: {'n': (_4324:Person {name: 'Bob'})}
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'})
tt.to_subgraph()
# Out[381]: (_4324:Person {name: 'Bob'})
aa = tt.to_subgraph()
aa['name']
# Out[383]: 'Bob'
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
from py2neo import Graph, Node, Relationship
g = 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
tx.finished()
# Out[182]: True
forward-only
,从第一个节点之前开始,只能前向遍历rr = graph.run('MATCH (n) RETURN n')
type(rr)
# Out[404]: py2neo.database.Cursor
for tt in rr:
print('type = %s, name = %s' % (type(tt), tt['n']['name']))
# type = , name = Bob
# type = , name = Carol
# type = , name = Alice
forward
有值返回 1,否则返回 0,current
表示当前的 recordrr = graph.run('MATCH (n) RETURN n')
while rr.forward():
print(rr.current['n']['name'])
# Bob
# Carol
# Alice
rr = graph.run('MATCH ()-[rr:KNOWS]-() RETURN rr')
next(rr)['rr']
# Out[427]: (Alice)-[:KNOWS {}]->(Bob)
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
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}]
graph.run('MATCH (n) RETURN n.name, n.age').to_data_frame()
# Out[460]:
# n.age n.name
# 0 None Bob
# 1 None Carol
# 2 None Alice
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.
NodeMatcher 匹配节点,支持 WHERE 子句 支持的条件
from py2neo import NodeMatcher
matcher = 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 的其他方法
RelationshipMatcher 匹配关系,支持与 NodeMatcher
类似的方法
from py2neo import RelationshipMatcher
matcher = 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)]
GraphObject
,并指定 Property
/ Label
属性,以及关系 RelatedTo
/ RelatedFrom
from py2neo.ogm import GraphObject, Property, Label, RelatedTo, RelatedFrom
class 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')
class Person(GraphObject):
name = Property()
alice = Person()
alice.name = 'Alice Smith'
alice.name
# Out[262]: 'Alice Smith'
bool
型,表示是否存在该标签class Food(GraphObject):
hot = Label()
pizza = Food()
pizza.hot
# Out[265]: False
pizza.hot = True
pizza.hot
# Out[268]: True
# GraphObject.match
match(graph, primary_value=None)
where(*conditions, **properties)
''' 初始化数据 '''
from py2neo import Graph, Node, Relationship
from py2neo.ogm import GraphObject, Property
a = 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 | ac
graph = Graph(auth=('neo4j', "123456"))
graph.create(s)
aa = graph.nodes.match("Person").first()
aa['age'] = 21
graph.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 = 22
pp.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'})
from py2neo.ogm import RelatedTo
class 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 = 28
new_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)]from py2neo.cypher import cypher_escape
cypher_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)"
Pygments lexer framework
from py2neo.cypher.lexer import CypherLexer
list(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)"]