从 Elasticsearch 文档中删除字段

Remove a field from a Elasticsearch document

我需要删除索引到 Elasticsearch 的所有文档中的一个字段。我该怎么做?

默认情况下这是不可能的,因为现在 Lucene 不支持它。基本上,您只能从 Lucene 索引中放置或删除整个 Lucene 文档。

  1. 获取文档的第一个版本
  2. 删除字段
  3. 推送您文档的这个新版本

此答案适用于 < 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"
}}

'