考虑到以下人为的数据库:
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不适合这个,但另一个数据库非常适合它,我也很感激它的输入。
回答查询效果(截至2017-02-28T21:56Z)
我还没有足够的经验,Neo4j或图表DB查询分析答案的性能,我还没有构建我的大数据集进行更有意义的比较,但我认为我每个都运行PROFILE命令并列出数据库命中成本。我省略了时序数据,因为我无法使这么小的数据集保持一致或有意义。
答案 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