热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python使用py2neo查询Neo4j的节点、关系及路径

本文介绍了使用Py2neo的NodeMatcher和RelationshipMatcher查询图中的节点和关系,以及通过执行Cypher语句的查询方式。感

一、连接Neo4j数据库

本文中会用到多种数据类型,在此一并引用

import pandas as pd
from py2neo import Node,Relationship,Graph,Path,Subgraph
from py2neo import NodeMatcher,RelationshipMatcher

配置Neo4j数据库的访问地址、用户名和密码:

neo4j_url = "访问地址"
user = "用户名"
pwd = "密码"

在此时间段之前访问数据库的方式为:

graph = Graph(neo4j_url, username=user, password=pwd)

在此时间段之后的版本访问数据库的方式为(就是这么不兼容):

graph = Graph(neo4j_url,  auth=(user, pwd))

以下图为例:

  • 图中包含一些Person节点,每个Person节点有name、age、work属性;
  • 其中“赵赵”节点是多label的节点,除了有Person标签,它还有Teacher标签;
  • Person和Person节点之间有同事、邻居、学生、老师等关系;
  • 图中还有一些Location节点,它们之间有包含关系;
  • Person节点和Location节点之间有“到访”关系,“到访”关系具有date和stay_hours两个属性。

二、 通过graph.schema查询图中节点和关系有哪些类型

查看节点的类型用graph.schema.node_labels,查看关系的类型用graph.schema.relationship_types,它们的返回值类型都是frozenset,是不能增删元素的集合。

>>>graph.schema.node_labels 
frozenset({"Location", "Person", "Teacher"})
>>>graph.schema.relationship_types
frozenset({"到访", "包含", "同事", "学生", "老师", "邻居"})


三、使用NodeMatcher查询节点

首先创建一个NodeMatcher对象,用match来指明要匹配哪种label的节点,用where来表示筛选条件(有两种方法)。需要注意的是,匹配成功返回的是NodeMatcher的对象,要转化成Node对象,可以用first取出符合条件的第一个节点,或者转化成节点的list。

>>>node_matcher = NodeMatcher(graph)
>>>node = node_matcher.match("Person").where(age=20).first()
>>>node
Node("Person", age=20, name="李李", work="编程笔记")
>>>nodes = list(node_matcher.match("Person").where(age=35))
>>>nodes
[Node("Person", age=35, name="王王", work="编程笔记")]

where条件有两种写法,一种是把要匹配的属性和值写成key=value的形式,例如上面的where(age=20),这种写法只能按照值是否完全一致来匹配,不能按照值的大小来筛选,如果写成下面这样是会报错的:

node = node_matcher.match("Person").where(age>20).first() # 错误
想要按照值的大小筛选或者做一些字符串的模糊匹配,可以把条件表达式写成一个字符串,整体放在where语句中,在这个字符串中,可以用 _ 来代指匹配到的节点。下面两个例子,第一个是匹配work属性为“月亮XX”模式的Person节点,另一个是匹配age大于20的Person节点。

>>>node = node_matcher.match("Person").where("_.work =~ "月亮.*"").first()
>>>node
Node("Person", "Teacher", age=45, name="赵赵", work="月亮中学")
>>>nodes = list(node_matcher.match("Person").where("_.age > 20"))
>>>nodes
[Node("Person", age=35, name="王王", work="编程笔记"),
 Node("Person", age=30, name="张张", work="编程笔记"),
 Node("Person", "Teacher", age=45, name="赵赵", work="月亮中学")]

将NodeMatcher返回的结果转化为Node数据类型或者Node的list之后,访问其中的属性也就十分简单了,如上面最后一例的结果,访问其中第一个节点的name属性:

>>>nodes[0]["name"]
"王王"


四、 使用RelationshipMatcher查询关系

RelationshipMatcher的match方法有三个及以上参数:

  • 第一个参数是节点的序列或者set,可以为None,为None表示任意节点均可;
  • 第二个参数是关系的类型,可以为None,为None表示任意类型的关系均可;
  • 第三个参数开始是要匹配的属性,写成key=value的形式。

match方法的返回值是RelationshipMatcher类型,需要通过first转化成Relationship数据结构,或者转化为list。

举例说明

