Elasticsearch 7:添加和更新文档


#Elasticsearch 笔记


在 ES 7 中新增索引:

PUT student
{
  "mappings" : {
    "properties" : {
      "name" : {
        "type" : "keyword"
      },
      "age" : {
        "type" : "integer"
      }
    }
  },
  "settings" : {
    "index" : {
      "number_of_shards" : 1,
      "number_of_replicas" : 0
    }
  }
}

使用 POST

POST 用于更新数据,如果不存在,则会创建。

添加数据示例1:

# 请求
POST student/_doc
{
  "name": "张三"
}

# 响应
{
  "_index" : "student",
  "_type" : "_doc",
  "_id" : "gCJ8Tm4Buf-uwlbZzC7C",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

添加数据示例2:

指定 _id 为 2。

# 请求
POST student/_doc/2
{
  "name": "李四"
}

# 响应
{
  "_index" : "student",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

一个错误的更新数据方式

# 请求
GET student/_doc/2

# 响应
{
  "_index" : "student",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 1,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "李四"
  }
}

可以看到没有 age 字段。

更新 age:

# 请求
POST student/_doc/2
{
  "age": 10
}

# 响应
{
  "_index" : "student",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}

再次请求数据:

GET student/_doc/2

# {
  "_index" : "student",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 2,
  "_seq_no" : 2,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "age" : 10
  }
}

结果是 version 从1变成了2,而 name 字段不见了。

原因是 POST student/_doc/2 这种语法的效果是覆盖数据。可以理解为先把原文档删除,再索引新文档。

POST student/_doc/2 的效果相同。

使用 _update 更新文档

如何在 name 不消失的情况下更新 age 呢?用 _update

示例:

# 请求1
POST student/_doc/2
{
  "name": "李四"
}

# 请求2: 新增 age
POST student/_doc/2/_update
{
  "doc": {
    "age": 10
  }
}

# 查询
GET student/_doc/2

# 查询结果
{
  "_index" : "student",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 6,
  "_seq_no" : 6,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "李四",
    "age" : 10
  }
}

POST student/_doc/2/_update 这种方式会报错:

#! Deprecation: [types removal] Specifying types in document update requests is deprecated, use the endpoint /{index}/_update/{id} instead.

所以,建议用下面的方法:

POST student/_update/2
{
  "doc": {
    "age": 11
  }
}

使用 _update 时,ES 做了下面几件事:

  1. 从旧文档构建 JSON
  2. 更改该 JSON
  3. 删除旧文档
  4. 索引一个新文档

使用 _update_by_query 更新文档

POST student/_update_by_query
{
  "query": { 
    "match": {
      "_id": 2
    }
  },
  "script": {
    "source": "ctx._source.age = 12"
  }
}

用下面的方法也行,但会有告警:

POST student/_update_by_query
{
  "query": { 
    "match": {
      "_id": 2
    }
  },
  "script": {
    "inline": "ctx._source.age = 12"
  }
}

执行时告警信息如下:

#! Deprecation: Deprecated field [inline] used, expected [source] instead

也就 inline 已经被废弃了,应该使用 source。 所以,最正确的方式是:

POST student/_update_by_query
{
  "query": { 
    "match": {
      "_id": 2
    }
  },
  "script": {
    "source": "ctx._source.age = 12"
  }
}


( 本文完 )