源数据频繁变化时如何处理分页
How to handle pagination when the source data changes frequently
具体来说,我正在使用 Elasticsearch 进行分页,但这个问题可能适用于任何数据库。
Elasticsearch 通过方便的 from
和 to
参数为 paginate search results 提供方法。
所以我运行查询get me the most recent data from result 1 to 10
效果很好。
用户点击"next page"查询为:
get me the most recent data from result 11 to 20
问题是在两次查询之间,2条新记录被添加到后备数据库,这意味着分页结果会重叠(第一页的最后2条在第二页)。
避免这种情况的最佳解决方案是什么?现在,我正在向查询添加一个过滤器,告诉它只包含比上一个查询的最后一个结果晚的结果。但这似乎很老套。
为此您需要使用扫描 API。扫描和滚动 API 让您进行时间点搜索和分页。
扫描 API -
如果您已经在为相关时间戳编制索引,那么过滤器是个不错的选择。您必须在客户端跟踪该时间戳才能正确准备您的查询。您还必须知道何时摆脱它。但这些都不是无法克服的问题。
Scroll API 是一个可靠的选择,因为它在 Elasticsearch 端有效地及时快照。 Scroll API 的目的是为深度分页提供稳定的搜索查询,它必须处理您遇到的确切变化问题。
您通过提供查询和 scroll
参数来开始 Scrolling Search,Elasticsearch return 是 scroll_id
。然后,您向 /_search/scroll
发出请求并提供该 ID,每个请求 return 一页结果和一个新的 scroll_id
用于下一个请求。
(请注意,您不需要此处的scan
搜索类型。它用于整体提取文档, 并且不应用任何排序。)
与过滤相比,您仍然需要跟踪一个值:下一页结果的 scroll_id
。这是否比跟踪时间戳更容易取决于您的应用。
还有其他潜在的缺点需要考虑。 Elasticsearch 在集群中的单个节点上保存您的搜索上下文。可以想象,这些可能会在您的集群中累积,具体取决于您对滚动搜索的依赖程度。您需要在那里测试性能影响。如果我没记错的话,滚动搜索也不会在节点故障或重启后持续存在。
Scroll API 的 ES 文档提供了有关上述所有内容的详细信息。
底线:按时间戳过滤实际上是一个不错的选择。 Scroll API 是另一个有效选项,专为类似用例而设计,但并非没有缺点。
意识到这有点过时了,但是在 ElasticSearch 6.3 中,请求主体现在有 search_after
功能,它允许游标类型分页:
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-search-after.html
It is very similar to the scroll API but unlike it, the search_after parameter is stateless, it is always resolved against the latest version of the searcher.
具体来说,我正在使用 Elasticsearch 进行分页,但这个问题可能适用于任何数据库。
Elasticsearch 通过方便的 from
和 to
参数为 paginate search results 提供方法。
所以我运行查询get me the most recent data from result 1 to 10
效果很好。
用户点击"next page"查询为:
get me the most recent data from result 11 to 20
问题是在两次查询之间,2条新记录被添加到后备数据库,这意味着分页结果会重叠(第一页的最后2条在第二页)。
避免这种情况的最佳解决方案是什么?现在,我正在向查询添加一个过滤器,告诉它只包含比上一个查询的最后一个结果晚的结果。但这似乎很老套。
为此您需要使用扫描 API。扫描和滚动 API 让您进行时间点搜索和分页。 扫描 API -
如果您已经在为相关时间戳编制索引,那么过滤器是个不错的选择。您必须在客户端跟踪该时间戳才能正确准备您的查询。您还必须知道何时摆脱它。但这些都不是无法克服的问题。
Scroll API 是一个可靠的选择,因为它在 Elasticsearch 端有效地及时快照。 Scroll API 的目的是为深度分页提供稳定的搜索查询,它必须处理您遇到的确切变化问题。
您通过提供查询和 scroll
参数来开始 Scrolling Search,Elasticsearch return 是 scroll_id
。然后,您向 /_search/scroll
发出请求并提供该 ID,每个请求 return 一页结果和一个新的 scroll_id
用于下一个请求。
(请注意,您不需要此处的scan
搜索类型。它用于整体提取文档, 并且不应用任何排序。)
与过滤相比,您仍然需要跟踪一个值:下一页结果的 scroll_id
。这是否比跟踪时间戳更容易取决于您的应用。
还有其他潜在的缺点需要考虑。 Elasticsearch 在集群中的单个节点上保存您的搜索上下文。可以想象,这些可能会在您的集群中累积,具体取决于您对滚动搜索的依赖程度。您需要在那里测试性能影响。如果我没记错的话,滚动搜索也不会在节点故障或重启后持续存在。
Scroll API 的 ES 文档提供了有关上述所有内容的详细信息。
底线:按时间戳过滤实际上是一个不错的选择。 Scroll API 是另一个有效选项,专为类似用例而设计,但并非没有缺点。
意识到这有点过时了,但是在 ElasticSearch 6.3 中,请求主体现在有 search_after
功能,它允许游标类型分页:
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-search-after.html
It is very similar to the scroll API but unlike it, the search_after parameter is stateless, it is always resolved against the latest version of the searcher.