从 Elasticsearch 文档中删除字段
Remove a field from a Elasticsearch document
我需要删除索引到 Elasticsearch 的所有文档中的一个字段。我该怎么做?
默认情况下这是不可能的,因为现在 Lucene 不支持它。基本上,您只能从 Lucene 索引中放置或删除整个 Lucene 文档。
- 获取文档的第一个版本
- 删除字段
- 推送您文档的这个新版本
此答案适用于 < ES 5 版本。
@backtrack 说的是真的,但是在 Elasticsearch 中有一种非常方便的方法可以做到这一点。
Elasticsearch 会将删除的内部复杂性抽象出来。
您需要使用更新 API 来实现此目的 -
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"script" : "ctx._source.remove(\"name_of_field\")"
}'
您可以找到更多文档 here。
注意:从 Elastic Search 6 开始,您需要包含 content-type header:
-H 'Content-Type: application/json'
Elasticsearch 在 2.3 中添加了 update_by_query
。此实验性界面允许您对与查询匹配的所有文档进行更新。
elasticsearch内部做一个scan/scroll收集批量文档,然后像批量更新接口一样更新。由于没有网络和序列化的开销,这比使用您自己的 scan/scroll 界面手动执行更快。每条记录都要加载到ram中,修改后再写入。
昨天我从我的 ES 集群中删除了一个大字段。在 update_by_query 期间,我看到了每秒 10,000 条记录的持续吞吐量,受到 CPU 而不是 IO 的限制。
如果集群有其他更新流量,请查看设置 conflicts=proceed
,或者当其中一个记录在其中一个批次下更新时,当它遇到 ConflictError
时整个作业将停止。
类似地设置wait_for_completion=false
将导致update_by_query通过tasks界面变为运行。否则,如果连接关闭,作业将终止。
url:
http://localhost:9200/INDEX/TYPE/_update_by_query?wait_for_completion=false&conflicts=proceed
POST正文:
{
"script": "ctx._source.remove('name_of_field')",
"query": {
"bool": {
"must": [
{
"exists": {
"field": "name_of_field"
}
}
]
}
}
}
自 Elasticsearch 1.43 起,内联 groovy scripting is disabled by default。您需要通过将 script.inline: true
添加到您的配置文件来启用它,这样的内联脚本才能工作。
或者将 groovy 作为脚本上传并使用 "script": { "file": "scriptname", "lang": "groovy"}
格式。
您可以使用_update_by_query
示例 1
索引:my_index
字段:user.email
POST my_index/_update_by_query?conflicts=proceed
{
"script" : "ctx._source.user.remove('email')",
"query" : {
"exists": { "field": "user.email" }
}
}
示例 2
索引:my_index
字段:total_items
POST my_index/_update_by_query?conflicts=proceed
{
"script" : "ctx._source.remove('total_items')",
"query" : {
"exists": { "field": "total_items" }
}
}
之前的答案对我不起作用。
我必须添加关键字“inline”:
POST /my_index/_update_by_query
{
"script": {
"inline": "ctx._source.remove(\"myfield\")"
},
"query" : {
"exists": { "field": "myfield" }
}
}
对于那些坚持 bulk API, the alternative to achieve deletion on field(s) of document(s) is to provide extra script in the update
action payload 批量 API 通话的人。
命令部分和官方文档描述的一样:
curl -s -H "Content-Type: application/x-ndjson" -H "Accept: application/json; indent=4;" \
--data-binary '@es_bulk_edit_data.json' --request POST \
"http://YOUR_ELASTICSEARCH_HOST:PORT_NUM/OPTIONAL_INDEX/OPTIONAL_TYPE/_bulk?pretty"
在request body文件中,同一个文档可能需要使用2个payload,一个是创建,更新字段,一个是脚本删除字段,可能是这样的:
// assume you attempt to add one field `artist`, update one field `num_views`,
// and delete one field `useless` in the document with type t1 and ID 123
{"update": {"_type": "t1", "_id": "123"}}
{"doc": {"artist": "new_artist", "num_views": 67}}
{"update": {"_type": "t1", "_id": "123"}}
{"script": {"source": "ctx._source.remove(params.del_field_name)", "lang":"painless", "params":{"del_field_name": "useless"}}}
注:
- 在批量 API 中,
doc
部分不能与 script
部分放在同一负载中,ElasticSearch 似乎拒绝处理此类负载结构和 return 错误响应 400 bad request
和原因消息将是 Validation Failed: 1: can't provide both script and doc;
。这就是为什么我在 2 个有效载荷中将删除和所有其他操作分开。
- 这些是在 5.6 和 6.6 版本上测试的,在最新版本 (v7.10) 中也应该得到相同的结果
PUT /products/_update/1
{
"docs" :{
"price": 12,
"quantity": 3,
"in_stock": 6
}
}
Now if I need to remove "quantity" then:
POST products/_update/1
{
"script": {
"source": "ctx._source.remove(\"quantity\")"
}
}
我想补充一下之前的答案,删除字段后,索引的大小不会改变。将不得不创建一个新索引或使用 _reindex api.
curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
{
"source": {
"index": "old-index"
},
"dest": {
"index": "new-index"
}}
'
我需要删除索引到 Elasticsearch 的所有文档中的一个字段。我该怎么做?
默认情况下这是不可能的,因为现在 Lucene 不支持它。基本上,您只能从 Lucene 索引中放置或删除整个 Lucene 文档。
- 获取文档的第一个版本
- 删除字段
- 推送您文档的这个新版本
此答案适用于 < ES 5 版本。
@backtrack 说的是真的,但是在 Elasticsearch 中有一种非常方便的方法可以做到这一点。 Elasticsearch 会将删除的内部复杂性抽象出来。 您需要使用更新 API 来实现此目的 -
curl -XPOST 'localhost:9200/test/type1/1/_update' -d '{
"script" : "ctx._source.remove(\"name_of_field\")"
}'
您可以找到更多文档 here。
注意:从 Elastic Search 6 开始,您需要包含 content-type header:
-H 'Content-Type: application/json'
Elasticsearch 在 2.3 中添加了 update_by_query
。此实验性界面允许您对与查询匹配的所有文档进行更新。
elasticsearch内部做一个scan/scroll收集批量文档,然后像批量更新接口一样更新。由于没有网络和序列化的开销,这比使用您自己的 scan/scroll 界面手动执行更快。每条记录都要加载到ram中,修改后再写入。
昨天我从我的 ES 集群中删除了一个大字段。在 update_by_query 期间,我看到了每秒 10,000 条记录的持续吞吐量,受到 CPU 而不是 IO 的限制。
如果集群有其他更新流量,请查看设置 conflicts=proceed
,或者当其中一个记录在其中一个批次下更新时,当它遇到 ConflictError
时整个作业将停止。
类似地设置wait_for_completion=false
将导致update_by_query通过tasks界面变为运行。否则,如果连接关闭,作业将终止。
url:
http://localhost:9200/INDEX/TYPE/_update_by_query?wait_for_completion=false&conflicts=proceed
POST正文:
{
"script": "ctx._source.remove('name_of_field')",
"query": {
"bool": {
"must": [
{
"exists": {
"field": "name_of_field"
}
}
]
}
}
}
自 Elasticsearch 1.43 起,内联 groovy scripting is disabled by default。您需要通过将 script.inline: true
添加到您的配置文件来启用它,这样的内联脚本才能工作。
或者将 groovy 作为脚本上传并使用 "script": { "file": "scriptname", "lang": "groovy"}
格式。
您可以使用_update_by_query
示例 1
索引:my_index
字段:user.email
POST my_index/_update_by_query?conflicts=proceed
{
"script" : "ctx._source.user.remove('email')",
"query" : {
"exists": { "field": "user.email" }
}
}
示例 2
索引:my_index
字段:total_items
POST my_index/_update_by_query?conflicts=proceed
{
"script" : "ctx._source.remove('total_items')",
"query" : {
"exists": { "field": "total_items" }
}
}
之前的答案对我不起作用。
我必须添加关键字“inline”:
POST /my_index/_update_by_query
{
"script": {
"inline": "ctx._source.remove(\"myfield\")"
},
"query" : {
"exists": { "field": "myfield" }
}
}
对于那些坚持 bulk API, the alternative to achieve deletion on field(s) of document(s) is to provide extra script in the update
action payload 批量 API 通话的人。
命令部分和官方文档描述的一样:
curl -s -H "Content-Type: application/x-ndjson" -H "Accept: application/json; indent=4;" \
--data-binary '@es_bulk_edit_data.json' --request POST \
"http://YOUR_ELASTICSEARCH_HOST:PORT_NUM/OPTIONAL_INDEX/OPTIONAL_TYPE/_bulk?pretty"
在request body文件中,同一个文档可能需要使用2个payload,一个是创建,更新字段,一个是脚本删除字段,可能是这样的:
// assume you attempt to add one field `artist`, update one field `num_views`,
// and delete one field `useless` in the document with type t1 and ID 123
{"update": {"_type": "t1", "_id": "123"}}
{"doc": {"artist": "new_artist", "num_views": 67}}
{"update": {"_type": "t1", "_id": "123"}}
{"script": {"source": "ctx._source.remove(params.del_field_name)", "lang":"painless", "params":{"del_field_name": "useless"}}}
注:
- 在批量 API 中,
doc
部分不能与script
部分放在同一负载中,ElasticSearch 似乎拒绝处理此类负载结构和 return 错误响应400 bad request
和原因消息将是Validation Failed: 1: can't provide both script and doc;
。这就是为什么我在 2 个有效载荷中将删除和所有其他操作分开。 - 这些是在 5.6 和 6.6 版本上测试的,在最新版本 (v7.10) 中也应该得到相同的结果
PUT /products/_update/1
{
"docs" :{
"price": 12,
"quantity": 3,
"in_stock": 6
}
}
Now if I need to remove "quantity" then:
POST products/_update/1
{
"script": {
"source": "ctx._source.remove(\"quantity\")"
}
}
我想补充一下之前的答案,删除字段后,索引的大小不会改变。将不得不创建一个新索引或使用 _reindex api.
curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
{
"source": {
"index": "old-index"
},
"dest": {
"index": "new-index"
}}
'