如何处理Elasticsearch中多个列表分开的项目?

时间:2014-08-06 12:53:10

标签: database-design elasticsearch

我正在开发一个系统,其中由Elasticsearch索引的文档可以显示在多个列表中。

列表名称:

  • LIST1
  • 列表2
  • 项目list3
  • LIST4

正在编入索引的文件:

{ title : 'Title' }

我每秒都会收到这样的文件。文档可以出现在多个列表中(某些业务逻辑也确定文档所属的列表)。我目前的方法是将列表数据附加到文档中,因此文档看起来像这样:

{ title : 'Title', lists : ['LIST2', 'LIST4'] }

这种方法使我能够通过查询列表数组包含LIST2的文档来列出LIST2中的所有文档。它还使我能够在LIST2中搜索文档。

客户认为LISTS需要合并的新要求。这意味着用户可以将LIST3合并到LIST2中,这实际上意味着:

  • 更新所有附有LIST3列表的文档,并将其更改为LIST2
  • 删除LIST2。

我的问题:在Elasticsearch中有更好的方法来解决这个问题吗?这种方法的可扩展性如何?我认为的问题可能是:

  1. 未来很多LISTS(可能是一百万)。帖子所属的LISTS越多,文档列表数组就越大。 Elasticsearch在这个部门的表现如何?
  2. 合并列表似乎是一项非常昂贵的操作。

2 个答案:

答案 0 :(得分:0)

您可以将列表对象编入索引作为自己的类型,其中列表本身例如只包含属于该列表的文档ID列表。然后,当您需要根据文档所属的列表查询文档时,可以使用术语查找过滤器(排序的“连接”) - http://www.elasticsearch.org/blog/terms-filter-lookup/

没有必要进行两个单独的查询 - 在弹性搜索中内置术语查找,以完成那种需要通过不同文档类型检查成员资格的查询(即“查找” - 完全类似于连接或“在哪里”)。你不仅不需要做两个单独的查询,而且还有弹性搜索方面的缓存,这使得它非常有效。

这样可以更轻松地管理列表成员资格,因为您只需要更新一个文档(列表文档)来合并列表,但在根据列表成员资格搜索特定文档时,您仍然可以根据需要查询信息。

答案 1 :(得分:0)

我认为答案实际上取决于你愿意放弃的东西以换取更大的灵活性。您的解决方案在查询时肯定具有优势,但您可能不希望花费这么多资源重新索引所有更改?如果是这样,其他解决方案建议维护一个单独的类型,以反向存储关系,其中索引是基于列表的,并且您可以更轻松地更新列表。

这样做的一个缺陷可能是在搜索时失去灵活性。如果您需要列表“A”中每个文档的详细信息,则必须查询“列表”类型,然后针对该列表的所有docID运行另一个查询。可能有插件允许您加入查询(使用此特定架构),但您必须进行一些研究。

此外,如果您的列表最终变得非常大,这可能会出现问题(想象一下将列表文档索引为一百万个标题!)。但是,如果您必须使用正确的listID列表更新一百万个文档,那么您可能会在解决方案中遇到类似的问题。这取决于您对数据集最终变得多大的期望,以及在应用解决方案时哪些功能对您最重要。

话虽如此,另一个可能的解决方案可能是使用父/子文件。父母将是列表,孩子将是文件。这将保持查询灵活性不变,因为您可以查询父文件中的歧视器的子文档。但合并将如何运作?如上所述,所有内容都有成本,在这种情况下,我会设计列表,使其具有2个ID字段。一个人将保留“先前”列表名称,另一个将是可搜索别名。

例如,您有列表'A'和列表'B'。基本文档结构类似于list:{alias:'A',name:'A'},同样适用于B.有一天,你想将A合并到B.你要做的是,更新列表文档A,并将'A'的别名设置为'B'。在搜索时,搜索文档时,您将查询类似“where parent.alias = [list_name]”的内容。此外,出于审计目的,您可以将刚被替换的列表名称(“A”)排队到上一个列表名称字段中。 (这部分完全是可选的......直到你想怎么做)

不幸的是,这意味着您可以拥有多个具有相同别名的列表类型(并且还会占用更多内存),但这可以防止大量重新编制索引(在任何规模上),并且您在搜索时获得较小的性能影响支持父/子关系(文档将在搜索时共享相同的分片,但不与嵌套文档共享相同的分段)。