如何在elasticsearch里面使用深度分页功能

前面的文章提到过es默认的from+size的分页方式返回的结果数据集不能超过1万点,超过之后返回的数据越多性能就越低。


这是因为es要计算相似度排名,需要排序整个整个结果集,假设我们有一个index它有5个shard,现在要读取1000到1010之间的这10条数据,es内部会在每个shard上读取1010条数据,然后返回给计算节点,这里有朋友可能问为啥不是10条数据而是1010条呢?这是因为某个shard上的10条数据,可能还没有另一个shard上top10之后的数据相似度高,所以必须全部返回,然后在计算节点上,重新对5050条数据进行全局排序,最后在选取top 10出来,这里面排序是非常耗时的,所以这个数量其实是指数级增长的,到后面分页数量越多性能就越下降的厉害,而且大量的数据排序会占用jvm的内存,很有可能就OOM了,这也是为什么es默认不允许读取超过1万条数据的原因。


那么问题来了,我就是想要深度的分页数据应该怎么办? es里面提供了两种方式来读取深度分页的数据:


(1)离线的读取深度分页数据的Scroll方法


(2)能够用于实时和高并发场景的searchAfter方法(5.x之后)


Scroll方式在前面的文章提到过,它通过一次查询请求后维护一个索引快照的search context,然后每次再去批量的读取数据,效率比较高。在5.x之后,还可以通过slice分片来实现并行导出。

它的缺点就是维护一个search context需要占用很多资源,而且在快照建立之后数据变化如删除和更新操作是不能被感知到的,所以不能够用于实时和高并发的场景。


searchAfter的方式通过维护一个实时游标来避免scroll的缺点,它可以用于实时请求和高并发场景。


它的缺点是不能够随机跳转分页,只能是一页一页的向后翻,并且需要至少指定一个唯一不重复字段来排序。


此外还有一个与scorll的不同之处是searchAfter的读取数据的顺序会受索引的更新和删除影响而scroll不会,因为scroll读取的是不可变的快照。


下面来看下如何使用searchAfter:

我们先查询一页数据:

````js
GET twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "elasticsearch"
}
},
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}
````


注意,上面用了两个字段来排序,第一个是业务字段可能不唯一,但是第二个id字段一定唯一不重复的。只有这样才能确保searchAfter的翻页顺序读取。

另外searchAfter的from字段一定要设置成0,不然会有问题。


第一个请求发出之后,我们需要获取第一个请求里面最后一条的数据的date和id,然后把这个信息传送到下一个批次,依次类推直到把所有的数据处理完。

如下第二个请求的查询体:

````
GET twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "elasticsearch"
}
},
"search_after": [1463538857, "654323"],
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}
````



总结:

本篇文章介绍了如何在es里面使用深度分页的功能,并对比了scroll和searchAfter的优缺点及不同之处,了解这些知识之后,我们就可以在适合的场景下正确的选择最优的处理方式。

[b][color=green][size=large] 有什么问题可以扫码关注微信公众号:我是攻城师(woshigcs),在后台留言咨询。 技术债不能欠,健康债更不能欠, 求道之路,与君同行。 [/size][/color][/b] [img]http://dl2.iteye.com/upload/attachment/0104/9948/3214000f-5633-3c17-a3d7-83ebda9aebff.jpg[/img]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Elasticsearch使用深度分页功能需要注意以下几点: 1. 尽量避免使用深度分页功能,因为它会增加网络和计算开销,可能导致性能问题。 2. 深度分页功能是通过设置 from 和 size 参数来实现的。from 参数表示从哪个位置开始查询,size 参数表示每页返回的文档数量。 3. Elasticsearch 默认最多只能返回 10000 条记录,如果需要查询更多的记录,需要设置 index.max_result_window 参数。但是设置太大会占用过多的内存,影响性能。 下面是一个 Java 实现 Elasticsearch 分页查询的示例代码: ``` import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.client.Client; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; public class ESQuery { private Client client; public ESQuery(Client client) { this.client = client; } public void search(String index, String type, int from, int size) { SearchResponse response = client.prepareSearch(index) .setTypes(type) .setQuery(QueryBuilders.matchAllQuery()) .addSort(SortBuilders.fieldSort("_id").order(SortOrder.DESC)) .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setFrom(from) .setSize(size) .execute() .actionGet(); SearchHits hits = response.getHits(); for (SearchHit hit : hits) { System.out.println(hit.getSourceAsString()); } } } ``` 调用示例: ``` ESQuery esQuery = new ESQuery(client); esQuery.search("my_index", "my_type", 0, 10); // 查询第一页,每页10条记录 esQuery.search("my_index", "my_type", 10, 10); // 查询第二页,每页10条记录,从第11条记录开始 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值