Neo4j入门(一)节点、关系的增删改查

共 14617字,需浏览 30分钟

 ·

2021-07-16 10:08

  本文作为笔者入门Neo4j的第一篇文章,后续将会更多地介绍Neo4j及知识图谱相关的内容。

Neo4j logo

  Neo4j是图数据库中的佼佼者,采用Java编写,社区版已开源,商业版需收费。Neo4j是一个高性能的NoSQL图形数据库(Graph Database),它将结构化数据存储在网络上而不是表中。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。Neo4j也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。Neo4j拥有十分酷炫的可视化界面,这是一般图数据库所不具备的。
  本文将通过一个简单的例子来介绍Neo4j中的基本操作:对节点和边实现增删改查。我们想要实现的图(作为例子,简单易懂)如下:


例子

  在上述例子中,共有两类节点:City和Company,一类关系:(Company) -[belongTo]-> (City)。

CQL

  Neo4j 的 CQL 是非常重要的命令,类似于 SQL 语句,具体的用法可以参考:https://www.w3cschool.cn/neo4j/neo4j_cql_introduction.html。我们使用CQL实现节点、关系的增删改查。

ADD

  City的节点可以通过使用如下命令使用:

create (cityCity{name"上海市", area: "6340.5平方千米", population: "2487.09万人", alias: ["沪""申"]});
create (cityCity{name"北京市", area: "16410平方千米", population: "2189.31万人", alias: ["京""帝都"]});
create (cityCity{name"深圳市", area: "1997.49平方千米", population: "1756万人", alias: ["深""鹏城"]});
create (cityCity{name"杭州市", area: "16850平方千米", population: "1193万人", alias: ["杭"]});

在上述语句中,create表示新建,小括号内是节点信息,节点的类型(label)是City,city是其别名,花括号内是该节点的属性,共有name、area、population、alias四个属性。注意:Neo4j支持列表这个数据类型,但不支持时间日期这个数据类型。
  Company的节点可以通过使用如下命令使用:

create (companyCompany{name"阿里"});
create (companyCompany{name"网易"});
create (companyCompany{name"百度"});
create (companyCompany{name"字节跳动"});
create (companyCompany{name"新浪"});
create (companyCompany{name"拼多多"});
create (companyCompany{name"B站"});
create (companyCompany{name"小红书"});
create (companyCompany{name"华为"});
create (companyCompany{name"腾讯"});
create (companyCompany{name"招商银行"});

  创建关系的命令如下:

