1.在使用ES之前就应该把mapping指定写好,官方文档写的很详细
You can only find that which is stored in your index. In order to make your data searchable, your database needs to know what type of data each field contains and how it should be indexed. If you switch a field type from e.g. a string to a date, all of the data for that field that you already have indexed becomes useless. One way or another, you need to reindex that field.
...
OK,这一段话很合理,我改了一个field的类型 需要对这个field进行reindex,如论哪种数据库都需要这么做,没错.
我们再继续往下看看,reindexing your data, 他的reindexing your data不是对修改的filed进行reindex,而是创建了一个新的index,对所有的filed进行reindexing, 太逆天了。所以请按照下面两种方式来解决。
2.第一种解决方案
elasticsearch索引一旦建立,就无法动态修改其字段的映射类型,有时候因为人为原因污染了索引的mapping,这个时候就只能通过重建索引来修改索引的mapping设置了。
在一次项目中,有一个字段结构如下:
{ "logistics":{ "company":"string", "no":"string" } }
由于当初创建索引的时候,既没有给这个索引中的这个字段指定合适的类型,也没有通过动态模板来为这个字段指定类型,导致 elasticsearch 默认将这种结构的数据设置成了 Object 类型,而我们真正想要设置的类型却是 Nested 类型。
第一种方案,给这个索引追加一个新的字段,同时给这个字段指定类型。
PUT test/_mapping/test { "properties": { "logisticsV2":{ "type": "nested", "properties": { "company":{ "type":"keyword" }, "no":{ "type":"keyword" } } } } }
执行之后,index的mapping中就是这样的了:
{ "test":{ "mappings":{ "test":{ "properties":{ "logistics":{ "properties":{ "company":{ "type":"text", "fields":{ "keyword":{ "type":"keyword", "ignore_above":256 } } }, "no":{ "type":"text", "fields":{ "keyword":{ "type":"keyword", "ignore_above":256 } } } } }, "logisticsV2":{ "type":"nested", "properties":{ "company":{ "type":"keyword" }, "no":{ "type":"keyword" } } } } } } } }
其中 logisticsV2
的类型是 nested 类型,之后依赖于 nested 类型的相关功能使用 logisticsV2字段来实现即可。
这个中方式有一些弊端,比如数据冗余问题、数据一致性问题等
第二个方案,使用 elasticsearch 提供的 reindex api 来迁移数据,创建新的索引。
首先创建好目标索引,并设置好mapping:
PUT test_new PUT test_new/_mapping/test { "properties": { "logistics":{ "type": "nested", "properties": { "company":{ "type":"keyword" }, "no":{ "type":"keyword" } } } } }
之后,使用 reindex 将原来的索引重建到新的索引上:
POST _reindex { "source": { "index": "test" }, "dest": { "index": "test_new" } }
等待 reindex 完成后, test_new 就结构就就是你想要的mapping了。
3.第二种解决方案
使用 Elasticsearch alias 功能切换 indexl.
有时候,需要将已有的索引做些调整重建为另外一个索引,但是为了不影响线上的访问,需要无缝切换到新的索引上。
基本上有两种方案,一是改代码,使线上代码访问新的索引,二是使用 alias 别名功能。
第一种方案有弊端,在代码进行发布到具体机器之前的并不能保证所有的访问都是访问的新的索引。
这里选择通过 alias 来切换索引,因为 alias 中的多条命令是原子性。
1.创建索引 test 和 test_v2
PUT test
PUT test_v2
GET test*
结果如下:
{ "test": { "aliases": {}, "mappings": {}, "settings": { "index": { "creation_date": "1514183636616", "number_of_shards": "5", "number_of_replicas": "1", "uuid": "oOgEhLzqS_usf7floIhNig", "version": { "created": "5030099" }, "provided_name": "test" } } }, "test_v2": { "aliases": {}, "mappings": {}, "settings": { "index": { "creation_date": "1514183638407", "number_of_shards": "5", "number_of_replicas": "1", "uuid": "o6x6VtmQSFaOpOB-OpIwBg", "version": { "created": "5030099" }, "provided_name": "test_v2" } } } }
2.现在需要将对 test 的访问无缝切换到 test_v2,使用 alias 功能即可做到,对线上服务、对用户无感
POST _aliases { "actions": [ { "add": { "index": "test_v2", "alias": "test" } }, { "remove_index": { "index": "test" } } ] }
actions 中的多条命令是原子性的,所以可以做到无缝切换,不必担心切换过程中会存在访问不到 test 时候。
3.命令解释
actions 中第一条命令:add 命令,给索引 test_v2 添加了一个别名 test。
actions 中第二条命令:remove_index, 删除原来的 test 索引。
执行之后,原来的 test索引会被删除,而对于访问方而言,访问的索引依然是 test,不过访问的是一个别名,底层实际访问的索引已经是 test_v2了
GET test* { "test_v2": { "aliases": { "test": {} }, "mappings": {}, "settings": { "index": { "creation_date": "1514183638407", "number_of_shards": "5", "number_of_replicas": "1", "uuid": "o6x6VtmQSFaOpOB-OpIwBg", "version": { "created": "5030099" }, "provided_name": "test_v2" } } } }
从结果中可见,test索引已经不存在了,但是通过 GET test 还是能访问到,而现在 test_v2 多了一个 alias test。
参考转载------------http://www.cnblogs.com/Creator/p/3722408.html