ES批量操作
一、引言与 mget 可以使我们一次取回多个文档同样的方式, bulk API 允许在单个步骤中进行多次 create 、 index 、 update 或 delete 请求。 如果你需要索引一个数据流比如日志事件,它可以排队和索引数百或数千批次。在单个API调用中执行多个批量操作。 这样可以减少开销,并可以大大提高索引速度。二、bulk API2.1、语法POST _bulk{ "...
一、引言
与 mget
可以使我们一次取回多个文档同样的方式, bulk API
允许在单个步骤中进行多次 create
、 index
、 update
或 delete
请求。 如果你需要索引一个数据流比如日志事件,它可以排队和索引数百或数千批次。
在单个API调用中执行多个批量操作。 这样可以减少开销,并可以大大提高索引速度。
二、bulk API
2.1、语法
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
Request:
POST /_bulk
POST /<index>/_bulk
2.2、描述
提供一种在单个请求中执行多个索引,创建,删除和更新操作的方法。
在请求正文中使用换行符分隔(\n)的JSON(NDJSON)结构指定操作,
这种格式类似一个有效的单行 JSON 文档流 ,它通过换行符(\n)连接到一起。注意两个要点:
- 每行一定要以换行符(\n)结尾, 包括最后一行 。这些换行符被用作一个标记,可以有效分隔行。
- 这些行不能包含未转义的换行符,因为他们将会对解析造成干扰。这意味着这个 JSON 不 能使用 pretty 参数打印。
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
...
action/metadata
行指定 哪一个文档 做 什么操作 。
action
必须是以下选项之一:
create
如果文档不存在,那么就创建它。index
创建一个新文档或者替换一个现有的文档。update
部分更新一个文档。delete
删除一个文档。
metadata
应该指定被索引、创建、更新或者删除的文档的 _index
、 _type
(7.x废弃) 和 _id
。
例如,一个 delete
请求看起来是这样的:
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
request body
行由文档的 _source
本身组成—文档包含的字段和值。
它是 index
和 create
操作所必需的,这是有道理的:你必须提供文档以索引。
它也是 update
操作所必需的,并且应该包含你传递给 update API
的相同请求体: doc 、 upsert 、 script
等等。删除操作不需要 request body
行。
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "My first blog post" }
如果不指定 _id
,将会自动生成一个 ID :
{ "index": { "_index": "website", "_type": "blog" }}
{ "title": "My second blog post" }
一个完整的 bulk 请求 有以下形式:
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
- 请注意 delete 动作不能有请求体,它后面跟着的是另外一个操作。
- 谨记最后一个换行符不要落下。
响应如下:
{
"took": 30,
"errors": false,
"items": [
{
"index": {
"_index": "test",
"_type": "_doc",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 201,
"_seq_no" : 0,
"_primary_term": 1
}
},
{
"delete": {
"_index": "test",
"_type": "_doc",
"_id": "2",
"_version": 1,
"result": "not_found",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 404,
"_seq_no" : 1,
"_primary_term" : 2
}
},
{
"create": {
"_index": "test",
"_type": "_doc",
"_id": "3",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 201,
"_seq_no" : 2,
"_primary_term" : 3
}
},
{
"update": {
"_index": "test",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 200,
"_seq_no" : 3,
"_primary_term" : 4
}
}
]
}
注意:
每个子请求都是独立执行,因此某个子请求的失败不会对其他子请求的成功与否造成影响。
2.3、批量更新
使用update
动作时,retry_on_conflict
可以用作动作本身(而不是额外的有效负载行)中的字段在版本冲突的情况下应重试更新的次数。
更新操作有效负载支持以下选项:
doc(部分文档),upsert,doc_as_upsert,脚本,params(用于脚本),lang(用于脚本)和_source。
更新动作示例:
POST _bulk
{ "update" : {"_id" : "1", "_index" : "index1", "retry_on_conflict" : 3} }
{ "doc" : {"field" : "value"} }
{ "update" : { "_id" : "0", "_index" : "index1", "retry_on_conflict" : 3} }
{ "script" : { "source": "ctx._source.counter += params.param1", "lang" : "painless", "params" : {"param1" : 1}}, "upsert" : {"counter" : 1}}
{ "update" : {"_id" : "2", "_index" : "index1", "retry_on_conflict" : 3} }
{ "doc" : {"field" : "value"}, "doc_as_upsert" : true }
{ "update" : {"_id" : "3", "_index" : "index1", "_source" : true} }
{ "doc" : {"field" : "value"} }
{ "update" : {"_id" : "4", "_index" : "index1"} }
{ "doc" : {"field" : "value"}, "_source": true}
三、不要重复指定Index和Type
也许你正在批量索引日志数据到相同的 index 和 type 中。 但为每一个文档指定相同的元数据是一种浪费。相反,可以像 mget API 一样,在 bulk 请求的 URL 中接收默认的 /_index
或者 /_index/_type
POST /website/_bulk
{ "index": { "_type": "log" }}
{ "event": "User logged in" }
POST /website/log/_bulk
{ "index": {}}
{ "event": "User logged in" }
{ "index": { "_type": "blog" }}
{ "title": "Overriding the default type" }
四、批量请求的大小
整个批量请求都需要由接收到请求的节点加载到内存中,因此该请求越大,其他请求所能获得的内存就越少。 批量请求的大小有一个最佳值,大于这个值,性能将不再提升,甚至会下降。 但是最佳值不是一个固定的值。它完全取决于硬件、文档的大小和复杂度、索引和搜索的负载的整体情况。
幸运的是,很容易找到这个 最佳点 :通过批量索引典型文档,并不断增加批量大小进行尝试。 当性能开始下降,那么你的批量大小就太大了。一个好的办法是开始时将 1,000 到 5,000 个文档作为一个批次, 如果你的文档非常大,那么就减少批量的文档个数。
密切关注你的批量请求的物理大小往往非常有用,一千个 1KB 的文档是完全不同于一千个 1MB 文档所占的物理大小。 一个好的批量大小在开始处理后所占用的物理大小约为 5-15 MB。
更多推荐
所有评论(0)