match (cityCity{name"杭州市"}), (companyCompany{name"阿里"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);
match (cityCity{name"杭州市"}), (companyCompany{name"网易"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);
match (cityCity{name"上海市"}), (companyCompany{name"拼多多"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);
match (cityCity{name"上海市"}), (companyCompany{name"B站"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);
match (cityCity{name"上海市"}), (companyCompany{name"小红书"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);
match (cityCity{name"北京市"}), (companyCompany{name"新浪"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);
match (cityCity{name"北京市"}), (companyCompany{name"百度"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);
match (cityCity{name"北京市"}), (companyCompany{name"字节跳动"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);
match (cityCity{name"深圳市"}), (companyCompany{name"华为"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);
match (cityCity{name"深圳市"}), (companyCompany{name"腾讯"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);
match (cityCity{name"深圳市"}), (companyCompany{name"招商银行"}) create (company-[r:belongTo{name: "所在城市"}]-> (city);

事实上,我们还可以用如下命令来实现关系的新建:

create (companyCompany{name"阿里"}) -[r:belongTo{name: "所在城市"}]-> (city:City{name"杭州市"});

update

  如果需要更新某个节点的属性,命令如下(比如将上海市节点的简称新增“魔都”这个名字):

MATCH (city:City)
WHERE city.name="上海市"
SET city.alias=["沪""申""魔都"]
RETURN city;
修改上海市节点的属性

上述命令也涉及到了查询(select),只是CQL的查询与SQL接近但又不相同。当然,我们也可以修改某条关系。

delete

  CQL的删除命令有delete和remove,两者的区别为:

  • delete命令为删除节点、删除节点及相关节点和关系;

  • remove命令为删除节点或关系的标签、删除节点或关系的属性

我们以删除上海市节点的alias属性为例,命令如下:

MATCH (cityCity{name"上海市"})
REMOVE city.alias
RETURN city;
删除上海市节点的alias属性

注意,当我们在删除某个节点的时候,需要确定该节点无其他节点无关系相连,即该节点为孤立节点,否则,就会报错。比如,我们想删除上海市这个节点,命令如下:
MATCH (cityCity{name"上海市"})
DELETE city;

报错如下:

删除上海市节点会报错

select

  CQL的查询语句是灵活、功能强大的。我们仅介绍简单的几个命令。

  • 查询所有的节点:

match (n) return (n);
  • 查询所有节点的数量

match (n) return count(n);
  • 查询所有的Company节点

match (n:Company) return (n);
  • 查询名字为北京市的City节点

match (n:City{name"北京市"}) return (n);
  • 查询招商银行与深圳市的关系

match (a:Company{name"招商银行"}) -[r]-> (b:City{name"深圳市"}) return type(r); 
  • 查询该图谱中杭州市下面的Company

match (a:Company) -[r:belongTo]-> (b:City{name"杭州市"}) return (a); 

CQL还支持更高级的查询,如最短路径查询等。

py2neo

  py2neo是用来对接 Neo4j 的 Python 库,官方文档地址为http://py2neo.org/v3/index.html,
GitHub地址为https://github.com/technige/py2neo。
  下面将介绍如何使用py2neo实现对Neo4j的简单操作。

neo4j的连接

  py2neo连接Neo4j需要Neo4j的服务网址,用户名和密码,示例连接Python代码如下:

# -*- coding: utf-8 -*-
from py2neo import Graph

url = "http://localhost:7474"
username = "neo4j"
password = "password"
graph = Graph(url, auth=(username, password))
print("neo4j info: {}".format(str(graph)))

输出结果如下:

neo4j info: Graph('http://neo4j@localhost:7474')

ADD

  我们来创建4个City节点和11个Company节点,代码如下:

from py2neo import Node, Relationship, Subgraph
city_list = [{"name""上海市""area""6340.5平方千米""population""2487.09万人""alias": ["沪""申"]},
             {"name""北京市""area""16410平方千米""population""2189.31万人""alias": ["京""帝都"]},
             {"name""深圳市""area""1997.49平方千米""population""1756万人""alias": ["深""鹏城"]},
             {"name""杭州市""area""16850平方千米""population""1193万人""alias": ["杭"]}]
company_list = [{"name""阿里"},
                {"name""网易"},
                {"name""百度"},
                {"name""新浪"},
                {"name""字节跳动"},
                {"name""小红书"},
                {"name""B站"},
                {"name""拼多多"},
                {"name""华为"},
                {"name""招商银行"},
                {"name""腾讯"}
                ]
for city in city_list:
    node = Node("City", **city)
    graph.create(node)
for company in company_list:
    node = Node("Company", **company)
    graph.create(node)

或者可以通过子图(Subgraph)来创建,这样创建效率更高,使用子图的示例代码如下:

from py2neo import Node, Relationship, Subgraph
city_list = [{"name""上海市""area""6340.5平方千米""population""2487.09万人""alias": ["沪""申"]},
             {"name""北京市""area""16410平方千米""population""2189.31万人""alias": ["京""帝都"]},
             {"name""深圳市""area""1997.49平方千米""population""1756万人""alias": ["深""鹏城"]},
             {"name""杭州市""area""16850平方千米""population""1193万人""alias": ["杭"]}]
company_list = [{"name""阿里"},
                {"name""网易"},
                {"name""百度"},
                {"name""新浪"},
                {"name""字节跳动"},
                {"name""小红书"},
                {"name""B站"},
                {"name""拼多多"},
                {"name""华为"},
                {"name""招商银行"},
                {"name""腾讯"}
                ]
node_list = []
for city in city_list:
    node_list.append(Node("City", **city))
for company in company_list:
    node_list.append(Node("Company", **company))

new_sub = Subgraph(node_list)
graph.create(new_sub)

  创建City节点与Company节点之间的关系的示例代码如下:

# 创建关系
from py2neo import NodeMatcher
rel_dict = {"上海市": ["小红书""B站""拼多多"],
            "北京市": ["百度""新浪""字节跳动"],
            "深圳市": ["华为""招商银行""腾讯"],
            "杭州市": ["阿里""网易"]}

node_matcher = NodeMatcher(graph=graph)
for key, vals in rel_dict.items():
    for val in vals:
        start_node = node_matcher.match("Company", name=val).first()
        end_end = node_matcher.match("City", name=key).first()
        rel = Relationship(start_node, "belongTo", end_end, name="所在城市")
        graph.create(rel)

这样创建的图谱就是一开始演示的例子。当然,我们也可以用Subgraph来创建,效率会更高。

UPDATE

  如果需要更新某个节点的属性,示例Python代码如下(比如将上海市节点的简称新增“魔都”这个名字):

# before update
node_matcher = NodeMatcher(graph=graph)
node = node_matcher.match("City", name="上海市").first()
print(node.__repr__())
# update node
node["alias"] = ['沪''申''魔都']
graph.push(node)
# after update
node = node_matcher.match("City", name="上海市").first()
print(node.__repr__())

输出结果如下:

Node('City'alias=['沪''申'], area='6340.5平方千米'name='上海市', population='2487.09万人')
Node('City'alias=['沪''申''魔都'], area='6340.5平方千米'name='上海市', population='2487.09万人')

当然,我们也可以更新关系。

DELETE

  我们以删除上海市节点的alias属性为例,示例Python代码如下:

# before delete
node_matcher = NodeMatcher(graph=graph)
node = node_matcher.match("City", name="上海市").first()
print(node.__repr__())
# delete node property
del node["alias"]
graph.push(node)
# after update
node = node_matcher.match("City", name="上海市").first()
print(node.__repr__())

输出结果如下:

Node('City'alias=['沪''申''魔都'], area='6340.5平方千米'name='上海市', population='2487.09万人')
Node('City', area='6340.5平方千米'name='上海市', population='2487.09万人')

当然,我们也可以删除节点。

SELECT

  py2neo也能够很好地支持查询语句,示例代码如下:

  • 查询所有的节点:

graph.nodes.match().all()
  • 查询所有节点的数量

len(graph.nodes.match().all())
  • 查询所有的Company节点

graph.nodes.match("Company").all()
  • 查询名字为北京市的City节点

graph.nodes.match("City", name="北京市").all()
  • 查询招商银行与深圳市的关系

node_matcher = NodeMatcher(graph=graph)
end_node = node_matcher.match("City", name="深圳市").first()
start_node = node_matcher.match("Company", name="招商银行").first()
print(graph.match([start_node, end_node]).first())
  • 查询该图谱中杭州市下面的Company

from py2neo import RelationshipMatcher
node_matcher = NodeMatcher(graph=graph)
node = node_matcher.match("City", name="杭州市").first()
rel_matcher = RelationshipMatcher(graph=graph)
find_rels = rel_matcher.match([None, node], r_type="belongTo").all()
print([_.start_node for _ in find_rels if _.start_node.has_label("Company")])

py2neo还支持CQL语句,我们以最后的查询语句为例,示例代码如下:

cql = 'match (a:Company) -[r:belongTo]-> (b:City{name: "杭州市"}) return (a); '
print(graph.run(cql).data())

输出结果如下:

[{'a': Node('Company', name='网易')}, {'a': Node('Company', name='阿里')}]

总结

  综上,我们可以了解到,neo4j的CQL以及py2neo各有各的好处,CQL在某些查询场合比较便利,而py2neo可以方便我们使用Python进行对Neo4j的操作,有些操作实现起来也很方便。
  本文简单介绍了Neo4j节点、关系的增删改查,以及CQL、py2neo的使用方法。后续会持续更新Neo4j相关内容,欢迎大家关注~
  2021.7.13-7.14深夜,最近上海酷暑~


浏览 132
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报