列1:比如想要查询“李李”节点的所有关系。先查询出节点,再查询节点的关系,r_type=None表示任意类型的关系均可。返回的关系包括到访、同事。

>>>node1 = node_matcher.match("Person").where(name="李李").first()
>>>relatiOnship= list(relationship_matcher.match([node1], r_type=None))
>>>relationship
[到访(Node("Person", age=20, name="李李", work="编程笔记"), Node("Location", name="禄口机场"), date="2021/7/16", stay_hours=1),
 同事(Node("Person", age=20, name="李李", work="编程笔记"), Node("Person", age=30, name="张张", work="编程笔记")),
 同事(Node("Person", age=20, name="李李", work="编程笔记"), Node("Person", age=35, name="王王", work="编程笔记"))]


例2:查询“李李”和“张张”的关系,两个节点的顺序表示了要匹配的关系的方向。所以在整个图中“李李”和“张张”节点之间的同事关系是双向的,但是查询结果只给出了从“张张”节点到“李李”节点的一条关系。

>>>node1 = node_matcher.match("Person").where(name="李李").first()
>>>node2 = node_matcher.match("Person").where(name="张张").first()
>>>relatiOnship= list(relationship_matcher.match((node2,node1), r_type=None))
>>>relationship
[同事(Node("Person", age=30, name="张张", work="编程笔记"), Node("Person", age=20, name="李李", work="编程笔记"))]

例3:询图中某一类关系,第一个参数为None,第二个参数r_type指定关系类型,这里查询了图中所有的同事关系。

>>>relatiOnship= list(relationship_matcher.match(None, r_type="同事"))
>>>relationship
[同事(Node("Person", age=20, name="李李", work="编程笔记"), Node("Person", age=30, name="张张", work="编程笔记")),
 同事(Node("Person", age=20, name="李李", work="编程笔记"), Node("Person", age=35, name="王王", work="编程笔记")),
 同事(Node("Person", age=35, name="王王", work="编程笔记"), Node("Person", age=20, name="李李", work="编程笔记")),
 同事(Node("Person", age=30, name="张张", work="编程笔记"), Node("Person", age=20, name="李李", work="编程笔记"))]


例4: 在查询关系时按照属性的值筛选,可以将该属性写为key=value的形式作为match方法的第三个参数。这里,查询图中的到访关系,并且stay_hours属性为1。

>>>relatiOnship= list(relationship_matcher.match(None, r_type="到访", stay_hours=1))
>>>relationship
[到访(Node("Person", age=20, name="李李", work="编程笔记"), Node("Location", name="禄口机场"), date="2021/8/24", stay_hours=1)]

虽然Py2neo的手册上没有写,但其实RelationshipMatcher也可以接上where方法,按照属性的值筛选关系。上面这个例子也可以写作下面这种形式,效果是一样的。

relatiOnship= list(relationship_matcher.match(None, r_type="到访").where(stay_hours=1))
同样,在where方法中也可以写一个字符串表达式,实现按值大小来筛选关系。例如要筛选出所有到访关系,且stay_hours>=1的关系时,可以这样写:

>>>relatiOnship= list(relationship_matcher.match(None, r_type="到访").where("_.stay_hours>=1"))
>>>relationship
[到访(Node("Person", age=20, name="李李", work="编程笔记"), Node("Location", name="禄口机场"), date="2021/8/24", stay_hours=1),
 到访(Node("Person", age=20, name="刘刘", work="地球电子商务公司"), Node("Location", name="禄口机场"), date="2021/8/24", stay_hours=4)]

如何访问返回的结果中的各个属性呢,Relationship其实是包含了一对起止节点:start_nodeend_node,包含了关系的类型,而关系的属性是以字典形式存在的,可以用get方法来获取属性的值。
获取关系的起止节点:

>>>print(relationship[0].start_node["name"])
>>>print(relationship[0].end_node["name"])
李李
禄口机场

获取关系的类型的文本字符串

>>>print(relationship[0])
>>>print(type(relationship[0]).__name__)
(李李)-[:到访 {date: "2021/8/24", stay_hours: 1}]->(禄口机场)
到访

获取关系中的属性和值

>>>print(relationship[0].keys())
>>>print(relationship[0].values())
>>>print(relationship[0].get("date"))
dict_keys(["date", "stay_hours"])
dict_values(["2021/8/24", 1])
2021/8/24

