0

我们开发了一个文件存储解决方案,它使用弹性搜索来存储有关文件的元数据,使用其余级别的客户端 java API。

我们目前通过“from”和“size”实现分页。客户打电话给我们指定大小,也可以指定页码,我们使用页码来计算偏移量或“从”。

它们也可以通过任何可以从字符串到日期、整数等命名的字段进行排序,但我们默认为创建日期

例如,从和大小导致的问题是深度分页,例如(解决方案1)

1. /rest/metadata/search*

  1. numberOfHitsPerPage = 5000
  2. from(0),size(5000)

2. /rest/metadata/search?pageNumber=2

  1. numberOfHitsPerPage=5000
  2. from(5000),size(5000)

3. /rest/metadata/search?pageNumber=3

  1. from(10000),size(5000)
  2. From + size = 15,000, which is over the index.max_result_window of 10,000 and will fail.

我一直在研究 searchAfter 功能并实现了这一点,所以在响应中我们返回最后一个“排序”索引值,客户端可以在后续调用中使用它来避免上述问题。例子。(解决方案 2)

1. /rest/metadata/search

  1. numberOfHitsPerPage = 5000
  2. We return the 5000 hits but also include the sort value of the last hit.

2. /rest/metadata/search?lastIndexValue=1581418484000

  1. numberOfHitsPerPage=5000
  2. Under the hood we then use search_after to search from 1581418484000, return the next 5000 hits and the new last index.

3. /rest/metadata/search? lastIndexValue=1581418484011

  1. numberOfHitsPerPage=5000
  2. Under the hood we then use search_after to search from 1581418484011, return the next 5000 hits and return the new last index.
  3. There is no exception here because the filter is applied on the search request itself @ 5000 a time.

这在某些情况下可以正常工作,但也给我们带来了奇怪的结果,因为我在上面提到我们允许按任何字段排序,所以例如我们有 100 个文件存储,所有“扩展”字段设置为 txt,100 个设置为 pdf,所以用户可以一个大小设置为 10 的调用并希望按“扩展名”排序,我们将它们与最后一个“排序”索引“txt”一起返回,然后在随后的 searchAfter 字段调用中使用“txt”,但这并没有不给出任何结果。

所以看起来 searchAfter 只适用于日期等字段。

我在想我们可能可以在内部存储 lastSorted 值(索引),所以回到解决方案 1,但如果 from + size > 10,000 使用最后一个排序值,它对客户端用户隐藏。我看到的唯一问题是我们可以在哪里存储最后一个排序值,并且每个搜索的最后一个排序值需要是唯一的,我可能不希望一个巨大的数据库纯粹为此而填充所有这些排序值。

想法?

谢谢,

4

1 回答 1

1

正如您正确观察到的那样,fromandsize技术不允许您进行深度分页。search_after您可以随心所欲地进行搜索。

search_after不允许你随机“跳跃”,但你可以按顺序检索命中。对于每个后续请求,您需要提供上一个请求的最后一次命中的排序参数的值。排序值必须是唯一的。由于仅按一个值(例如 _score 或后缀)排序很可能不是唯一的,因此您需要指定第二个排序标准(理想情况下是唯一值)以使上一个请求的最后一次命中唯一可识别。

您可以_id为此使用 -field,但这不是很有效,因为 Elasticsearch 不会为_id-field 编写 doc-values 数据结构。因此,为此目的使用任何其他类型keyword的唯一字段(例如 uri)。如果您没有每个文档具有唯一值的此类字段,只需将_id-field 的值复制到 type 的新字段中keyword。例如,您可以在摄取管道中这样做。

于 2020-02-28T03:28:30.447 回答