elasticsearch plugin的action
logstash提供了多达40多种的output plugin用于将处理后的数据输出到下游系统。其中最为常见的输出端自然是elasticsearch plugin
。而elasticsearch plugin
提供了3种操作类型,分别是index
,create
,update
。
对于这三种action,官方文档上的解释如下:
Value type is string
Default value is “index”
Protocol agnostic (i.e. non-http, non-java specific) configs go here Protocol agnostic methods The Elasticsearch action to perform. Valid actions are:
index
: indexes a document (an event from Logstash).delete
: deletes a document by id (An id is required for this action)create
: indexes a document, fails if a document by that id already exists in the index.update
: updates a document by id. Update has a special case where you can upsert — update a document if not already present. See the upsert option. NOTE: This does not work and is not supported in Elasticsearch 1.x. Please upgrade to ES 2.x or greater to use this feature with Logstash!
A sprintf style string to change the action based on the content of the event. The value %{[foo]} would use the foo field for the action
For more details on actions, check out the Elasticsearch bulk API documentation
这段解释没有针对不同的情况给予详细的说明,因此,以下问题让人费解:
index
与document_id
的关系index
与create
、update
的异同
而让人不知道该选择何种类型的操作。在这里,我们进行深入的解释
create
相当于:
POST _bulk
{ "create" : { "_index" : "<index>", "_id" : "<id>" } }
{ "<field>" : "<value>" }
其具体行为是:
- 必须指定
document_id
,若不指定,直接返回失败 - 如果
document_id
在elasticsearch中不存在,创建一条新的文档,使用document_id
作为该文档的_id
。 - 如果
document_id
在elasticsearch中存在,直接返回失败
只适合用在像是用户创建之后就不能再更新的场景。
index
index
是action的默认值。
相当于:
POST _bulk
{ "index" : { "_index" : "<index>", "_id" : "<id>" } }
{ "<field>" : "<value>" }
或
POST _bulk
{ "index" : { "_index" : "<index>" } }
{ "<field>" : "<value>" }
其具体行为是:
- 没有
document_id
的情况下,会将数据索引到elasticsearch当中,并且由elasticsearch生成该文档的_id
。因为没有指定document_id
,重复的数据会生成多条内容相同但_id
不同的文档。 - 有
document_id
的情况下:- 如果
document_id
在elasticsearch中不存在,创建一条新的文档,使用document_id
作为该文档的_id
。 - 如果
document_id
在elasticsearch中存在,直接更新该文档。
- 如果
注意:如果指定了document_id
,会造成写入的效率降低,因为额外增加了查询该document_id
是否存在的过程。因此,在日志分析等只写入不更新的场景,就不要尝试自己去指定id。
update
相当于:
POST _bulk
{ "update" : { "_index" : "<index>", "_id" : "<id>" } }
{ "<field>" : "<value>" }
其具体行为是:
- 必须指定
document_id
,若不指定,直接无法启动pipeline - 有
document_id
的情况下:- 如果
document_id
在elasticsearch中不存在,创建一条新的文档,使用document_id
作为该文档的_id
。doc_as_upsert
为true,使用event的值做为文档的值scripted_upsert
为true,使用script
作为文档的值- 其余情况,使用
upsert
作为文档的值
- 如果
document_id
在elasticsearch中存在,直接更新该文档。
- 如果
doc_as_upsert
input {
stdin {
add_field => {
id => "my_id"
}
}
}
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "logstash-%{+YYYY.MM.dd}"
document_id => "%{id}"
action => "update"
doc_as_upsert => true
# 不能同时设置 doc_as_upsert => ture和 upsert
# upsert => '{"message":"hello"}'
}
stdout {}
}
在标准输入输入“aaaaa”,文档内容为:
{
"_index" : "logstash-2019.09.24-000001",
"_type" : "_doc",
"_id" : "my_id",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"host" : "lexlideMacBook-Pro.local",
"id" : "my_id",
"@timestamp" : "2019-09-24T09:52:41.661Z",
"@version" : "1",
"message" : "aaaaa"
}
}
可以看到,这样的逻辑其实是和index
一样的
upsert
input {
stdin {
add_field => {
id => "my_id"
}
}
}
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "logstash-%{+YYYY.MM.dd}"
document_id => "%{id}"
action => "update"
# 不能同时设置 doc_as_upsert => ture和 upsert
#doc_as_upsert => true
upsert => '{"message":"hello"}'
}
stdout {}
}
在标准输入输入“aaaaa”,文档内容为:
{
"_index" : "logstash-2019.09.24-000001",
"_type" : "_doc",
"_id" : "my_id",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"message" : "hello"
}
}
这种情况下,可以为id不存在的文档指定自定义的数据内容
异常
如果都不设置,则会抛出异常:
[2019-09-24T17:59:26,671][WARN ][logstash.outputs.elasticsearch] Could not index event to Elasticsearch. {:status=>404, :action=>["update", {:_id=>"my_id", :_index=>"logstash", :_type=>"_doc", :routing=>nil, :retry_on_conflict=>1}, #<LogStash::Event:0x61b3501a>], :response=>{"update"=>{"_index"=>"logstash-2019.09.24-000001", "_type"=>"_doc", "_id"=>"my_id", "status"=>404, "error"=>{"type"=>"document_missing_exception", "reason"=>"[_doc][my_id]: document missing", "index_uuid"=>"XWAUuIwqTtmZMnnhnVnMkA", "shard"=>"0", "index"=>"logstash-2019.09.24-000001"}}}}
总结
总的来说,大部分情况下,我们直接使用默认的index
操作就可以了,只在一些特殊的情况下使用别的action:
- 创建指定id的文档,并且只能创建一次的场景下使用create
- 对指定id的文档进行更新,并且在文档不存在的情况下,需要使用自定义的数据内容而非原始数据内容的,使用update