五、通过执行Cypher语句查询

NodeMatcher和RelationshipMatcher能够表达的匹配条件相对简单,更加复杂的查询还是需要用Cypher语句来表达。Py2neo本身支持执行Cypher语句的执行,可以将复杂的查询写成Cypher语句,通过graph.run方法查询,返回的结果可以转化为pandas.DataFrame或者pandas.Series对象,从而和其他数据分析工具无缝衔接。

例如:要查询Person节点,并满足work属性为“编程笔记”。Cypher语句中可以使用WHERE接条件表达式,使用AS将返回的属性改名,返回多个属性时,用xxx AS x, yyy AS y。graph.run方法之后再接to_data_frame()可以将返回的数据变成pandas的DataFrame对象,并且用AS改过的属性名即为DataFrame中的列名。

cypher_ = "MATCH (n:Person) 
WHERE n.work="编程笔记" 
RETURN n.name AS name, n.age AS age "

df = graph.run(cypher_).to_data_frame() # pd.DataFrame

例2:查询一个已知节点和其他哪些节点有关系,有什么样的关系。Cypher语言查询关系时用 <或者 > 表示方向,这里需要返回type(r),直接返回r的话结果里是空值。

>>>cypher_ = "MATCH (n:Person)-[r]->(m:Person) 
WHERE n.name="李李" 
RETURN type(r) AS type,m.name AS name"
>>>df = graph.run(cypher_).to_data_frame() # pd.DataFrame

例3:Cypher语言还可以查询路径,因为不确定返回的路径数量,所以最好先将结果转化为pandas.Series,再遍历访问其中每条路径的节点和关系。
这里查询的是“赵赵”节点和“王王”节点之间的关系路径,关系指定为同事或邻居,关系不超过4层。

>>>cypher_ = "MATCH path=(m:Person)-[:同事|邻居*1..4]->(n:Person) 
WHERE m.name="赵赵" AND n.name="王王" 
RETURN path"
>>>s = graph.run(cypher_).to_series()
>>>print(len(s))
>>>s[0]

Path(Node("Person", "Teacher", age=45, name="赵赵", work="月亮中学"),
邻居(Node("Person", "Teacher", age=45, name="赵赵", work="月亮中学"), 
Node("Person", age=30, name="张张", work="编程笔记")), 
同事(Node("Person", age=30, name="张张", work="编程笔记"), 
Node("Person", age=20, name="李李", work="编程笔记")), 
同事(Node("Person", age=20, name="李李", work="编程笔记"), 
Node("Person", age=35, name="王王", work="编程笔记")))

这里查询到的关系路径数量仅有1条。从上图的结果中也可以看出来,Path是一个比较复杂的结构,Path中的节点和关系分别用nodes和relationships表示,并且是按照路径上节点和关系的顺序分别存放的。这里给出一段示例代码,对每一个路径都做了直接打印path数据结构和自己组织路径文本。

for path in s:
    # 直接打印path
    print(path)
    # 获取路径中的节点和关系
    nodes = path.nodes
    relatiOnshis= path.relationships   
    # 自己组织路径文本
    path_text = ""
    for n,r in zip(nodes, relationshis):
        # 每次加入一个节点和一个关系的类型
        path_text += "{} - {} - ".format(n["name"], type(r).__name__)
    # 别忘了最后一个节点
    path_text += nodes[-1]["name"] + "
"
    print(path_text)

运行这段代码得的结果如下所示,上面一行是直接打印路径的结果,下面一行是自己组织文本得到的结果。

(赵赵)-[:邻居 {}]->(张张)-[:同事 {}]->(李李)-[:同事 {}]->(王王)
赵赵 - 邻居 - 张张 - 同事 - 李李 - 同事 - 王王

使用Py2neo查询Neo4j中的节点、关系和路径时,条件简单的查询可以通NodeMatcher和RelationshipMatcher来实现。而较为复杂的查询,可以写成Cypher语句来查询,查询结果可以转化为pandas的DataFrame或者Series数据类型,与其他数据分析工具结合

 以上就是python使用py2neo查询Neo4j的节点、关系及路径的详细内容,更多关于python py2neo的资料请关注编程笔记其它相关文章!

 


推荐阅读
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
author-avatar
-彼岸花开-hui
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有