【问题标题】:Neo4j indexing (with Lucene) - good way to organize node "types"?Neo4j 索引(使用 Lucene) - 组织节点“类型”的好方法?
【发布时间】:2012-04-10 09:20:39
【问题描述】:

这实际上更像是一个 Lucene 问题,但它是在 neo4j 数据库的上下文中。

我有一个数据库,它分为 50 种左右的节点类型(其他类型的数据库中的“集合”或“表”)。每个都有一个需要索引的属性子集,有些名称相同,有些则没有。

搜索时,我总是希望找到特定类型的节点,而不是跨越所有节点。

我可以看到三种组织方式:

  • 每种类型一个索引,属性自然映射到索引字段:索引'foo','id'='1234'

  • 单个全局索引,每个字段映射到一个属性名称,以区分类型或者将其作为值的一部分 ('id'='foo:1234') 或在节点返回后检查节点(我希望重复非常罕见)。

  • 单个索引,类型是字段名称的一部分:'foo.id'='1234'

一旦创建,数据库就是只读的。

其中一项在便利性、大小/缓存效率或性能方面有什么好处吗?

据我了解,对于第一个选项,neo4j 将为每种类型创建一个单独的物理索引,这似乎不是最理想的。第三,我最终发现大多数 lucene 文档只有一小部分字段,不确定这是否会影响任何内容。

【问题讨论】:

  • 为每种类型设置一个单独的索引似乎更方便也更快,因为索引的整体大小会更小。但我可能会遗漏一些东西。
  • @biziclop:实际上这对我来说似乎最不方便,因为我必须管理打开/关闭各个索引。我的理解是整体尺寸也会更大(见 jpountz 的回答)。
  • @Dimitri 好吧,显然整体大小会更大,问题是:所有类型的搜索在时间上是否均匀分布?还是某些类型的搜索频率高于其他类型?无论哪种方式,我要做的是实施我认为最方便的解决方案,看看它是否表现良好。如果是这样,你就有了赢家。
  • 我同意,我只是想找出我认为最方便的方法:)

标签: java lucene indexing neo4j


【解决方案1】:

我最近在为 Neo4j over REST 构建 ActiveRecord 连接适配器时遇到了这个问题,以用于 Rails 项目。由于ActiveRecordActiveRelation 都与SQL 语法紧密耦合,因此很难将所有内容都放入NoSQL。可能不是最好的解决方案,但我是这样解决的:

  1. 创建了一个名为model_index 的索引,它在typemodel 这两个键下索引了节点
  2. 使用type 键的索引查找目前只使用一个值model。引入这主要是为了实现SHOW TABLES SQL 功能,它可以让我获得图表中所有模型的列表。
  3. 使用model 键进行索引查找,其值对应于我系统中的不同型号名称。这主要是为了实现DESC <TABLENAME> 功能。
  4. CREATE TABLE 中创建每个表时,都会创建一个节点,其中表定义属性存储在节点属性中。
  5. 创建的节点在model_index 下使用type:modelmodel:<model-name> 进行索引。这会在“表”列表中启用新创建的模型,并且还允许通过带有model 键的索引查找直接到达模型节点。
  6. 对于根据model(在您的情况下键入)创建的每条记录,都会创建一个标记为instances 的传出边,从模型节点指向此新记录。 v[123] :=> [instances] :=> v[245] 其中 v[123] 表示模型节点,v[245] 表示 v[123] 类型的记录。
  7. 现在,如果您想获取指定类型的所有实例,您可以使用model:<model-name> 查找model_index 以到达模型节点,然后获取标记为instances 的传出边上的所有相邻节点。通过应用过滤器和其他复杂的遍历,可以进一步实现过滤查找。

上述方案防止model_index堵塞,因为它包含2x,通过一次索引查找和单级遍历实现了有效的记录查找。

尽管在您的情况下,不同类型的节点彼此不相邻,即使您想这样做,您也可以通过简单地查找带有标记为@987654344 的传入边的相邻节点来确定任意节点的类型@。此外,我正在考虑合并 SpringDataGraph 在每个实例节点上存储 __type__ 属性的模式,以避免这种相邻节点查找。

我目前正在将 AREL 翻译成 Gremlin 脚本,用于几乎所有内容。你可以在https://github.com/yournextleap/activerecord-neo4j-adapter找到我的AR适配器的源代码

希望这会有所帮助,干杯! :)

【讨论】:

  • 这听起来像我的选项“2b”:将所有内容索引在一起,并使用图表过滤类型(使用边缘检查,或者按照您的建议使用类型属性)。我认为我倾向于选项 3,以便过滤后的查找可以完全在索引中完成。
  • 过度依赖索引的一个缺点是,当您需要在 GraphML 或 GraphSON 中导出图形时,它们都不保留索引,当您在其他地方导入图形时需要重新生成索引.对图表上的所有内容进行索引可能意味着导出->导入的周转时间较长。此外,如果有一个与根节点断开连接的子图,在这种情况下丢失索引可能意味着丢失数据,并且您没有万无一失的选择来访问子图。
  • 因此我建议您让所有节点都可以从根节点遍历,以防您碰巧从之前导出的 GraphML/SON 中导入图形。
  • 是的,我的图表几乎按照您描述的方式设置:ref-->type-->instance。实际上还有一层组织 - 类型被分组为“数据集”(在实际模式中更有意义,“类型”可能是一个坏名字),但想法是一样的。这是一个非常专业的数据库,针对一些特定的搜索操作进行了优化,所以我不太担心导出/导入(无论如何它太大了)。似乎如果我可以在不访问边缘存储的情况下进行值查找,那是更好的方法。
【解决方案2】:

单个索引将小于几个小索引,因为某些数据,例如术语字典,将被共享。但是,由于术语字典查找是 O(lg(n)) 操作,因此在更大的术语字典中查找可能会慢一些。 (如果您有 50 个索引,这只需要 6 (2^6>=50) 次比较,您可能不会注意到任何差异。)

较小索引的另一个优点是操作系统缓存可能会使查询运行得更快。

代替您的选项 2 和 3,我将索引两个不同的字段 idtype 并搜索 (id:ID AND type:TYPE) 但我不知道是否可能使用 neo4j。

【讨论】:

  • 使用多个字段是可能的,但不太自然(这就是我忽略它的原因):您可以将特定于实现的查询字符串直接传递给索引引擎。我更喜欢使用更通用的index.get(field, value) API。
  • 然后我会选择最自然的第二个选项(id:TYPE+ID)
【解决方案3】:

spring-data-neo4j 使用第一种方法 - 它为每种类型创建不同的索引。所以我想这对于一般情况来说是一个不错的选择。但正如您所说,在您的特定情况下,它可能不是最理想的。我会运行一些基准来衡量性能。

顺便说一句,另外两个似乎有点做作。您可能在同一个索引中索引完全不相关的信息,这听起来不对。

【讨论】:

  • 不确定我是否发现将不相关的数据一起索引的问题 - 例如,如果这是一个关系数据库,这些属性中的大多数可能会在单个“属性值”表中建立索引。跨度>
  • 是的,你可能是对的。对于全文索引,这很奇怪,但是当您将它用作支持 neo4j 存储的索引时,听起来还不错。
猜你喜欢
  • 1970-01-01
  • 2013-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-06
  • 2015-06-20
  • 2023-03-06
  • 2015-08-20
相关资源
最近更新 更多