我有一个很大的neo4j数据库,其中有关于明星的信息,他们都与其他许多人有关系,他们是相互联系,约会,彼此结婚。所以我需要从一个名人那里得到随机路径,并定义关系数(5)。我不在乎谁会在这个链条中,我唯一的条件就是不应该在链条中重复明星。
更清楚:我需要在每次查询后获得“新”链,例如:
可以通过查询来实现吗?
答案 0 :(得分:1)
这在Cypher中是可行的,但它非常棘手。你提到
我唯一的条件我不应该在链条中重复出现明星。
可以通过使用节点 - 同构模式匹配来捕获此条件,这需要路径中的所有节点都是唯一的。不幸的是,Cypher尚未支持此功能。它是proposed as part of the openCypher project,但仍在进行中。目前,Cypher仅支持relationship uniqueness,这对于这个用例是不够的,因为有多种关系类型(例如A与B结合,但B也与A合作,所以我们已经有一个只有两个节点的副本)。
APOC解决方案。如果您可以使用APOC库,请查看path expander,它支持各种唯一性约束,包括NODE_GLOBAL
。
Plain Cypher解决方案。要解决此限制,您可以使用过滤操作捕获节点唯一性约束:
MATCH p = (c1:Celebrity {name: 'Rita Ora'})-[*5]-(c2:Celebrity)
UNWIND nodes(p) AS node
WITH p, count(DISTINCT node) AS countNodes
WHERE countNodes = 5
RETURN p
LIMIT 1
性能方面,只要限制其结果,这应该没问题,因为查询引擎基本上会一直枚举新路径,直到其中一个路径通过过滤测试。
UNWIND nodes(p) AS node WITH count(DISTINCT node) ...
构造的目标是首先从节点列表中删除重复项UNWIND-ing以分隔行,然后aggregating them to a unique collection using DISTINCT
。然后我们检查唯一节点列表是否仍有5个元素 - 如果是,原始列表也是唯一的,我们RETURN
结果。
注意。而不是UNWIND
和count(DISTINCT ...)
,从列表中获取唯一元素可以用其他方式表达:
(1)使用list comprehension和范围:
WITH [1, 2, 2, 3, 2] AS l
RETURN [i IN range(0, length(l)-1) WHERE NOT l[i] IN l[0..i] | l[i]]
(2)使用reduce:
WITH [1, 2, 2, 3, 2] AS l
RETURN reduce(acc = [], i IN l | acc + CASE NOT i IN acc WHEN true THEN [i] ELSE [] END)
但是,我认为这两种形式的可读性都低于原始形式。