创建以下MATCH语句的最高效方法是什么?为什么?

时间:2015-06-14 06:08:55

标签: neo4j cypher

问题:
创建以下MATCH语句的最佳性能是什么?为什么?

详细问题:
我们假设我们有一个Place节点,其中包含可变数量的属性,需要根据其类别从可能数十亿个节点中查找节点。我试图围绕每个查询的表现进行总结,这证明是非常困难的。

可能的查询:

  • 使用Place查找匹配property节点:
    MATCH (entity:Place { category: "Food" })

  • Place节点与isCategory节点的Food关系匹配:
    MATCH (entity:Place)-[:isCategory]->(category:Food)

  • Place节点与Food节点的Category关系匹配:
    MATCH (entity)-[category:Food]->(:Category)

  • Food节点与isCategoryFor节点的Place关系匹配:
    MATCH (category:Food)-[:isCategoryFor]->(entity:place)

显然所有的变化都介于两者之间。关系方向也是相反的。

更复杂:
让我们更复杂一点,并说我们现在需要使用多个类别查找所有Place个节点。例如:查找类别为PlaceFood的所有Bar个节点 我们是否只会谈论另一个MATCH声明?如果没有,那么最有效的路线是什么?

额外:
是否有工具可以帮助我描述遍历过程并告诉我最佳选择方法?

1 个答案:

答案 0 :(得分:6)

如果我正确理解您的域名,我建议您自己将Category转换为节点。

MERGE (:Category {name:"Food"})
MERGE (:Category {name:"Bar"})
MERGE (:Category {name:"Park"})

将每个Place节点连接到它所属的Category

MERGE (:Place {name:"Central Park"})-[:IS_A]->(:Category {name:"Park"})
MERGE (:Place {name:"Joe's Diner"})-[:IS_A]->(:Category {name:"Food"})
MERGE (:Place {name:"Joe's Diner"})-[:IS_A]->(:Category {name:"Bar"})

然后,如果您想查找属于Place的{​​{1}},那么它可以非常快。首先匹配类别,然后分支到与类别相关的位置。

Category

您的类别数量相对有限,因此匹配该类别会很快。然后,由于Neo4j实际存储数据的方式,可以快速找到与该类别相关的所有地点。

更复杂

在多个类别中查找地点也很容易。

MATCH (c:Category {name:"Bar"}), (c)<-[:IS_A]-(p:Place)
RETURN p

同样,您只是先匹配类别(快速,因为它们不多),然后分支到连接的位置。

使用索引

如果你想要快速,你需要在有意义的地方使用索引。在这个例子中,我将在类别的MATCH (c:Category) WHERE c.name = "Bar" OR c.name = "Food", (c)<-[:IS_A]-(p:Place) RETURN p 属性上使用索引。

name

或者更好的是,对类别名称使用唯一性约束,这将对它们编制索引并防止重复。

CREATE INDEX ON :Category(name)

索引(和唯一性)会使查询速度产生差异。

为什么这是最快的

Neo4j以非常紧凑,快速访问的格式存储节点和关系。拥有节点或关系后,获取相邻关系或节点的速度非常快。但是,它分别存储每个节点(和关系)的属性,这意味着查看属性相对较慢。

目标是尽快到达起始节点。在那里,遍历相关实体很快。如果您只有1,000个类别,但是您有10亿个位置,那么选择单个CREATE CONSTRAINT ON (c:Category) ASSERT c.name IS UNIQUE 比单个Category更快。一旦有了这个起始节点,进入相关节点将非常有效。

其他选项

只是为了强化,这就是让你的其他选择更慢或更糟的原因。

在第一个示例中,您将查看每个节点上的属性以查找匹配项。属性查找很慢,你做了十亿次。索引可以帮助解决这个问题,但它仍然需要做很多工作。此外,您实际上是在每个十亿个地方复制类别数据,而不是利用Neo4j的优势。

在所有其他示例中,您的数据模型看起来很奇怪。 “食物”,“酒吧”,“公园”等都是类别的所有实例,而不是单独的类型。它们应该都是自己的节点,但它们都应该有Place标签,因为它们就是这样。此外,类别是的东西,因此它们应该是节点。关系描述了事物之间的连接。以这种方式使用类别是没有意义的。

我希望这有帮助!