文章目录
- 1、问题描述
- 2、案例讲解
- 3、问题剖析
- 4、解决方案
- 4.1 注意:
- 4.2 步骤:
- 4.3 示例:
- 4.3.1 创建一个新的索引
- 4.3.2 reindex 重建索引
- 4.3.3 恢复索引
- 5、彩蛋 & 坑
- 5.1 坑
- 5.2 使用 Pipline
- 6、总结
1、问题描述
在 Elasticsearch 中,删除字段是一个常见的需求,尤其是在数据模型发生变化或需要清理无用字段时。
以下是一些常见的需要删除字段的场景:
- 数据模型变更:某些字段不再需要,需要从索引中移除。
- 数据清理:删除敏感信息或无用的字段。
- 性能优化:减少索引的大小,提升查询性能。
- 修改类型:由于字段类型前期预估错误,需要删除重建
传统的 SQL 数据库可以直接使用 ALTER TABLE DROP COLUMN
,但在 Elasticsearch 中,删除字段可能并不是想象的那么简单,Elasticsearch 并没有直接提供删除字段的 API,而是需要通过一些间接的方式来实现。本文将详细介绍如何在 Elasticsearch 中删除字段,包括使用场景、解决方案和实际案例。
2、案例讲解
假设有一个索引 my_index
,其中包含字段 t1
和 t2
,现在需要删除 t1
。
首先写入测试索引字段类型可以使用自动映射
POST /my_index/_doc
{"t1": "我是我是第一个字段","t2": "我是第二个字段"
}
查询结果记录
GET my_index/_search
尝试使用 _update
结合 script 删除字段
POST my_index/_update/RakddJUBPtRg8Gmh8sq8
{"script": "ctx._source.remove('t1')"
}
当然,你也可以使用 update_by_query 对文档进行批量操作:
POST my_index/_update_by_query
{"query": {"match_all": {}},"script": "ctx._source.remove('t1')"
}
执行完毕之后,在此查询结果,发现的确删掉了 t1
字段
3、问题剖析
看似达到了效果,但是,字段真的删掉了吗?
ES 的特性不同于 RDB,是允许稀疏字段存在的,可以是 doc1: field1,field2;doc2:field2,field3。这种情况是允许的,也就是说,查不到结果,不一定就意味着字段不存在。
查看索引的映射,验证一下:
GET my_index/_mapping
果然,字段 t1 依旧还是存在的,只不过所查询的文档记录,t1 并没有值,所以也就看不到。
4、解决方案
Elasticsearch 的索引映射(mapping)一旦创建,字段的类型和结构就不能直接修改。如果需要删除某个字段,
重建索引是 Elasticsearch 中删除字段的最常见方法。通过创建一个新的索引,并将旧索引的数据复制到新索引中(排除需要删除的字段),可以实现字段的删除。
4.1 注意:
删除字段需要借助以下方法:
- 重建索引(Reindex)。
- 使用
_update_by_query
更新文档。 - 使用 Ingest Pipeline 过滤字段。
4.2 步骤:
- 创建一个新的索引,定义新的映射(不包含需要删除的字段)。
- 使用
_reindex
API 将旧索引的数据复制到新索引中。 - 删除旧索引,将新索引重命名为旧索引的名称(可选)。
4.3 示例:
4.3.1 创建一个新的索引
如果源索引的名字可以修改,可以把新索引作为源索引的替代,不然的话,后面需要将新索引重新再 reindex 回去,一共需要 reindex 两次
PUT /my_index_bak
{"mappings": {"properties": {"t2": {"type": "text"}}}
}
注意,字段 t2
如果需要和源索引类型保持一致,直接复制源索引的字段类型即可,这里删除 t1
的字段映射。
4.3.2 reindex 重建索引
POST /_reindex
{"source": {"index": "my_index"},"dest": {"index": "my_index_bak"},"script": {"source": "ctx._source.remove('t1')"}
}
再次查看索引 mapping,可以看到,字段 t1 就已经被彻底删除了
4.3.3 恢复索引
当新索引创建完成,旧索引就可以删除了,然后同样的方式,把新索引的 mapping 重新创建一次,使用需要的索引名称即可
POST /_reindex
{"source": {"index": "my_index_bak"},"dest": {"index": "my_index"}
}
再次查看索引 mapping,可以看到,字段 t1 就已经被彻底删除了
或者给新索引添加别名
DELETE /my_index
PUT /my_index_bak/_alias/my_index
5、彩蛋 & 坑
5.1 坑
在执行重建索引的时候,有一个关键操作
"script": {"source": "ctx._source.remove('t1')"}
它的意思是在重建索引时,会删除指定的字段,比如上面代码在重建的时候,就会忽略 t1 字段,这样新索引就不会有 t1 字段,不然,即便新索引没有创建 t1 字段的 mapping,也会因为源索引包含 t1 字段且会因为 dynamic mapping 而导致 t1 重新被写入。
因此,这一步是绝对不能忽视的。
5.2 使用 Pipline
在 reindex 的时候,也可以通过 Pipeline 来达到同样的目的
PUT _ingest/pipeline/remove_t1
{"processors": [{"remove": {"field": "t1"}}]
}
# 重建索引
POST /_reindex?
{"source": {"index": "my_index"},"dest": {"index": "my_index_bak","pipeline": "remove_t1"}
}
6、总结
- Elasticsearch 索引具备不可变性,字段的类型是不可修改的,包括删除字段,因此一切通过修改当前索引的操作都是不可行的,包括:
- update API
- update_by_query API
- 重建索引可以通过 Script 或者 Pipline 完成过滤字段,但是后者需要创建 pipline,因此更推荐前者