生命周期和模板都是为了优化ES性能的,假如ES是一个小学校,数据是一个个入学的小学生,那么生命周期就是一二三年级,用生命周期制定的规则来管理学生何时进入下一个年级,1年级新学生允许他们随意玩耍,支持数据写入、读取,而6年级的老学生要冷静一点,就只支持读取,以此优化整个ES服务的性能,好钢用到刀刃上。至于模板就是学生课桌,保证每次进来新同学,教室座位顺序不乱。
另:此篇单纯讲解生命周期和模板创建,如果要建立ES集群模式,同步参考下篇文章:Elasticsearch7.×集群搭建,生命周期策略ilm_policy、索引模板template管理
(以下命令行均以ES7.0版本及以上操作,7.0以下涉及到文档操作注意添加“_doc”才能正确执行,另外演示代码块中的中文注释部分删掉后才可以执行,别直接复制粘贴运行呀!)
可以PUT命令创建,也可以在kibana中创建(推荐)
//设定生命周期
PUT /_ilm/policy/article_ilm_policy(自定义生命周期名称)
{
"policy":{
"phases":{
"hot":{
"actions":{
"rollover":{
"max_docs":"50000000"(最大文章数上限)
}
}
},
"warm":{
"min_age":"15d",
"actions":{
"allocate":{
"include":{
"box_type":"warm"
},
"number_of_replicas":0
},
"forcemerge":{
"max_num_segments":1
}
}
},
"cold":{
"min_age":"30d",
"actions":{
"allocate":{
"include":{
"box_type":"cold"
}
}
}
},
"delete":{
"min_age":"60d",
"actions":{
"delete":{
}
}
}
}
}
}
查看当前所有模板
GET _template
查看指定模板规则
GET _template/article_ilm_template
创建模板
//设定索引模板
PUT /_template/article_ilm_template
{
"index_patterns":[
"article*"(索引匹配规则,满足article为前缀的索引以此模板创建,这个要写好,瞎写或者写复杂了容易导致索引找不到模板)
],
"aliases": {
"article": {}(规定新索引的别名,这里有bug,如果写上这个索引别名,但滚动索引会跟下面rollover_alias重复冲突,引起rollover失败,建议不写这个配置,第一个索引采用手动创建别名)
},
"settings":{
"number_of_shards":9,(主分片数)
"number_of_replicas":1,(副本数)
"index.lifecycle.name":"article_ilm_policy",(规定索引遵从哪个生命周期)
"index.lifecycle.rollover_alias":"article",(规定rollover索引别名)
"index.routing.allocation.include.box_type":"hot",(让所有符合命名规则索引的 Shard 都将被分配到 Hot Nodes 节点上,如果不需要指定分配,可以去掉)
},
"mappings":{
"properties":{
"id":{
"type":"integer"
},
"appChannel":{
"type":"long"
},
"channleId":{
"type":"integer"
},
"content":{
"type":"text",
"index":false,
"copy_to":[
"fulltext"
]
},
"createTime":{
"type":"date",
"format":"yyyy-MM-dd'T'HH:mm:ss.SSSZZ||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"wordCount":{
"type":"keyword",
"index":false
}
}
}
}
当然模板中settings不仅下面这些属性配置,还可指定分词器analysis、过滤器等
"index.max_ngram_diff":5,
"analysis" : {
"analyzer" : {
"ngram_analyzer" : {
"tokenizer" : "ngram_tokenizer"
}
},
"tokenizer" : {
"ngram_tokenizer" : {
"filter" : [
"lowercase"
],
"min_gram" : "1",
"type" : "ngram",
"max_gram" : "3"
}
}
}
说一下别名问题,我们代码程序查询、添加文档到索引时,需要指定索引名称,但是这种方式扩容的索引需要统一的别名,根据别名进行操作,查询别名就会查询别名下的所有索引,同样添加文档到别名,就会添加到此别名下最新索引,当然最新索引必须满足"is_write_index":true也就是支持写入,集群只能规定一个写入的索引,如果不是请注意修改调整。
//写入和读取,都是根据共同的别名article进行的,他们别名一样
//设置别名,如果别名不对的话,就无法查询到此article-test索引
//设置允许写入写入"is_write_index":true ,否则无法写入数据,集群只能规定一个写入的索引
//创建索引,指定别名
PUT article-test(需要修改的索引)
{
"aliases":{
"article(别名)":{
"is_write_index":true
}
}
}
//另一种写法,修改别名,指定索引:
POST /_aliases
{
"actions":[
{
"add":{
"index":"article-test",(需要修改的索引)
"alias":"article",(别名)
"is_write_index":true
}
}
]
}
当时一个索引达到生命周期所规定的扩容条件后就可以进行Rollover 扩容,我上面创建的生命周期规定的是"rollover":{ "max_docs":"50000000"(最大文章数上限) },也可以去kibana中根据内存大小、文档数量、存活时间进行设置。
Rollover不是完全自动的,还是需要命令简单执行,如果达到完全自动的方式,可以通过程序编写定时任务或者服务器定时脚本执行命令。
POST article(别名)/_rollover/
{
"conditions": {
"max_docs": 2
}
}
或者
POST article(别名)/_rollover/article-05(指定rollover后的索引名称)
{
"conditions": {
"max_docs": 50000000
}
}
或者强行rollover
POST article(别名)/_rollover/
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
公司ES有个article索引,设定索引生命周期:5千万文档后Rollover新建下一个索引。初始索引名为article-01,后续新增的依次为article-02,article-03等,他们的别名都叫article,这样查询和写入索引都按照别名进行。
有一天公司突然发现从Kibana的discover查不到ES中article数据了,程序中也不能查到最新的数据,但根据id细查还是能查到,并且也有文档数据进来。
排查后发现是自动新增的索引article-04中的字段crawTime不是data类型,而是text,导致discover设置的根据crawTime为条件的查询失效,并且导致程序查询中无法根据crawTime过滤筛选查询,也就查不到最新article-04中的数据。
索引模板未生效,新索引没有匹配到模板,也就没有预先设定好所需要的字段类型。
首先解决现有问题让网站系统恢复了,再修改模板,避免再出现此问题。
首先已经创建的索引字段是无法更改的,所以要新建索引article-test,并为其创建好正确的字段类型,将article-04数据转移到article-test。先设定新索引字段类型
//设置当前索引的字段及字段类型
PUT article-test/_mapping/_doc
{
"_doc":{
"_source":{
"enabled":true
},
"_routing":{
"required":true
},
"properties":{
"id":{
"type":"integer"
},
"appChannel":{
"type":"long"
},
"channleId":{
"type":"integer"
},
"content":{
"type":"text",
"index":false,
"copy_to":[
"fulltext"
]
},
"createTime":{
"type":"date",
"format":"yyyy-MM-dd'T'HH:mm:ss.SSSZZ||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"wordCount":{
"type":"keyword",
"index":false
}
}
}
}
转移数据到新索引
//转移数据,从article-04到article-test
POST _reindex
{
"source": {
"index": "article-04",
},
"dest": {
"index": "article-test"
}
}
删除原出错的索引,如果有必要的话
DELETE article_04
由于别名的存在,所以article-test就已经可以代替article-04使用了,但我是强逼症,就想恢复到原样,所以重新创建了article-04再重复上述转移数据的步骤折腾回去。
数据和功能恢复了,下一步修复模板,避免article-05也出现这样的问题,首先想一想为什么模板没生效?再看下这个模板
感觉也没问题呀,该有的都有,是因为这个模板权重order太低了吗,有重名的模板?被其他模板取代了吗?那我重新编辑模板,添加权重"order":10000试试,发现也不行,那看来就是这个模板本身的问题了。
{
"order":10000,(添加权重)
"index_patterns":[
"article-*"
],
"settings":{
"number_of_shards":9,
"number_of_replicas":1,
"index.lifecycle.name":"article_ilm_policy",
"index.lifecycle.rollover_alias":"article",
"index.routing.allocation.include.box_type":"hot",
"analysis":{
"analyzer":{
"ngram_analyzer":{
"tokenizer":"ngram_tokenizer"
}
},
"tokenizer":{
"ngram_tokenizer":{
"type":"ngram",
"min_gram":1,
"max_gram":3,
"filter":[
"lowercase"
]
}
}
}
},
"properties":{
"websiteId":{
"type":"integer"
},
"weixinBiz":{
"type":"keyword"
},
"wordCount":{
"type":"keyword",
"index":false
}
}
}
那我匹配简单的名称行不行,名称匹配不搞那么复杂了,将 "article-*换成 "a*",然后去创建索引article-test01发现成功了!!!能够按照模板规则创建索引的属性等信息。
"index_patterns":[
"a*"
]
结果就是证明索引根据名称没匹配到期望的模板。最后将匹配规则 "article-*"去掉横杠"-"变为"article*"也能匹配上,所以模板匹配名称不要写太复杂,能匹配上又不会冲突就够了。