Silentdoer

导航

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编辑  收藏  举报