为什么在Neo4j中隐藏方面不好?

时间:2019-04-01 10:12:12

标签: neo4j spring-data-neo4j

考虑到下一篇文章中有关方面隐藏的最佳实践,我正在尝试了解构建neo4j实体的最佳实践 https://neo4j.com/blog/dark-side-neo4j-worst-practices/

下图说明,将“ country”属性建模为与Person节点的关系而不是将其封装在节点本身中时,性能会更好

当将其建模为查询的单独实体时,重点在于性能的提高,该查询可以获取居住在特定国家/地区的人员。

https://s3.amazonaws.com/dev.assets.neo4j.com/wp-content/uploads/20160223191647/neo4j-data-modeling-hide-concepts.png

案例1:“国家/地区”字段位于“个人实体”中,因此查询遍历两个节点以检查“国家/地区”字段是否相同

案例2:“国家/地区”作为单独的实体。

我无法理解案例2中支票的数量减少了。 请帮我 。非常感谢您的宝贵时间

1 个答案:

答案 0 :(得分:2)

这里发生的一些事情会影响您的建模决策。

首先,当我们从字段值中提取出一个节点时,我们正在对数据进行规范化。现在,我们不再为居住在英国的所有:Person节点重复相同的值(例如,“ UK”),而是现在只有一个带有“ UK”代码的:Country节点,并且所有居住在英国的人节点都有:LIVES_IN与他们所在国家/地区的关系。因此,在这方面,我们避免了数据库中字符串数据的重复。

要考虑的另一件事是,在Neo4j中,属性查找和过滤通常是较昂贵的操作之一,因此通常可以通过调整查询和建模来进行优化以最小化属性查找和属性过滤。

对于第一种情况,我们总是必须过滤我所有的朋友,才能从所需的国家/地区获得朋友。尽管对于一个如此小的数据集来说,这不是一个问题,但是对于一个人的朋友来说,当涉及到更复杂的查询时,您可能会进行大量的属性查找和过滤,这可能会减慢查询的执行速度。

在第二种情况下,规划器也许可以通过对索引进行查找(在Stefan的节点上查找)(如果规划器不这样做,则可以通过与国家/地区匹配)来优化国家(在:Country(code)上) ,我们可以使用规划器提示进行强制)。预先匹配英国国家节点后,我们可以将模式扩展到朋友及其所在国家的节点,这将对英国节点(或节点哈希联接,取决于计划者的方法)执行ExpandInto操作。无论哪种情况,过滤操作根本不需要进行属性访问,而是基于我们预先匹配的UK节点(基于节点的图ID进行幕后过滤)进行过滤,这是一种有效的操作。 / p>

您可以使用PROFILE或EXPLAIN来检查计划者如何执行查询。

与性能没有直接关系的另一个方面是,在提取此类实体而不是将其保留为属性字段时,您可以解锁的灵活性和实用性。

通过将国家提取到其自己的节点,我们现在可以在不同的上下文中使用这些节点。虽然我们目前在:Person和:Country节点之间具有:LIVED_IN关系,但现在我们可以与:Country节点之间添加任何其他类型的关系。我们可以在图形中获得如下数据:

(:Person)-[:TRAVELED_TO]->(:Country)
(:Language)-[:COMMONLY_SPOKEN_IN]->(:Country)
(:State)-[:LOCATED_IN]->(:Country)

等等。虽然我们可以单独使用这些模式,但是当我们需要将多个部分包含在同一模式中时,才真正发挥作用,从而使我们在查询时拥有丰富的上下文。

例如:“我想知道我的哪个朋友居住或旅行到经常说西班牙语的国家,并找回该朋友和相匹配的国家”

MATCH (me:Person {name:'InverseFalcon'})-[:FRIENDS_WITH]->(friend)-[:LIVES_IN | TRAVELED_TO]->(country:Country)<-[:COMMONLY_SPOKEN_IN]-(:Language {name:'Spanish'})
RETURN friend, collect(country.code) as countries

通过像这样重构我们的模型,我们避免了提取属性值并在随后的匹配中使用它们的麻烦(类似于表联接)。