当前位置: 首页 > 知识库问答 >
问题:

Neo4j Cypher查询查找未连接的节点太慢

潘振国
2023-03-14

假设我们有下面的Neo4j模式(简化了,但它显示了重要的一点)。有两种类型的节点节点版本<代码>版本s通过关系的VERSION\u连接到节点sVERSION节点确实有两个属性fromuntil,它们表示有效时间跨度-其中一个或两个可以是NULL(在Neo4j术语中不存在)以表示无限<代码>节点s可以通过HAS\u CHILD关系连接。同样,这些关系有两个属性fromuntil,表示有效时间跨度-其中一个或两个可以NULL(在Neo4j术语中不存在)表示无限。

编辑:VERSION节点和HAS_CHILD关系的有效性日期是独立的(尽管示例巧合地显示它们是对齐的)。

该示例显示了两个节点A和B。A有两个版本AV1到2017年6月30日,AV2从2017年7月1日开始,而B只有一个版本BV1是无限的。在2017年6月30日之前,B通过A与A有子关系连接。

现在的挑战是在一个特定时刻查询图中所有非子节点(根节点)的节点。鉴于上述示例,如果查询日期为6/1/17,则查询应仅返回B,但如果查询日期为8/1/17,则应返回B和A(因为从2017年7月1日起,A不再是B的子项)。

当前的查询与该查询大致相似:

MATCH (n1:NODE)
OPTIONAL MATCH (n1)<-[c]-(n2:NODE), (n2)<-[:VERSION_OF]-(nv2:ITEM_VERSION)
WHERE (c.from <= {date} <= c.until)
AND (nv2.from <= {date} <= nv2.until)
WITH n1 WHERE c IS NULL 
MATCH (n1)<-[:VERSION_OF]-(nv1:ITEM_VERSION)
WHERE nv1.from <= {date} <= nv1.until
RETURN n1, nv1 
ORDER BY toLower(nv1.title) ASC 
SKIP 0 LIMIT 15

一般来说,这个查询工作得比较好,但是在大型数据集(与实际生产数据集相当)上使用时,它会变得非常慢。使用20-30kNODEs(以及大约两倍的VERSIONs),(真实的)查询在Mac OS X上运行的小型docker容器上需要大约500-700 ms),这是可以接受的。但是使用1.5MNODEs(并且大约是VERSIONs的两倍),(真正的)查询在裸机服务器上需要1分钟多一点(运行Neo4j以外的任何东西)。这不是真的可以接受的。

我们是否可以选择调整此查询?是否有更好的方法来处理节点s的版本控制(我怀疑这是性能问题)或关系的有效性?我知道关系属性不能被索引,所以可能有更好的模式来处理这些关系的有效性。

任何帮助,甚至是最轻微的暗示都非常感谢。

Michael Hunger回答后编辑:

>

对于当前示例数据集(1.5M节点),结果集包含约2k行。这还不到1%。

ITEM\u VERSION节点在第一个匹配中:

我们正在使用ITEM\u版本nv2筛选结果集,以筛选在给定日期与其他ITEM节点没有连接的ITEM节点。这意味着要么不存在对给定日期有效的关系,要么连接的项目不具有对给定日期有效的item\u版本。我试图说明这一点:

// date 6/1/17

// n1 returned because relationship not valid
(nv1 ...)->(n1)-[X_HAS_CHILD ...6/30/17]->(n2)<-(nv2 ...)

// n1 not returned because relationship and connected item n2 valid
(nv1 ...)->(n1)-[X_HAS_CHILD ...]->(n2)<-(nv2 ...)

// n1 returned because connected item n2 not valid even though relationship is valid
(nv1 ...)->(n1)-[X_HAS_CHILD ...]->(n2)<-(nv2 ...6/30/17)

不使用关系类型:

这里的问题是,该软件具有用户定义的模式和ITEM节点通过自定义关系类型连接。因为我们不能在一个关系上有多种类型/标签,这种关系的唯一共同特征是它们都以X_开始。这在这里的简化示例中被忽略了。用谓词type(r)STARTS with'X_'搜索会有帮助吗?


共有2个答案

卫浩瀚
2023-03-14

我认为改进的一个良好开端是使用索引匹配节点,这样可以快速获得较小的相关节点子集进行搜索。现在,您的方法必须每次检查您的所有:节点及其所有关系和模式,正如您所发现的,这些关系和模式不会随数据扩展。

