Neo4j 无法优化具有多个可选匹配项的查询

Neo4j trouble optimizing query with multiple optional matches

我以为我掌握了 neo4j。事实证明我不是。我有一个很长的查询,我正在 运行ning。当我 运行 与任何 2 个可选匹配时,它会在大约 20 秒内 运行s。但是,如果我有任何第三个可选匹配项(哪一个似乎无关紧要),将需要将近 15 分钟才能达到 运行。我不太明白。我(有点)理解可选匹配顺序很重要,因为它们在它们之前获取所有已经匹配的东西并使用这些“行”来检查可选匹配,从而使每个匹配的成本成倍增加。我想如果我在每个语句之间小心地添加“with”语句,我可以尝试只过滤每个语句中必需的东西。

我的可选比赛彼此之间并没有太大关系。实际上,我会将其作为 3-4 个不同的 neo4j 查询来执行,但我的老板希望我在一个查询中完成所有操作。如果结果证明性能好得多,我可能最终会违背他的意愿。我将为您提供完整的查询,其中包含一些已更改的名称。它不会影响查询或任何东西,我的工作在技术上是开源的,但我仍然不应该分享任何可识别的内容。

我还 运行“配置文件”以显示完整的树。

profile
match (ds:Analysis)<-[:OUTPUT]-(a)<-[:INPUT]-(firstSample:Sample)<-[*]-(source:Source)
with ds, firstSample

optional match (ds)<-[*]-(othersample:Sample)
with ds, othersample, firstSample
where not othersample.location is null and not trim(othersample.location) = ''

optional match (source)-[:INPUT]->(oa)-[:OUTPUT]->(specialsample:Sample {sample_type:'protein'})-[*]->(ds)
with ds, othersample, firstSample, source, specialsample

optional match (ds)<-[*]-(finalsample:Sample)
with ds, othersample, firstSample, source, specialsample, finalsample
where not finalsample.metadata is null and not trim(finalsample.metadata) = ''


return ds.id, collect(distinct firstSample), collect(distinct source), collect(distinct othersample), collect(distinct specialsample), ds.alt_id, ds.status, ds.group_name, ds.group_uuid, 
ds.created_timestamp, ds.created_email, ds.last_modified_timestamp, ds.last_modified_email, ds.lab_id, ds.data_types, collect(distinct finalsample)

这是挂接到已经编写的 python 脚本中,所以我对输出甚至它们返回的顺序都没有真正的灵活性,但如果有必要我可以做一些事情.

如有任何建议,我们将不胜感激。 https://i.stack.imgur.com/9psgT.png

我会尝试一些事情。

  1. 在查询的早期聚合而不是等到结束。

  2. 尽可能使用 pattern comprehensions 而不是 OPTIONAL MATCH

这可能会让您入门。

match (ds:Analysis)<-[:OUTPUT]-(a)<-[:INPUT]-(firstSample:Sample)<-[*]-(source:Source)

WITH ds, 
collect(distinct firstSample) as firstSamples, 
collect(distinct source) as sources

UNWIND sources as source

OPTIONAL MATCH (source)-[:INPUT]->(oa)-[:OUTPUT]->(specialsample:Sample {sample_type:'protein'})-[*]->(ds)

WITH ds, 
firstSamples, 
collect(distinct source) AS sources, 
collect(distinct specialsample) AS specialSamples

RETURN ds.id, ds.alt_id, ds.status, ds.group_name, ds.group_uuid, 
ds.created_timestamp, ds.created_email, ds.last_modified_timestamp, 
ds.last_modified_email, ds.lab_id, ds.data_types, 
firstSamples, 
sources,
specialSamples,

apoc.coll.toSet([(ds)<-[*]-(othersample:Sample) 
where not othersample.location is null 
and not trim(othersample.location) = '' | othersample]) 
AS otherSamples,

apoc.coll.toSet([(ds)<-[*]-(finalsample:Sample) 
where not finalsample.metadata is null 
and not trim(finalsample.metadata) = '' | finalsample]) 
AS finalSamples

您可以在配置文件跟踪中看到,查询的最终样本部分涉及很多行。你确定你的逻辑是正确的吗?