Neo4J节点遍历cypher where子句的每个节点

时间:2016-07-25 19:37:12

标签: neo4j

我一直在为neo4j玩一个基因学网站而且效果很好!

我遇到了一个问题,那里找到起始节点并不容易。通过在线查看文档和帖子,我没有看到任何暗示这一点,所以也许这是不可能的。

我想要做的是传递一个性别列表,然后从该列表中按照节点中的特定路径获取单个节点。

在家庭背景下:

我想得到我母亲的父亲母亲的母亲。所以我有我的身份所以我会从那里开始并从我的四个节点遍历。

所以伪查询将是

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

4 个答案:

答案 0 :(得分:2)

关注一般解决方案:

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

这是它的工作原理:

  1. 通过id
  2. 匹配起始节点
  3. 匹配前往任何祖先的所有可变长度路径
  4. 约束路径的length(即关系的数量,与祖先的数量相同),因为您无法在查询中参数化长度
  5. 提取路径中的性别
    1. nodes(p)返回路径中的所有节点,包括起始节点
    2. tail(nodes(p))跳过列表的第一个元素,即起始节点,所以现在我们只有祖先
    3. extract()提取所有祖先节点的性别,即它将祖先节点列表转换为其性别
    4. 可以将提取的性别列表与参数
    5. 进行比较
  6. 如果路径匹配,我们可以返回绑定的祖先,这是路径的结尾
  7. 但是,我认为它不会比显式解决方案更快,尽管性能可以保持可比性。在我的小测试数据(仅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引擎再次解析单个查询,而每个生成的查询都需要进行解析。

答案 1 :(得分:1)

这比我想象的要简单。也许还有更好的方法,所以我会稍微开放一下。

查询将是

MATCH (n1:Person { Id: 'f59c40de-506d-4829-a765-7a3ae94af8d1' })
<-[:CHILDOF]-(n2 { Gender:'0'})
<-[:CHILDOF]-(n3 { Gender:'1'})
<-[:CHILDOF]-(n4 { Gender:'1'})
RETURN n4

并且每回一代都会添加一个新行。

答案 2 :(得分:1)

等效查询看起来像这样:

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(根据需要进行修改以匹配唯一属性)。然后,我们遍历一系列与祖先的关系,提取遍历关系中所有终端节点的性别属性,并将性别与预期的性别列表进行比较(您需要确保参数是括号列表按期望的顺序)。

请注意,这种方法会过滤掉所有可能的结果,而不是走路图,所以关系程度越高(您查询的祖先程度越高),呼叫的速度就越慢得到。

我也不确定你是否可以参数化变量关系的程度,这可能会阻止它成为任何程度的祖先的通用解决方案。

答案 3 :(得分:1)

我不确定您是否想要一个通用查询,它可以处理您传递的性别集合或特定解决方案。

以下是具体的解决方案:您将路径与所需长度匹配,并匹配每个性别,如您在自己的答案中所述。

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