elasticsearch中的 slice (切片)详解
Paginate search results | Elasticsearch Guide [8.1] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/8.1/paginate-search-results.html#slice-scroll先敬上官网链接。一手资料永远都是官网!我先说一下为什么会关注这块内容:我有需
Paginate search results | Elasticsearch Guide [8.1] | Elastichttps://www.elastic.co/guide/en/elasticsearch/reference/8.1/paginate-search-results.html#slice-scroll 先敬上官网链接。一手资料永远都是官网!
我先说一下为什么会关注这块内容:我有需求需要快速导出集群中的数据,而数据又非常多。将近20亿!
单线程利用 scroll导出也比较慢。然后我在业务上去拆分任务,虽然能完成,但是非常麻烦。然后又研究了一下网上的帖子,看到有人说滚动查询还可以利用 slice来提升速度。它的快原理其实就是利用多线程。
接下来再分析一下slice的原理,以及一些优化点!
Slice使用方式以及原理
它实际上会将一个任务拆分成多个任务。
api
GET /my-index-000001/_search?scroll=1m
{
"slice": {
"id": 0,
"max": 2
},
"query": {
"match": {
"message": "foo"
}
}
}
GET /my-index-000001/_search?scroll=1m
{
"slice": {
"id": 1,
"max": 2
},
"query": {
"match": {
"message": "foo"
}
}
}
解释一下:实际上 max就是任务拆分的个数。id就是拆分后对应的任务id,下标从0开始的!
工作原理就是
拆分在分片上进行。然后数据再切分。切分公式就是:slice(doc) = floorMod(hashCode(doc._id), max)).
解释一下这个公式:其实就是 文档id的hash值去模上最大任务数,得到的余数就是对应拆分的任务。注意这里的任务id是可以换成其它字段,但是有个条件是只能是数字类型。
假如你有10亿数据,你拆分成5个任务。应该是一个任务2亿。最后五个任务执行完,应该是10亿数据的全集!
The result from the first request returned documents that belong to the first slice (id: 0) and the result from the second request returned documents that belong to the second slice. Since the maximum number of slices is set to 2 the union of the results of the two requests is equivalent to the results of a scroll query without slicing. By default the splitting is done first on the shards, then locally on each shard using the
_id
field. The local splitting follows the formulaslice(doc) = floorMod(hashCode(doc._id), max))
.
注意点
- 想要获取极限的速度,要知道这是有成本的。在执行这个的时候,要想清楚,是否继续要对外提供稳定良好服务。根据这个前提,再去适当的调参数到极限能力!
- 理论值:任务拆分数要小于等于分片数。建议是分片的倍数。假如索引有200个分片,是不是可以搞200个任务。那肯定不能,这是非常花资源的,假如你的机器资源没有那么多,又想稳定对外提供服务,不建议这么搞,我的建议是最大不要超过CPU的核心数。
- slice 在 search + scroll 的时候可以用,在聚类结果导出的时候也可以用。
- 注意用完的scroll应该及时删除。es默认保留500个滚动任务id。多了就不能再使用了!
- 注意scroll状态保留的时间。如果你后续接到数据以后的处理时间比较长,或者查询本身时间花费也长,你应该合理的设置一个长的状态保留时间。
GET /_search?scroll=1m
{
"sort": [
"_doc"
]
}
- 假如你的结果不考虑结果顺序性,利用默认的数据在分片中的顺序是一个不错的选择,就是上述的API。
- 注意在滚动查询的过程中。因为是对段保留了快照。此时新的数据进来,是无法被看到的。另外在滚动查询过程中,会阻碍段合并,因为执行中的任务保留着这些旧段的信息!
实战
官网java客户端,并没有提供 slice的demo,明天我提供一份出来!先测试一下。
更多推荐
所有评论(0)