2012-03-26 113 views
5

这实际上更多的是Lucene的问题,但它是在neo4j数据库的上下文中。Neo4j索引(与Lucene) - 组织节点“类型”的好方法?

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

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

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

每种类型
  • 一个指标,性能自然映射到索引字段:指数“富”,'id'='1234'

  • 一个单一的全局索引,每个字段映射到一个属性名称,以区分该类型或者将其包含为值的一部分('id'='foo:1234'),或者在返回节点后检查它们(我预计副本非常罕见)。

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

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

在便利性,大小/缓存效率或性能方面,对其中之一是否有任何好处?

据我所知,对于第一个选项,neo4j会为每种类型创建一个单独的物理索引,这看起来并不理想。第三,我最终lucene文档只有一小部分的字段,不知道这是否影响任何东西。

+0

为每种类型分别编制索引似乎更方便也更快捷,因为索引的整体大小会更小。但我可能会错过一些东西。 – biziclop 2012-03-26 21:31:54

+0

@biziclop:它实际上对我来说似乎是最不方便的,因为我必须管理打开/关闭单个索引。我的理解是整体规模也会更大(请参阅jpountz的答案)。 – Dmitri 2012-03-26 21:50:37

+0

@Dimitri好吧,显然整体规模会更大,问题是:搜索所有类型的时间均匀分布?或者某些类型的搜索次数比其他类型的次数多?无论哪种方式,我会做的是实施我觉得最方便的解决方案,看看它是否表现良好。如果是这样,你有你的赢家。 – biziclop 2012-03-26 21:54:49

回答

1

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

较小索引的另一个优点是OS高速缓存很可能会使查询运行得更快。

而不是你的选择2和3,我就指数两个不同的领域idtype和搜索(id:ID和type:TYPE),但我不知道是否有可能与Neo4j的。

+0

使用多个字段是可能的,但有点不太自然(这就是为什么我将它遗留下来):您可以传递特定于实现的查询字符串直接到索引引擎。我宁愿使用更通用的'index.get(field,value)'API。 – Dmitri 2012-03-26 22:00:42

+0

然后我会选择最自然的第二个选项(id:TYPE + ID) – jpountz 2012-03-26 22:23:40

1

spring-data-neo4j正在使用第一种方法 - 它为每种类型创建一个不同的索引。所以我想这对于一般场景来说是个不错的选择。但就你的具体情况而言,它可能不是最理想的,就像你说的那样。我会运行一些基准来衡量性能。

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

+0

不确定我看到问题与索引不相关的数据在一起 - 如果这是一个关系数据库,例如,大多数这些属性可能会被索引在一个'属性值'表中。 – Dmitri 2012-03-26 21:54:57

+0

是的,你可能是对的。对于全文索引来说这很奇怪,但是因为您将它用作支持neo4j存储的索引,听起来并不那么糟糕。 – Bozho 2012-03-26 21:56:15

2

最近,当我在通过REST构建Neo4j的ActiveRecord连接适配器时,我遇到了这个问题,将用于Rails项目。由于ActiveRecordActiveRelation都与SQL语法紧密结合,因此很难将所有内容都纳入NoSQL。可能不是最好的解决办法,但这里是我如何解决它:

  1. 创建了一个名为model_index的指数,指数下两个键,typemodel
  2. 索引查找与type字,目前只用一个价值model发生节点。这主要是为了实现一个SHOW TABLES SQL功能,它可以让我看到图中所有模型的列表。
  3. 使用model键进行索引查找,其中的值与我系统中不同型号名称对应。这主要是为了实现DESC <TABLENAME>的功能。
  4. 随着每个表的创建与CREATE TABLE一样,创建一个节点时将表定义属性存储在节点属性中。
  5. 创建的节点在model_indextype: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,并通过一次索引查找和单级遍历实现有效的记录查找。

虽然在你的情况下,不同类型的节点彼此不相邻,即使你想这样做,你可以通过简单地查找它的相邻节点来确定任意节点的类型,标记为instances 。此外,我正在考虑合并SpringDataGraph在每个实例节点上存储__type__属性的模式,以避免此相邻节点查找。

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

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

+0

这听起来像我的选择“2b”:将所有内容一起索引,并使用图来过滤类型(或者使用边缘检查,或者如您所建议的那样使用类型属性)。我想我倾向于选项3,以便过滤查找可以完全在索引中完成。 – Dmitri 2012-03-27 11:50:38

+0

过度依赖索引的一个缺点是,当您需要导出图形时,无论是在GraphML还是GraphSON中,都没有保留索引,您需要在其他位置导入图形时重新生成索引。为图表上的所有内容建立索引可能意味着导出 - >导入的周转时间很长。另外,如果有一个与根节点断开连接的子图,那么在这种情况下丢失索引可能意味着数据丢失,并且没有一个到达子图的简单选项。 – rhetonik 2012-03-27 14:37:43

+0

因此,我建议您将所有节点都从根节点穿过,以防偶然从先前导出的GraphML/SON导入图形。 – rhetonik 2012-03-27 14:39:25