为什么我会收到“笛卡尔积”警告?

时间:2016-06-10 14:46:46

标签: neo4j graph-databases

我仍在努力理解为什么我会在neo4j中为某个查询获取某种格式的笛卡尔积,而不是另一个。这就是我设置数据库的方式:

CREATE (q:Form {version: "1.0"})
CREATE (q:Question {text: "Sector de la empresa", active: true})

然后我尝试了以下查询:

MATCH
(f:Form {version: "1.0"}),
(q:Question {text: "Sector de la empresa"})
CREATE (f)-[:asks]->(q)
RETURN f, q

但是,我收到以下警告:

This query builds a cartesian product between disconnected patterns.
If a part of a query contains multiple disconnected patterns,
this will build a cartesian product between all those parts.
This may produce a large amount of data and slow down query processing.
While occasionally intended, it may often be possible to reformulate the
query that avoids the use of this cross product, perhaps by adding a
relationship between the different parts or by using OPTIONAL MATCH
(identifier is: (q))

当我使用以下查询时,它不会给我这个警告:

MATCH (f:Form {version: "1.0"})
WITH f
(q:Question {text: "Sector de la empresa"})
CREATE (f)-[:asks]->(q)
RETURN f, q

当我使用此查询时:

MATCH (f:Form {version: "1.0"})
MATCH (q:Question {text: "Sector de la empresa"})
CREATE (f)-[:asks]->(q)
RETURN f, q

我使用以下文章作为资源,但它仍未完全回答我的问题:Why does neo4j warn: "This query builds a cartesian product between disconnected patterns"?

为什么我会为某些查询格式而不是其他格式获取笛卡尔积?另外,我不完全了解笛卡尔产品警告是什么。

2 个答案:

答案 0 :(得分:5)

如果您MATCH在两个不同的标签上没有任何关系,那么您将收到此警告。原因是如果你这样做:

MATCH (a:Foo), (b:Bar)

找到这两个节点的所有可能组合是Neo4j的工作。因此,对于a的第一场比赛,它将为b的每场比赛返回一行,对于a的第二场比赛,它将再次为{{1}的每场比赛返回一行}, 等等。因此,您的结果中将获得b个总行数。随着数据库的增长,这对性能非常不利。

我可以看到您正在(number of Foo nodes) x (number of Bar nodes) versionForm text进行过滤,这样会有所帮助。这甚至可以为您提供一个Question节点和一个Form节点。因此,只要您在QuestionForm(version)上有索引,查询应该非常快。 Neo4j无法告诉(或者至少目前没有实现能够告诉)将返回多少行,因此它会发出警告,说明您的查询可能会很慢。

答案 1 :(得分:1)

他们都是笛卡尔式的

读完你的问题后,我的密码世界崩溃了 - 所有三个问题都应该涉及笛卡尔积。

检查(同时the console和本地数据库 - 版本3.3.0),结果证明我是理智的 - 他们都涉及笛卡尔产品:

The execution plan of the first query, showing a cartesian product

The execution plan of the second query, showing a cartesian product

The execution plan of the third query, showing a cartesian product

为什么在第一种情况下只有一个警告(仍然在版本3.3.0中我没有任何线索 - 你只需要运行计划器来解决这个问题,如果这不是警告那么警告是什么?一些愚蠢的密码逻辑?

Cypher基础知识

Cypher查询由部分组成,每个部分可以是更新(写入)或读取。

就阅读部分而言,这是发生的事情:

  • Neo4j挑选一个starting point,它认为它会产生最少的命中率。它会经历每一次点击......
  • ...使用节点/关系模式遍历图表。
  • 反复这样做,直到没有更多的模式匹配。

如果你有这样的事情:

(a {name:'Bill'})-->(b:Dog)

计划可能看起来像这样。

  • 对于每个节点(AKA AllNodeScan):
    • 根据谓词(name == 'bill'
    • 进行过滤
    • 获取所有传出的-->关系
    • 对于每个关系:
      • 获取结束节点
      • 根据谓词(:Dog
      • 进行过滤

重要的是,在找到(a)时,我们需要扫描每个节点。但我们只是遍历图表,为后者找到(b) s - no AllNodeScan

(有AllNodeScan的变体,请参阅Starting Node Operators

如果您的查询是这样的:

MATCH (f:Form {version: "1.0"}), (q:Question {text: "Sector de la empresa"})

Neo被迫对AllNodeScanf进行q - 他们之间没有模式可以遍历。这可能会创建一个f * q大小的结果集,这可能是巨大的。