现在,图形中唯一具有日期/时间属性的节点是:ITEM\u版本节点,因此让我们从这些节点开始。您需要在:ITEM_版本的from和till属性上建立索引,以便快速查找。

空值对您的查找来说是有问题的,因为对空值的任何不等式都会返回空值,并且大多数处理空值的变通方法(使用COALESCE()或几个ANDs/ORs来处理空值)似乎阻止了索引查找的使用,这就是我的特别建议。

我鼓励您使用min和max值替换from和till中的空值,这将使您能够利用索引查找查找节点的优势:

MATCH (version:ITEM_VERSION)
WHERE version.from <= {date} <= version.until
MATCH (version)<-[:VERSION_OF]-(node:NODE)
...

这至少应该在开始时提供对较小节点子集的快速访问,以便继续查询。

邵宜年
2023-03-14

你用的是什么Neo4j版本?

在示例日期,150万个节点中有多大百分比会被发现为根节点,如果您没有限制,返回多少数据?也许问题不在于比赛,而在于最后的排序?

我不知道为什么您在第一部分中有版本节点,至少您没有将它们描述为与确定根节点相关。

你没有使用关系类型。

MATCH (n1:NODE) // matches 1.5M nodes
// has to do 1.5M * degree optional matches
OPTIONAL MATCH (n1)<-[c:HAS_CHILD]-(n2) WHERE (c.from <= {date} <= c.until)
WITH n1 WHERE c IS NULL
// how many root nodes are left?
// # root nodes * version degree (1..2)
MATCH (n1)<-[:VERSION_OF]-(nv1:ITEM_VERSION)
WHERE nv1.from <= {date} <= nv1.until
// has to sort all those
WITH n1, nv1, toLower(nv1.title) as title
RETURN n1, nv1
ORDER BY title ASC 
SKIP 0 LIMIT 15
 类似资料:
  • 10.4. 查找节点的直接子节点 解析 XML 文档时,另一个有用的己技巧是查找某个特定元素的所有直接子元素。例如,在语法文件中,一个 ref 元素可以有数个 p 元素,其中每一个都可以包含很多东西,包括其他的 p 元素。你只要查找作为 ref 孩子的 p 元素,不用查找其他 p 元素的孩子 p 元素。 你可能认为你只要简单的使用 getElementsByTagName 来实现这点就可以了,但是

  • 问题内容: 我有一个节点和方式数据库。一种方式包含两个或更多节点。一些节点属于多种方式,因此被称为两种或多种方式之间的“联接”。 我试图找到所有以两种或两种以上方式连接的节点。所以我正在使用这个查询, way_nodes表包含每种方式的节点列表。 但是,在我的数据库上,它有9,021种方式和43,706个节点,这简直令人难以置信地缓慢,并且每秒只能给我20-30个节点。 最初,我尝试对节点使用次数

  • MongoDB提供了lookup操作,用于实现两个表的关联聚合,但聚合操作编写起来比较麻烦,而且不符合面向对象的思维。为简化开发,bugu-mongo提供了一个JoinQuery类,用于实现两个表的连接查询。 JoinQuery借鉴了SQL左连接的概念: 当前表为左表,被连接的表为右表; 通过指定左键、右键进行关联; 对于不存在关联的数据,只会返回左表的数据,右表的数据为null。 创建JoinQ

  • 我已经成功地连接和运行查询来从neo4j数据库检索数据。现在的问题是,我只能显示结果中的一个节点。如何修改它以显示所有节点?

  • 小精灵:计算连接忽略边,在这个问题中,平行边在相反的方向,我想知道是否有方法找到从给定顶点以两种方式连接的顶点。我们知道重复数据消除()是为了避免重复。但是有没有办法找到具有平行边的顶点?

  • 问题内容: Windows从节点通过“ Java Web Start”连接到Jenkins服务器。节点的系统信息没有其IP地址。 我必须遍历我们拥有的所有从属节点,并找到与Jenkins中的从属节点相对应的机器(IP地址)。 有没有办法从詹金斯本身找到从属节点的IP地址? 问题答案: 通过该 节点 的脚本控制台( Manage Jenkins- > 节点 -> 选择一个节点 -> 脚本控制台 ),