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

Lev*_*rts 1 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使用多个类别查找所有节点.例如:查找Place具有类别的所有节点Food或者Bar 我们只是在另一个MATCH语句上添加?如果没有,那么最合适的路线是什么?

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

jus*_*ela 6

如果我正确理解您的域名,我建议您Category自己创建节点.

MERGE (:Category {name:"Food"})
MERGE (:Category {name:"Bar"})
MERGE (:Category {name:"Park"})
Run Code Online (Sandbox Code Playgroud)

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

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"})
Run Code Online (Sandbox Code Playgroud)

然后,如果你想找到Place属于a的s Category,它可以非常快.首先匹配类别,然后分支到与类别相关的位置.

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

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

更复杂

在多个类别中查找位置也很容易.

MATCH (c:Category) WHERE c.name = "Bar" OR c.name = "Food", (c)<-[:IS_A]-(p:Place)
RETURN p
Run Code Online (Sandbox Code Playgroud)

再次,您只是首先匹配类别(快速,因为它们不是很多),然后分支到连接的位置.

使用索引

如果你想要快速,你需要在有意义的地方使用索引.在这个例子中,我将使用类别name属性的索引.

CREATE INDEX ON :Category(name)
Run Code Online (Sandbox Code Playgroud)

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

CREATE CONSTRAINT ON (c:Category) ASSERT c.name IS UNIQUE
Run Code Online (Sandbox Code Playgroud)

索引(和唯一性)会对查询速度产生很大影响.

为什么这是最快的

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

目标是尽快到达起始节点.在那里,遍历相关实体很快.如果你只有1000个类别,但你有10亿个名额,那么挑选个人Category比个人更快Place.一旦有了这个起始节点,访问相关节点将非常有效.

其他选择

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

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

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

我希望这有帮助!

  • 如果您(在Neo4j 2.2+中)使用`EXPLAIN`或`PROFILE'为查询添加前缀,您还可以直观地看到查询的复杂性. (2认同)