ElasticSearch修改index增加修改字段(包括template)
0.已经生成的index,它的mappings是不会变的,比如只有name、age、desc三个字段,且各自的index、doc_values都已经确立;那么我往里面提交是可以提交额外的字段如:phone
,但是这个phone字段无法被搜索,它只能被查已经存在且能查询的三个字段查出来后 附带 的带出来,无论这个字段是数值还是文本类型;
因此这里面临一个问题,那就是怎么对已经生成的index 增加字段,或者删除字段,甚至是修改字段;
1.注意,ES似乎是不支持修改字段的,所以字段的类型一定要确定好(包括index、doc_values),否则就只能通过程序实现修改字段了(即一份数据存两个index,将旧的index数据导入新的index,最后drop旧的index)
2.命令为:PUT
indexname/_mapping/_doc?include_type_name=true
{
"properties": {
"newProp1": {
"type": "keyword",
"doc_values": true
},
"newProp2": {...}
}
}
通过上面的方法把该字段的mapping结构增加到这个index后,对于旧的文档仍然是无法通过该字段来查询的,因为旧的文档里没有该字段的数据,因为保存的时候因为没有该字段的mapping,所以没有保存该document的该字段的查询信息;
注意,这个只适用新字段,旧字段不行,所以如果是旧字段要改变元数据,如index和doc_values,可以用reindex api
POST _reindex可以将index_origin复制到index_tmp里【index_tmp可以不事先创建】,然后删除index_origin,然后创建一个有mappings结构的index_origin(如果index_origin是根据模板来创建,模板里已经写好了相关的mapping结构,则不需要事先创建index_origin直接_reindex将index_tmp复制回index_origin即可),然后再将index_tmp通过_reindex复制回新的index_origin【注意_reindex可能会执行很久,需要等待】即可实现index_origin已存在字段数据结构的改变(然后清理临时index_tmp);写法为:
POST接口,uri就是_reindex,请求体为:
{
"source": {
"index": "old_index",
//"size": 5000 //可选,每次批量提交5000个,可以提高效率,建议每次提交5-15M的数据
},
"dest": {
"index": "new_index"
}
}
这种方式将没有配置mapping的字段a的index m,先_reindex已经配置了字段a mapping的index n里,在index n里就可以通过字段a来查询文档了;
删除index m后重新_reindex n到有mapping a的index m,然后m也能通过a来查询文档了(包括旧数据)
【注意】注意_reindex可以对相同的参数执行多次,而且是覆盖更新不会出现第一次_reindex到index_tmp,使得tmp有了数据1,然后此时又执行了_reindex不会导致index_tmp有两条数据1,只会全量覆盖(确认是根据_id来覆盖更新);
【重要】如果index_origin是已经在使用状态,却也需要将里面的如name字段的index由false改成true,用_reindex虽然可以,但是会丢失数据,因为数据到index_tmp之后,删除index_origin之前的这一小段时间是可能有数据又插入到了index_origin里的;那么就必须通过程序来实现这样的处理了:(前提是文档的_id是由程序来主动写的,否则这个方案不适用;所以es的index数据写入都用自定义的_id)
1.程序改成同时写index_origin和index_tmp(两个异步写不需要事务,可能存在一定的概率导致index_source写成功了但是index_tmp写失败了,但是概率已经很低很低了,毕竟单写一个index也是可能出现问题的,做好补录问题不大)的版本2
2.部署好以后(应用可以是集群多实例的,因为会在应用所有实例发完后_reindex一次,所以没有影响)肯定存在index_tmp比index_origin数据量少的问题,此时通过_reindex将index_source同步到index_tmp里同步好后,那应该来说没有丢数据的前提下index_source和index_tmp数据是一致的(丢了数据肯定有日志记录,需要看是丢的哪个index来选择性补录);
3.此时index_tmp有全量数据,且字段name的index是改成了true;
4.再删除index_source(有template能自动生成index),然后再通过_reindex将index_tmp的数据复制到index_source里就行了;
5.回退应用(取消同时插入index_tmp)
分隔符:这里注意第4点,有些程序可能要求比较高,不能某段时间查出index_source是没有数据,所以还可以这样改:
即再准备一个版本3,这个版本是查询从index_tmp来查询,也需要同时写index_tmp和index_source(也必须两个都写,否则也会存在_reindex之后删除之前这段时间的数据问题);
应用切换完后,用户仍然能查看到所有数据(因为版本3也是会写index_tmp);
然后此时再删除index_source(先在template增加name的index:true)然后会自动生成index_source(此时是新的mappings),这时候不影响用户查询出所有数据,然后再_reindex将index_tmp数据同步到index_source
此时index_source拥有所有数据,且name有index:true了
然后再回退应用版本2,即同时插入index_source和index_tmp,但是是从index_source里查询;(之所以先回退到这个版本是因为如果直接回退到最初的版本,会在某一时刻出现实例1是读取的index_tmp,而实例2是读取的index_source,而这两个
index数据是理论上就不一致的,因为回退到最初的版本的实例它只插入数据到index_source,然后用户第一次请求如果请求到了实例2发现有数据8888,它是在实例2回退到最初版本后新插入的,但是第二次请求是到了实例1却发现没有了这条数据,因为实例2没有同时插入8888的数据到index_tmp里,而实例1还没回退它读取的是index_tmp)
然后再回退到最初的版本即可;
【重要】注意,模板里没有加某个字段,然后写数据的时候这个字段是可以插进入的,但是无法通过它来查询,因为它不在index的mapping里;
【ES往index里增加字段mapping的终极方法】
1.利用es index哪怕没有添加某个字段如uuid的mapping,只要源头写入时有uuid字段则存储是能存储进来的,只不过无法通过uuid来查(没有mapping)
2.利用_reindex本质上就是把A index的数据完整的POST 到B index;
3.利用es POST数据如果存在则会覆盖的特性;
所以当index m里有uuid字段数据,但是它没有mapping,首先是给index m通过上面的方法添加uuid的mapping;
但是此时只是新增的文档可以用uuid来搜索,旧的是没法搜索的;
接着用_reindex将index m备份到m_bak里(m_bak要先创建好正确的mapping【估计都不用】);
然后接着再_reindex将m_bak的数据覆盖掉m里原先的,这时候m_bak的数据就会覆盖m的从而导致旧的文档会重新保存而能通过uuid来搜索了;
然后再delete掉m_bak;
【这个方法也只适合新增不适合修改字段,修改的话还是得先_reindex备份后,删除掉原先的,然后再恢复(但是这里就有时间空隙,可能_reindex备份好的过程里再删除原index时,原index已经有新增的数据了,会导致数据丢失)】
posted on 2022-06-14 18:18 Silentdoer 阅读(968) 评论(0) 编辑 收藏 举报