Neo4J节点遍历密码每个节点的where子句
我一直在玩neo4j为一个geneology网站,它的工作很好!Neo4J节点遍历密码每个节点的where子句
我遇到了一个障碍,找到起始节点并不容易。通过在线文档和帖子查看,我还没有看到任何暗示这一点,所以也许这是不可能的。
我想要做的是传递性别列表,并从该列表中通过节点的特定路径获取单个节点。
在家庭背景:
我想我母亲的父亲的母亲的母亲。所以我有我的ID,所以我会从那里开始并遍历我的四个节点。
所以伪查询是
select person (follow childof relationship)
where starting node is me
where firstNode.gender == female
AND secondNode.gender == male
AND thirdNode.gender == female
AND fourthNode.gender == female
着眼于一般的解决办法:
MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person)
WHERE me.uuid = {uuid}
AND length(p) = size({genders})
AND extract(x in tail(nodes(p)) | x.gender) = {genders}
RETURN ancestor
这里的如何作品:
- 按id开始节点匹配
- 匹配所有可变长度的路径要任何祖先
- 约束的路径的length(即关系的数量,这是一样的祖先的数量),因为你不能参数长度在查询
- 路径提取性别
-
nodes(p)
回报所有节点的路径,包括起始节点 -
tail(nodes(p))
跳过列表中的第一个元素,即起始节点,所以现在我们只有祖先 -
extract()
提取所有祖先节点的性别,也就是它把祖先的节点列表进入他们的性别 - 性别的提取的列表可以比作参数
-
- 如果路径匹配,我们可以返回绑定的祖先,这是路径
然而结束,我不认为它将比明确的解决方案更快,但性能可以保持可比性。在我的小测试数据(只有5个节点)上,通用解决方案可以实现26个DB访问,而具体解决方案只有22个,如PROFILE
所报告的那样。将需要进一步分析一个更大的数据库来比较性能:
PROFILE MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person)
WHERE me.uuid = {uuid}
AND length(p) = size({genders})
AND extract(x in tail(nodes(p)) | x.gender) = {genders}
RETURN ancestor
总体方案具有将不需要通过Cypher支架引擎重新分析单个查询的优势,而每个生成的查询将需要被解析。
它比我想象的更简单。也许还有更好的方法,所以我会稍微打开一下。
查询将
MATCH (n1:Person { Id: 'f59c40de-506d-4829-a765-7a3ae94af8d1' })
<-[:CHILDOF]-(n2 { Gender:'0'})
<-[:CHILDOF]-(n3 { Gender:'1'})
<-[:CHILDOF]-(n4 { Gender:'1'})
RETURN n4
和每一代背会添加一个新行。
作为一个侧面说明,如果'n1'就是你,你的关系似乎走错了方向。通常情况下,你读的是它的方向,当它实际上是相反的时候,这就是“n2 childof n1”。 –
等效查询将是这个样子:
MATCH (me:Person)
WHERE me.ID = ?
WITH me
MATCH (me)-[r:childof*4]->(ancestor:Person)
WITH ancestor, EXTRACT(rel IN r | endNode(rel).gender) AS genders
WHERE genders = ?
RETURN ancestor
声明,我没有仔细检查语法。
在Neo4j中,您通常首先找到您的起始节点,通常通过某种类型的ID(根据需要进行修改以匹配唯一属性)。然后,我们遍历许多关系到祖先,提取遍历关系中所有末端节点的性别属性,并将性别与期望的性别列表进行比较(您需要确保参数是包含在期望的顺序)。
请注意,这种方法会过滤掉所有可能的结果,而不是走过你的图表,所以关系越高(你查询的祖先的程度越高),呼叫就会越慢。
我还不确定您是否可以参数化变量关系的程度,以便可以防止它成为任何程度的祖先的广义解决方案。
我不知道你是否想要一个通用查询,它可以工作在任何你通过的性别集合或者特定的解决方案。
下面是具体的解决方案:您将路径与想要的长度相匹配,并匹配每个性别,如您在自己的答案中已经注意到的那样。
MATCH (me:Person)-[:IS_CHILD_OF]->(p1:Person)
-[:IS_CHILD_OF]->(p2:Person)
-[:IS_CHILD_OF]->(p3:Person)
-[:IS_CHILD_OF]->(p4:Person)
WHERE me.uuid = {uuid}
AND p1.gender = {genders}[0]
AND p2.gender = {genders}[1]
AND p3.gender = {genders}[2]
AND p4.gender = {genders}[3]
RETURN p4
现在,如果你想传递任意长度的性别列表,它实际上是可能的。您匹配一个可变长度的路径,确保它具有正确的长度(匹配性别数量),然后按顺序匹配每个性别。
MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person)
WHERE me.uuid = {uuid}
AND length(p) = size({genders})
AND all(i IN range(0, size({genders}) - 1)
WHERE {genders}[i] = extract(x in tail(nodes(p)) | x.gender)[i])
RETURN ancestor
大厦@ InverseFalcon的答案,实际上你可以比较的集合,从而简化了查询:
MATCH p = (me:Person)-[:IS_CHILD_OF*]->(ancestor:Person)
WHERE me.uuid = {uuid}
AND length(p) = size({genders})
AND extract(x in tail(nodes(p)) | x.gender) = {genders}
RETURN ancestor
最后建议的查询是最干净的。如果你认为这也是最快速的解决方案,那么我会将其标记为正确的。我已经测试了它对我的数据库,它很好。用新的答案你可以在关键词的简要解释中进行解释?提取物和尾巴以及管道。谢谢 –
今天早上想了解更多。这个查询将是一个n^2查询。它会比较通往所有可能祖先的所有可能路径。如我错了请纠正我。而如果我循环访问数据集并像我在答案中那样构建查询,它会表现得更好,因为它只查看每个级别的相关数据。所以它会更接近于n。我对Neo4J仍然很陌生,所以我可能会误解。 –
假设你长大了_n_世代的祖先,有_Σ(i = 1→n,2^i)_不同的路径,但希望性别只会被比较为_2^n_(它取决于是否以及如何Cypher引擎重新排序'WHERE'子句)并构建长度为_n_的路径,无论如何您必须首先在_n-1_上创建一个路径。通过建立一个特定的查询,因为你可以直接在每一代选择2个可用的正确的分支,只有_2 * n_性别比较需要完成,并且如果远离血统,速度会更快。 –
这个问题源于Cypher中不能进行递归的事实,所以通用解决方案可能会比定制解决方案效率低得多。这是你的召唤,无论如何,你只会建立_n_不同的查询,以至于无论如何都要生成_n_代(如果你构建它们参数化)。 –