我们使用ElasticSearch时一般需要自己创建ElasticSearch的索引的Mapping,当索引非常多的时候,可能需要配置一个索引模板Template来对类似的索引做统一配置,让索引模板Template中配置匹配索引的规则,来确定该Template会被应用到哪些索引上。
当Logstash在整合ElasticSearch的时候,会有下面三种方式的Template配置:
Template配置方式
1. 使用ElasticSearch默认自带的索引模板
ElasticSearch默认自带了一个名字为”logstash”的模板,默认应用于Logstash写入数据到ElasticSearch使用
- 优点:最简单,无须任何配置
- 缺点:无法自定义一些配置,例如:分词方式
2. 在Logstash Indexer端自定义配置索引模板
Logstash的output插件中使用template指定本机器上的一个模板json文件路径,可以在json文件中设置对应的Template模板信息。例如:template => “/tmp/logstash.json”
- 优点:配置简单
- 缺点:因为分散在Logstash Indexer机器上,维护起来比较麻烦
3. 在ElasticSearch服务端自定义配置索引模板
由ElasticSearch负责加载模板。这种方式需要在ElasticSearch的集群中的config/templates路径下配置模板json。而且ElasticSearch提供了Restful API接口维护索引模板信息。
- 优点:维护比较容易,可动态更改,全局生效。
- 缺点:需要注意模板的命名规则,比较容易通过看Template名字就能够确定模板应用到哪些索引
这里可能使用第三种方式统一管理Template最好,推荐使用第三种方式,但是具体问题具体分析。例如我现在的场景就使用的第二种方式,因为我们的Logstash Indexer和ElasticSearch只有一台服务器,所以在Logstash Indexer端维护Template文件也可以。
模板类型
ElasticSearch的模板类型主要由两种:静态模板和动态模板
静态模板
适合索引字段数据固定的场景,一旦配置完成,不能向里面加入多余的字段,否则会报错
- 优点:scheam已知,业务场景明确,不容易出现因字段随便映射从而造成元数据撑爆es内存,从而导致es集群全部宕机
- 缺点:字段数多的情况下配置稍繁琐,针对于每个索引可能需要的模板都不同,很有可能需要配置很多个模板
动态模板
适合字段数不明确,大量字段的配置类型相同的场景,可以按照类型规则动态添加新字段,新加字段不会报错。主要需要配置”dynamic_templates”
- 优点:可动态添加任意字段,无须改动schema
- 缺点:无标准schema导致数据不规则,如果添加的字段非常多,有可能造成ES集群宕机
需要注意:模板在设置生效后,仅对ES集群中新建立的索引生效,而对已存在的索引及时索引名满足模板的匹配规则,也不会生效,因此如果需要改变现有索引的Mapping信息,仍需要在正确的Mapping基础上建立新的索引,并将数据从原索引拷贝至新索引,变更新索引别名为原索引这种方式来实现。
模板结构
模板的结构大致分四部分:
第一部分:通用设置,主要是模板匹配索引的过滤规则,影响该模板对哪些索引生效;
第二部分:settings:配置索引的公共参数,比如索引的replicas,以及分片数shards等参数;
第三部分:mappings:最重要的一部分,在这部分中配置每个type下的每个field的相关属性,比如field类型(string,long,date等等),是否分词,是否在内存中缓存等等属性都在这部分配置;
第四部分:aliases:索引别名,索引别名可用在索引数据迁移等用途上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| { "logstash" : { "order" : 0, "template" : "logstash-*", "settings" : { "index" : { "refresh_interval" : "5s" } }, "mappings" : { "_default_" : { "dynamic_templates" : [ { "message_field" : { "mapping" : { "fielddata" : { "format" : "disabled" }, "index" : "analyzed", "omit_norms" : true, "type" : "string" }, "match_mapping_type" : "string", "match" : "message" } }, { "string_fields" : { "mapping" : { "fielddata" : { "format" : "disabled" }, "index" : "analyzed", "omit_norms" : true, "type" : "string", "fields" : { "raw" : { "ignore_above" : 256, "index" : "not_analyzed", "type" : "string" } } }, "match_mapping_type" : "string", "match" : "*" } } ], "_all" : { "omit_norms" : true, "enabled" : true }, "properties" : { "@timestamp" : { "type" : "date" }, "geoip" : { "dynamic" : true, "properties" : { "ip" : { "type" : "ip" }, "latitude" : { "type" : "float" }, "location" : { "type" : "geo_point" }, "longitude" : { "type" : "float" } } }, "@version" : { "index" : "not_analyzed", "type" : "string" } } } }, "aliases" : { } } }
|
总结:
定制索引模板,是搜索业务中一项比较重要的步骤,需要注意的地方有很多,比如:
- 字段数固定吗
- 字段类型是什么
- 分不分词
- 索引不索引
- 存储不存储
- 排不排序
- 是否加权
除了这些还有其他的一些因素,比如,词库的维护改动,搜索架构的变化等等。如果前提没有充分的规划好,后期改变的话,改动其中任何一项,都需要重建索引,这个代价是非常大和耗时的,尤其是在一些数据量大的场景中。
Logstash整合ElasticSearch模板实例
首先我们通过ElasticSearch的Restful API接口查询一下ElasticSearch中一共创建了多少个索引模板,默认情况下ElasticSearch应该会有一个名字为”logstash”的Template,这个Template匹配了所有”logstash-*”的索引,也就是说所有以”logstash-“开头的索引都默认使用了这个”logstash”的Template。这个Template就是一个动态模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| curl -XGET localhost:9200/_template?pretty { "logstash" : { "order" : 0, "template" : "logstash-*", "settings" : { "index" : { "refresh_interval" : "5s" } }, "mappings" : { "_default_" : { "dynamic_templates" : [ { "message_field" : { "mapping" : { "fielddata" : { "format" : "disabled" }, "index" : "analyzed", "omit_norms" : true, "type" : "string" }, "match_mapping_type" : "string", "match" : "message" } }, { "string_fields" : { "mapping" : { "fielddata" : { "format" : "disabled" }, "index" : "analyzed", "omit_norms" : true, "type" : "string", "fields" : { "raw" : { "ignore_above" : 256, "index" : "not_analyzed", "type" : "string" } } }, "match_mapping_type" : "string", "match" : "*" } } ], "_all" : { "omit_norms" : true, "enabled" : true }, "properties" : { "@timestamp" : { "type" : "date" }, "geoip" : { "dynamic" : true, "properties" : { "ip" : { "type" : "ip" }, "latitude" : { "type" : "float" }, "location" : { "type" : "geo_point" }, "longitude" : { "type" : "float" } } }, "@version" : { "index" : "not_analyzed", "type" : "string" } } } }, "aliases" : { } } }
|
我们创建一个自定义Template动态模板,这个模板指定匹配所有以”go_logsindex“开始的索引,并且指定允许添加新字段,匹配所有string类型的新字段会创建一个raw的嵌套字段,这个raw嵌套字段类型也是string,但是是not_analyzed不分词的(主要用于解决一些analyzed的string字段无法做统计,但可以使用这个raw嵌套字段做统计)
go_logs_template.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| { "template": "go_logs_index_*", "order":0, "settings": { "index.number_of_replicas": "1", "index.number_of_shards": "5", "index.refresh_interval" : "10s" }, "mappings": { "_default_": { "_all": { "enabled": false }, "dynamic_templates": [ { "my_template": { "match_mapping_type": "string", "mapping": { "type": "string", "fields": { "raw": { "type": "string", "index": "not_analyzed" } } } } } ] }, "go": { "properties": { "timestamp": { "type": "string", "index": "not_analyzed" }, "msg": { "type": "string", "analyzer": "ik", "search_analyzer": "ik_smart" }, "file": { "type": "string", "index": "not_analyzed" }, "line": { "type": "string", "index": "not_analyzed" }, "threadid": { "type": "string", "index": "not_analyzed" }, "info": { "type": "string", "index": "not_analyzed" }, "type": { "type": "string", "index": "not_analyzed" }, "@timestamp": { "format": "strict_date_optional_time||epoch_millis", "type": "date" }, "@version": { "type": "string", "index": "not_analyzed" } } } } }
|
接下来我们看看Logstash是如何使用Template的。首先我们需要准备好Logstash要使用的Template文件,其实这里我们也可以在ES直接创建好Template,然后都在ES维护Template,就是前面说的推荐的第三种方式,但是对于我们单个Logstash Indexer和ElasticSearch节点,方式二和方式三配置都很简单。
在Logstash的配置文件中添加template相关的配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ... output { stdout { codec => rubydebug } elasticsearch { codec => "json" hosts => ["hadoop1:9200", "hadoop2:9200", "hadoop3:9200"] index => "go_logs_index_%{+YYYY.MM.dd}" document_type => "%{type}" template => "/usr/local/elasticsearch/template/go_logs_template.json" template_name => "go_logs_template" template_overwrite => true workers => 1 flush_size => 20000 idle_flush_time => 10 } } # 配置说明: # template : 指定template模板文件 # template_name : 指定在ES中创建template的名称,默认是logstash # template_overwrite : 是否覆盖ES中的template,默认是false
|
这样我们使用Logstash创建的索引”go_logsindex%{+YYYY.MM.dd}”就会匹配到我们的Template,就会使用Template中的配置,所以使用Template之后就不需要每新创建一个索引就自己手动创建Mapping了,可以直接使用Template为一类的索引创建默认Mapping配置。
参考文章: