在Neo4j中,可以找到其关系是另一个节点关系的超集的所有节点吗?

时间:2017-02-27 19:19:03

标签: neo4j cypher

考虑到以下人为的数据库:

CREATE (a:Content {id:'A'}),
  (b:Content {id:'B'}),
  (c:Content {id:'C'}),
  (d:Content {id:'D'}),
  (ab:Container {id:'AB'}),
  (ab2:Container {id:'AB2'}),
  (abc:Container {id:'ABC'}),
  (abcd:Container {id:'ABCD'}),
  ((ab)-[:CONTAINS]->(a)),
  ((ab)-[:CONTAINS]->(b)),
  ((ab2)-[:CONTAINS]->(a)),
  ((ab2)-[:CONTAINS]->(b)),
  ((abc)-[:CONTAINS]->(a)),
  ((abc)-[:CONTAINS]->(b)),
  ((abc)-[:CONTAINS]->(c)),
  ((abcd)-[:CONTAINS]->(a)),
  ((abcd)-[:CONTAINS]->(b)),
  ((abcd)-[:CONTAINS]->(c)),
  ((abcd)-[:CONTAINS]->(d))

是否存在可以检测所有Container个节点对的查询,其中一个CONTAINS节点是与另一个Content节点相同的Container节点?

对于我的示例数据库,我希望查询返回:

(ABCD) is a superset of (ABC), (AB), and (AB2)
(ABC) is a superset of (AB), and (AB2)
(AB) and (AB2) contain the same nodes

如果cypher不适合这个,但另一种查询语言非常适合它,或者Neo4j不适合这个,但另一个数据库非常适合它,我也很感激它的输入。

Visualization of the sample database

回答查询效果(截至2017-02-28T21:56Z)

我还没有足够的经验,Neo4j或图表DB查询分析答案的性能,我还没有构建我的大数据集进行更有意义的比较,但我认为我每个都运行PROFILE命令并列出数据库命中成本。我省略了时序数据,因为我无法使这么小的数据集保持一致或有意义。

  • stdob--:129 db db hits
  • Dave Bennett:总共有46次点击
  • InverseFalcon:27个db db hits

3 个答案:

答案 0 :(得分:3)

// Get contents for each container
MATCH (SS:Container)-[:CONTAINS]->(CT:Content)
      WITH SS, 
           collect(distinct CT) as CTS
// Get all container not equal SS
MATCH (T:Container) 
      WHERE T <> SS
// For each container get their content
MATCH (T)-[:CONTAINS]->(CT:Content)
      // Test if nestd
      WITH SS, 
      CTS, 
      T, 
      ALL(ct in collect(distinct CT) WHERE ct in CTS) as test 
      WHERE test = true
RETURN SS, collect(T)

答案 1 :(得分:2)

这是第一次尝试。我相信这可以使用一些改进,但这应该让你去。

// find the containers and their contents
match (n:Container)-[:CONTAINS]->(c:Content)

// group the contents per container
with n as container, collect(c.id) as contents

// combine the continers and their contents
with collect(container{.id, contents: contents}) as containers

// loop through the list of containers
with containers, size(containers) as container_size
unwind range(0, container_size -1) as i
unwind range(0, container_size -1) as j

// for each container pair compare the contents
with containers, i, j
where i <> j
and all(content IN containers[j].contents WHERE content in containers[i].contents)
with containers[i].id as superset, containers[j].id as subset
return superset, collect(subset) as subsets

答案 2 :(得分:2)

在获取容器及其收集的内容之后,我将使用的方法是过滤掉哪些容器通过其内容计数相互比较,然后运行apoc.coll.containsAll() from APOC Procedures以过滤超集/同等集。最后,您可以比较内容的计数,以确定它是超集还是同等集,然后收集。

这样的事情:

match (con:Container)-[:CONTAINS]->(content)
with con, collect(content) as contents
with collect({con:con, contents:contents, size:size(contents)}) as all
unwind all as first
unwind all as second
with first, second
where first <> second and first.size >= second.size
with first, second
where apoc.coll.containsAll(first.contents, second.contents)
with first, 
 case when first.size = second.size and id(first.con) < id(second.con) then second end as same, 
 case when first.size > second.size then second end as superset
with first.con as container, collect(same.con) as sameAs, collect(superset.con) as supersetOf
where size(sameAs) > 0 or size(supersetOf) > 0
return container, sameAs, supersetOf
order by size(supersetOf) desc, size(sameAs) desc