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
我会尝试一些事情。
在查询的早期聚合而不是等到结束。
尽可能使用 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
您可以在配置文件跟踪中看到,查询的最终样本部分涉及很多行。你确定你的逻辑是正确的吗?
我以为我掌握了 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
我会尝试一些事情。
在查询的早期聚合而不是等到结束。
尽可能使用 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
您可以在配置文件跟踪中看到,查询的最终样本部分涉及很多行。你确定你的逻辑是正确的吗?