Neo4j 数据建模:私有节点、丰富的关系、锁
Neo4j data modeling: private owned nodes, rich relationships, locks
使用的版本:Neo4j 3.0.6 和 Spring-data-neo4j 4.2.0.M1 用于 POJO 映射
我正在尝试选择如何使用 neo4j 对数据建模并比较 benefits/drawbacks 不同的解决方案。
要求:
- 电影有元数据的动态列表(元数据有 3 个属性:'key'、'value'、'locale')。电影的元数据数量是事先不知道的,可能的密钥也是如此。它们必须与其他电影技术属性分开,因为它们已本地化并被视为业务数据。
- 元数据归电影所有,并且始终可以从电影中访问。它们不能与其他电影共享
- 必须可以对元数据值进行快速提取查询
电影元数据示例:
Movie metadata
locale 'en_GB':
title: 'Jurassic Park'
description: 'description in english'
locale 'fr_FR':
description: 'description en francais'
locale 'none':
actor: 'Jeff Goldblum'
解决方案 A
- 每个元数据一个节点(每个节点有 3 个属性:'key'、'value'、'locale')
- 缺点:私有概念 待实施(删除元数据孤立节点以手动管理,因为 spring-data-neo4j/neo4j-ogm 不支持)
解决方案 B
- 每个区域设置一个唯一节点(有 1 个 属性:'locale')(示例:'en_GB')
- 作为丰富关系的元数据(具有 2 个关系属性:'key'、'value')
- 缺点:要创建关系,必须在 Locale 节点
上锁定
有人对解决方案 B 有经验吗? 需要锁定将由数百万其他节点共享的节点有多糟糕?
对性能和可扩展性有何影响?
有人有更好的建模解决方案吗?
您可以直接将 "metadata" 存储为每个 Movie
节点的属性(无需求助于 key
和 value
).这是最简单的方法,它避免了锁定问题并最大限度地减少了所需的节点数和关系。您可以随时向节点自由添加更多属性。这种方法还允许您为特定的 Movie
属性添加索引,您需要在开始查询时快速访问这些属性。
例如:
CREATE (m:Movie {id: 123, title: 'Men in black', director: 'Barry Sonnenfeld'});
[更新]
如果您需要将 "metadata" 与 "data" 完全分开,并且还需要能够本地化元数据(包括 locale
属性),那么您可以将每个 Movie
节点与每个区域设置的单个 Metadata
节点相关联。 Metadata
节点将 直接 包含特定 Movie
节点的单个语言环境的所有元数据属性。
Cypher 可用于执行 "cascading deletes"。例如:
MATCH (m:Movie {id: 123})
OPTIONAL MATCH p=(m)-->()
DELETE p;
tl,dr:采用方法 A。不要理会孤立的 :Locale
节点,除了定期清理,它们不会影响查询性能。
您的方法 'A' 是迄今为止更好的解决方案。您确实需要将该数据移出 :Movie
节点,您是对的,因为它必须是嵌套地图或地图列表,节点属性都不支持这两种情况。对于存储,您可以将它们转换为列表的 Map,但这将很难查询,更不用说快速查询了。您对 "orphaned" 个节点的关注是微不足道的;它会对查询性能和数据大小产生微不足道的影响,并且在任何情况下都非常容易定期清理以使您放心。
MATCH (x:Locale) WHERE NOT (x) <- [:METADATA] - () DETACH DELETE x
一个月做一次,或者从来不做,真的不会对你有太大影响。您的查询已经受到路径其余部分的限制,因此除非孤立 :Locale
节点的数量大大超过附加节点,否则您只是向查询中已经可能是最大的集合添加了一小部分,这也将在第一次通过时被查询操作删除。
至于锁定,无论如何它只会影响写查询,而且只会影响写事务打开时。您可以 运行 在写入过程中进行一百万个只读查询,并且不会受到任何影响。尽管如此,第二种模型容易受到查询性能降低的影响,因为如上所述,您不能在关系属性上放置索引。
使用的版本:Neo4j 3.0.6 和 Spring-data-neo4j 4.2.0.M1 用于 POJO 映射
我正在尝试选择如何使用 neo4j 对数据建模并比较 benefits/drawbacks 不同的解决方案。
要求:
- 电影有元数据的动态列表(元数据有 3 个属性:'key'、'value'、'locale')。电影的元数据数量是事先不知道的,可能的密钥也是如此。它们必须与其他电影技术属性分开,因为它们已本地化并被视为业务数据。
- 元数据归电影所有,并且始终可以从电影中访问。它们不能与其他电影共享
- 必须可以对元数据值进行快速提取查询
电影元数据示例:
Movie metadata
locale 'en_GB':
title: 'Jurassic Park'
description: 'description in english'
locale 'fr_FR':
description: 'description en francais'
locale 'none':
actor: 'Jeff Goldblum'
- 每个元数据一个节点(每个节点有 3 个属性:'key'、'value'、'locale')
- 缺点:私有概念 待实施(删除元数据孤立节点以手动管理,因为 spring-data-neo4j/neo4j-ogm 不支持)
解决方案 B
- 每个区域设置一个唯一节点(有 1 个 属性:'locale')(示例:'en_GB')
- 作为丰富关系的元数据(具有 2 个关系属性:'key'、'value')
- 缺点:要创建关系,必须在 Locale 节点 上锁定
有人对解决方案 B 有经验吗? 需要锁定将由数百万其他节点共享的节点有多糟糕? 对性能和可扩展性有何影响?
有人有更好的建模解决方案吗?
您可以直接将 "metadata" 存储为每个 Movie
节点的属性(无需求助于 key
和 value
).这是最简单的方法,它避免了锁定问题并最大限度地减少了所需的节点数和关系。您可以随时向节点自由添加更多属性。这种方法还允许您为特定的 Movie
属性添加索引,您需要在开始查询时快速访问这些属性。
例如:
CREATE (m:Movie {id: 123, title: 'Men in black', director: 'Barry Sonnenfeld'});
[更新]
如果您需要将 "metadata" 与 "data" 完全分开,并且还需要能够本地化元数据(包括 locale
属性),那么您可以将每个 Movie
节点与每个区域设置的单个 Metadata
节点相关联。 Metadata
节点将 直接 包含特定 Movie
节点的单个语言环境的所有元数据属性。
Cypher 可用于执行 "cascading deletes"。例如:
MATCH (m:Movie {id: 123})
OPTIONAL MATCH p=(m)-->()
DELETE p;
tl,dr:采用方法 A。不要理会孤立的 :Locale
节点,除了定期清理,它们不会影响查询性能。
您的方法 'A' 是迄今为止更好的解决方案。您确实需要将该数据移出 :Movie
节点,您是对的,因为它必须是嵌套地图或地图列表,节点属性都不支持这两种情况。对于存储,您可以将它们转换为列表的 Map,但这将很难查询,更不用说快速查询了。您对 "orphaned" 个节点的关注是微不足道的;它会对查询性能和数据大小产生微不足道的影响,并且在任何情况下都非常容易定期清理以使您放心。
MATCH (x:Locale) WHERE NOT (x) <- [:METADATA] - () DETACH DELETE x
一个月做一次,或者从来不做,真的不会对你有太大影响。您的查询已经受到路径其余部分的限制,因此除非孤立 :Locale
节点的数量大大超过附加节点,否则您只是向查询中已经可能是最大的集合添加了一小部分,这也将在第一次通过时被查询操作删除。
至于锁定,无论如何它只会影响写查询,而且只会影响写事务打开时。您可以 运行 在写入过程中进行一百万个只读查询,并且不会受到任何影响。尽管如此,第二种模型容易受到查询性能降低的影响,因为如上所述,您不能在关系属性上放置索引。