如何使用logstash更新已有的elasticsearch记录
来源:互联网 发布:顶点软件(603383)股吧 编辑:程序博客网 时间:2024/06/05 01:54
如何使用logstash更新已有的elasticsearch记录
常使用elasticsearch的童鞋,一定会遇到这种情况:我们需要修改已存储在ES中的数据,无论是数据内容或者是数据结构,来满足我们不断变化的需求。当我们需要修改数据的时,如果自己撸码一条一条的改动数据,不免有点低级,特别在大量的数据都需要修改的时候,这根本就是无法完成的任务。此时,势必要求助于工具。不知道Logstash是不是在其他领域也比较普及,但在ELK架构的日志分析系统里面,logstash是我们的ETL模块,对数据的提取,转换,丰富都是由它来完成的。它可以从其他数据源提取原始数据,经过转换,再把数据按照我们的要求输入到ES当中。也可以从ES里面提取已有的数据,进行再处理之后,再重新输出到ES当中。这样,我们就可以轻松的完成对已有数据的更新,美滋滋!当然,如果所有的原始数据还在,你也可以不用这么高级的玩法,直接把index删掉,把原始数据按照新的需求结构化后,重新导入ES也是可以的!但如果你还有点追求,接着往下看,顺便给我点个赞,我们来介绍怎么玩。
玩法简介
- 观察你的ES数据,确定需要修改的项,比如:
- @timestamp和你日志中的timestamp没有对应上
- 数据中的url需要拆分成更细verb, request, host, device...等项
- 提取一些样本数据到本地的ES上
- 在logstash里面配置elasticsearch input plugin,读取本地ES的样本数据,并使用filter plugin重构你的数据
- 反复修改,直到logstash能够正确处理所有样本
- 将logstash配置为读取服务器的需要修改的数据(需要正确的query),并重构你的数据。
以上,就是一个比较直观简短的介绍,很简单。。。
软件要求
其实要求只有一个,那就是把你logstash的elasticSearch input plugin升级到5.3.*版本以上,我在5.2.2版本上就遇到了下面的bug:
Error: [400] {"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"Failed to parse request body"}],"type":"illegal_argument_exception","reason":"Failed to parse request body","caused_by":{"type":"json_parse_exception","reason":"Unrecognized token 'DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAgJFmlmNnYtNlZkU1B5TmlhRjU4QkJLZkEAAAAAAAAIChZpZjZ2LTZWZFNQeU5pYUY1OEJCS2ZBAAAAAAAACAsWaWY2di02VmRTUHlOaWFGNThCQktmQQAAAAAAAAgMFmlmNnYtNlZkU1B5TmlhRjU4QkJLZkEAAAAAAAAIDRZpZjZ2LTZWZFNQeU5pYUY1OEJCS2ZB': was expecting ('true', 'false' or 'null')\n at [Source: org.elasticsearch.transport.netty4.ByteBufStreamInput@7b31ce02; line: 1, column: 457]"}},"status":400}
这个问题出现在使用logstash从ES读取数据时。当出现这个问题时,logstash会一直从ES上不停的query数据,药不能停。 当然,我的整个集群都是使用的最新版本的(5.5.*)的ES,Kibana, Logstash,我不保证用低版本也能完成同样的事情。
配置logstash
input{ # 在写入样本时,可以先使用stdin plugin往ES里面写入样本数据 # stdin{ # type => "test" # }# 使用以下的配置,从ES中读入数据 elasticsearch { hosts => "localhost:9200" index => "test-*" query => '{ "query": { "query_string": { "tags": "_grokparsefailure" } } }' size => 500 scroll => "5m" docinfo => true codec => json }}# 以下filter只是一个例子,不用在意filter { mutate{ remove_tag => ["_grokparsefailure"] } grok { patterns_dir => ["./patterns"] match => { "message" => "%{PLATFORM_SYSLOG}" } } date { match => ["timestamp", "MMM dd HH:mm:ss", "MMM dd HH:mm:ss", "ISO8601"] } if "_grokparsefailure" not in [tags] { mutate{ remove_field => ["message"] } }}output{ # stdout{ # codec => json # } # 在我的实践中,我会先把ES里面的原记录删掉,再创建一条新的记录,当然,也可以直接update elasticsearch { hosts => ["localhost:9200"] # action => "update" action => "delete" document_type => "%{[@metadata][_type]}" document_id => "%{[@metadata][_id]}" index => "%{[@metadata][_index]}" user => "elastic" password => "changeme" } elasticsearch{ hosts => ["localhost:9200"] #index => "test-%{+YYYY.MM.dd}" index => "%{[@metadata][_index]}" user => "elastic" password => "changeme" } }
图文步骤
问题document
可以看到,这条记录没有被正确的解析,和这条记录类似的其他记录都有这样的问题,我们需要对它重新解析输入样本数据
把这条无法解析的数据,放到本地的ES上做测试。将logstash的input配置成stdin, 然后导入。
配置
input{ stdin{ type => "test" }}output{ elasticsearch{ hosts => ["localhost:9200"] index => "test-%{+YYYY.MM.dd}" user => "elastic" password => "changeme" } }
导入
启动logstash,输入无法解析的数据
[2017-09-15T17:13:20,609][INFO ][logstash.pipeline ] Starting pipeline {"id"=>"main", "pipeline.workers"=>8, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>5, "pipeline.max_inflight"=>1000}[2017-09-15T17:13:20,620][INFO ][logstash.pipeline ] Pipeline main startedThe stdin plugin is now waiting for input:[2017-09-15T17:13:20,662][INFO ][logstash.agent ] Successfully started Logstash API endpoint {:port=>9600},Sep 15 03:29:02,HostName=sz190034,IP=10.60.22.117,Tag=run-parts(/etc/cron.daily)[19239,ProgramName=run-parts(,Procid=,Facility=cron,Sev=notice,AppName=run-parts(,Msg= finished prelink
可以看到,ES里面已经有了这条数据:
从ES中读入数据,并现场修改
继续在本地环境上,验证我们的修改,使用之前提到的logstash配置,从ES上读入数据,用filter对数据内容进行更新,然后再放回ES。这里需要注意的是,我们既可以在原有的记录上直接修改,也可以在将原记录删除,把新的记录填上。对ES已有的记录进行更新或删除,请记得下面三项是必须配置:
index => "%{[@metadata][_index]}" document_type => "%{[@metadata][_type]}" document_id => "%{[@metadata][_id]}"
"%{[@metadata][_index]}"是原记录所在的索引,"%{[@metadata][_type]}"是原记录的类型,"%{[@metadata][_id]}"是原记录的id。这三条缺一不可,特别是索引(其他两项是必填,不填logstash的插件会报错),因为它不会报错,但是update会不成功。 使用如下的配置重启logstash:
elasticsearch { hosts => "localhost:9200" index => "test-*" query => '{ "query": { "query_string": { "query": "*" } } }' size => 500 scroll => "5m" docinfo => true codec => json }}filter { mutate{ # remove_field => ["@timestamp"] remove_tag => ["_grokparsefailure"] } grok { patterns_dir => ["./patterns"] match => { "message" => "%{PLATFORM_SYSLOG}" } } date { match => ["timestamp", "MMM dd HH:mm:ss", "MMM dd HH:mm:ss", "ISO8601"] } if "_grokparsefailure" not in [tags] { mutate{ remove_field => ["message"] } }}output{ elasticsearch { hosts => ["localhost:9200"] action => "delete" document_type => "%{[@metadata][_type]}" document_id => "%{[@metadata][_id]}" index => "%{[@metadata][_index]}" user => "elastic" password => "changeme" } elasticsearch{ hosts => ["localhost:9200"] index => "test-%{+YYYY.MM.dd}" user => "elastic" password => "changeme" } }
它就会把本地ES上的数据取下来,丢给filter,处理之后,再丢回给ES。结果如下:
数据被正确解析,并且时间戳被更新在ES的服务器上更新
在本地验证无误之后,就可以将logstash的elasticsearch input plugin和output plugin的地址改为服务器的地址,并更新一下query的规则,选出需要更新的记录,比如:
elasticsearch { hosts => "10.60.47.168:9200" index => "platform-*" query => '{ "query": { "term": { "tags": "_grokparsefailure" } } }' size => 500 scroll => "5m" docinfo => true codec => json }
再进行数据的更新。
小结
我们可以看到,通过logstash的两个plugin:
- elasticsearch input plugin
- elasticsearch output plugin
我们可以方便的选出我们希望更新的es的数据,在进行修改之后,再放回es当中。整个过程很简单,但在实际的操作过程中,已经要做足够的测试,争取只对数据做一遍更新。 像上面的例子,如果第一遍过后,发现还要动规则,你就要注意,有些新的field已经被logstash添加到es当中,有一些老的field已经被删除。这时你就不能再用第一遍时的filter了,你的整个filter需要重写,并且在原始数据已经被改过的情况下,还会出现不可逆的数据丢失。所以,要慎行!
- 如何使用logstash更新已有的elasticsearch记录
- mysql:使用已有的记录更新另一条数据
- 如何使用已有的主题
- Android如何使用已有的so库
- logstash-output elasticsearch插件使用
- 如何在Android应用中使用已有的Sqlite数据库
- 如何为logstash+elasticsearch配置索引模板?
- 如何为logstash+elasticsearch配置索引模板?
- logstash-filter-elasticsearch 具体使用实例
- Elasticsearch、Logstash、Kibana、Filebeat的使用总结
- 使用 logstash + kafka + elasticsearch 实现日志监控
- 记录一下怎么使用pycaffe调用已有的网络模型识别人脸(物体)
- Elasticsearch如何更新mapping
- Elasticsearch 429,logstash没有更新kafka队列状态的问题
- 如何给已有的Project改名字?
- 如何导入已有的外部数据库
- 如何导入已有的外部数据库
- [Android]如何导入已有的外部数据库
- 30 多个为成为一名更好的安卓开发者的短小而又专业的建议
- Live555学习之(四)------建立RTSP连接的过程(RTSP客户端)
- 条件判断语句(if...else)与条件编译(#if .... #else ... #endif)
- 【洛谷1342】请柬
- LeetCode-42-Trapping Rain Water 贪心或单调栈
- 如何使用logstash更新已有的elasticsearch记录
- 自配Tomcat的启动
- SVN库迁移
- 我遇到的前端面试题2017
- Volley的框架解读一(Http的封装)
- 相反数
- C语言小程序2--致新手
- Java基础部分全套教程
- C++随机数求圆周率