问题:
创建以下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语句上添加?如果没有,那么最合适的路线是什么?
额外:
是否有工具可以帮助我描述遍历过程并告诉我最佳选择方法?
如果我正确理解您的域名,我建议您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标签,因为它们就是这样.另外,类别是事物,因此它们应该是节点.关系描述了事物之间的联系.以这种方式使用类别是没有意义的.
我希望这有帮助!