elasticsearch 文档增删改

版本

版本内容基于elasticsearch-7.6.1。部分API可能会和低版本不一致,而且低版本的elasticsearch 支持多个type,7.0 之后已经移除type概念,默认情况下type有且只能有一个: _doc。 应该是为了兼容以前的版本,部分关于type的API依旧可以使用,通常还会会给出Deprecation提示。 在elasticsearch8.X中已经移除了类型(type)

创建文档

_index、_type(7.x 已固定)、_id三者唯一确定一个具体文档。 如同数据库数据一样,数据库库、表、主键值唯一确定一条数据。

对于elasticsearch 因为是分布式服务,没有提供自增主键,故需要我们手动指定主键ID或者 es使用特定算法生成主键

自动生成唯一_id

上面提到过 7.0后仅支持 _doc 这一种type, 实际使用时会发现依旧可以创建一个额外的type,但是会有Deprecation提示,不建议这么做,先以创建为例 自动生成ID 为例

7.0 以后
POST  person/_doc
{
    "name":"test",
    "age":256,
    "sex":"男"
}

返回结果

{
  "_index" : "person",
  "_type" : "_doc",
  "_id" : "F1YBNH8B6e0WzfSClmq1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}
7.0 版本之前
POST  person/doc
{
    "name":"test",
    "age":20,
    "sex":"男"
}

因为现在是elasticsearch-7.6.1 版本,故在Kibana上操作上述语句,则会出现以下提示。 但是依旧执行成功了

#! Deprecation: [types removal] Specifying types in search requests is deprecated, use the typeless endpoints instead (/{index}/_doc/{id}, /{index}/_doc, or /{index}/_create/{id})

{
  "_index" : "person",
  "_type" : "doc",
  "_id" : "FFbwM38B6e0WzfSCzGrE",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

使用搜索语句时也会提示 type 已移除

GET person/doc/_search

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

并且会发现使用 _doc 确实可以访问到数据

GET person/_doc/FFbwM38B6e0WzfSCzGrE
{
  "_index" : "person",
  "_type" : "_doc",
  "_id" : "FFbwM38B6e0WzfSCzGrE",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "test",
    "age" : 256,
    "sex" : "男"
  }
}
自定义 _id

这三种写法都支持PUT请求方式

第一种写法

POST  person/_create/2
{
    "name":"test",
    "age":256,
    "sex":"男"
}

返回结果

{
  "_index" : "person",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}
  • 当文档id不存在时,创建文档
  • 当文档Id存在时,抛出异常

第二种写法

POST person/_doc/1/_create

第三种写法

POST person/_doc/2?op_type=create

第四种写法
该方式, id不存在是创建文档,存在时更新文档

POST  person/_doc/2
{ "name":"test"}
异常

前三种方式调用多次,会抛出以下异常信息

version conflict, document already exists (current version [1])

因为如果ID已存在,再次调用则会报错。 状态码409

{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[2]: version conflict, document already exists (current version [1])",
        "index_uuid": "rkGDBwl6SCuWSX2UbrVm7Q",
        "shard": "0",
        "index": "person"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[2]: version conflict, document already exists (current version [1])",
    "index_uuid": "rkGDBwl6SCuWSX2UbrVm7Q",
    "shard": "0",
    "index": "person"
  },
  "status": 409
}

[2]: version conflict, document already exists (current version [1])

【2】中的就是自定义ID

批量插入

批量操作语法

POST _bulk
{"actionName":{"_index":"indexName","_type":"_doc", "_id":"id"}}
{"field1":"value1","field2":"value2"}

actionName 为操作类型:

  • create: 创建文档。文档id已存在会冲突抛出异常
  • index: 替换文档(创建|更新)。id已存在会替换
  • delete:删除文档
  • update: 局部更新

批量操作可以同时操作多个不同的索引。 如果是操作某个固定的索引,可以将索引添加中url中,同时在请求体中可以省略这一部分。

第一种写法

POST person/_bulk
{"index":{"_id":"6"}}
{"name":"a","age":25,"sex":"男"}
{"index":{"_id":"6"}}
{"name":"b","age":25,"sex":"女"}

id为6的数据执行了两次,两次执行都成功。且最后的结果为最后一条数据。

  "_source" : {
    "name" : "b",
    "age" : 25,
    "sex" : "女"
  }

第二种写法

POST person/_bulk
{"create":{"_id":"7"}}
{"name":"a","age":25,"sex":"男"}
{"create":{"_id":"7"}}
{"name":"b","age":25,"sex":"女"}

id为7 的执行了两此,第一条指定成功, 第二条执行失败

{
  "took" : 5,
  "errors" : true,
  "items" : [
    {
      "create" : {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "7",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 12,
        "_primary_term" : 3,
        "status" : 201
      }
    },
    {
      "create" : {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "7",
        "status" : 409,
        "error" : {
          "type" : "version_conflict_engine_exception",
          "reason" : "[7]: version conflict, document already exists (current version [3])",
          "index_uuid" : "QN2oJb_FSF-2ePQesU11aQ",
          "shard" : "0",
          "index" : "person"
        }
      }
    }
  ]
}
删除文档
DELETE  person/_doc/1

同样的7.0后的版本, 如果指定了其他 type类型。删除会存在提示

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

批量删除

第一种写法

POST person/_bulk
{"delete":{"_id":1}}
{"delete":{"_id":2}}
{"delete":{"_id":3}}

POST _bulk
{"delete":{"_index":"person","_id":1}}
{"delete":{"_index":"person","_id":2}}
{"delete":{"_index":"person","_id":3}}

第二种写法

批量删除符合特定查询条件的文档

POST person/_delete_by_query
{
  "query":{
    "term": {
      "age": {
        "value": 256
      }
    }
  }
}
更新文档
单文档更新
覆盖更新
POST person/_doc/2
{
    "name":"test2",
    "age":28,
    "sex":"男",
    "address":"山东"
}

更新操作结果

{
  "_index" : "person",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 6,
  "_primary_term" : 1
}

该操作 实际的功能是upsert, id不存在时新增,id存在时更新。 可以通过返回的数据判断是何种操作,

“result”: “updated” , 更新操作
“result”: “created”, 新增操作

局部更新

如果文档包含数据特别多,信息量比较大,仅仅只是更改某个字段,却需要把整个文档数据传输过去,无疑是不合理的。 比如更新user 表的age字段,却要把user的全部字段信息都传递,造成了无意义的带宽浪费。

当然这个更新不仅仅是对已有字段的更新,还可以添加之前不存在的字段
语法一
更新文档2 的sex为 女

POST person/_update/2
{
  "doc":{
    "sex" :"女"
  }
}

语法二
添加一个手机号字段

POST /person/doc/2/_update

{
    "doc": {
        "phone": "12345678901"
    }
}

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

当使用其他类型时,可以看到这种方式已经不推荐

经过上述的操作,现在文档结果为:

{
  "_index" : "person",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 4,
  "_seq_no" : 8,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "test2",
    "age" : 28,
    "sex" : "女",
    "phone" : "11111111"
  }
}
批量更新

相对的批量更新也分为局部和全局更新两种。

一般来说局部更新用的更多一些, 比如新增字段, city

批量覆盖更新

POST person/_bulk
{"index":{"_id":"6"}}
{"name":"a","age":25,"sex":"男", "city":"临沂"}

批量局部更新

POST person/_bulk
{"update":{"_id":"6"}}
{"doc":{"city":"临沂"}}
总结

在 7.0以后的版本,推荐使用以下API

新增
  1. 自动生成ID
    根据REST定义PUT请求是幂等操作。如下API每次调用都会生成新的文档,故必须是POST请求
    POST user/_doc
    
  2. 自定义ID
    POST /PUT 都可以
    POST user/_doc/1
    
    POST  user/_create/2
    
    POST  user/_doc/3/_create
    
  3. 批量插入
    POST person/_bulk
    {"index":{"_id":"6"}}
    {"name":"a","age":25,"sex":"男"}
    
    或者如下
    POST _bulk
    {"index":{"_index":"person","_id":"6"}}
    {"name":"a","age":25,"sex":"男"}
    
更新
  1. 覆盖更新
    POST user/_doc/1
    
  2. 局部更新
    POST  user/_update/1
    {
    	"doc":{
    		"filed_name" :"filed_value"
    	}
    }
    
  3. 批量更新
    POST person/_bulk
    {"index":{"_id":"6"}}
    {"name":"a","age":25,"sex":"男"}
    
  4. 批量局部更新
    POST person/_bulk
    {"update":{"_id":"6"}}
    {"doc":{"sex":"女"}}
    
删除
  1. 删除单个文档

    DELETE  user/_doc/1
    
  2. 批量删除

    POST user/_delete_by_query
    
    POST _bulk
    {"delete":{"_index":"person","_id":1}}
    
其他异常

mapper_parsing_exception: failed to parse field [age] of type [long] in document with id ‘2’. Preview of field’s value: ‘q1’

当创建索引时, 如果未指定字段类型。 那么Elasticsearch为对字段类型进行猜测,动态生成了字段和类型的映射关系。

GET   person/_mapping
{
  "person" : {
    "mappings" : {
      "properties" : {
        "age" : {
          "type" : "long"
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "phone" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "sex" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}   

可以看到 age 类型为long 类型。当我试图把age修改为非数字的字符串时,则会报错。 es会先尝试把字符串解析成数字

POST person/_update/2
{
  "doc":{
    "age":"q1"
  }
}
{
  "error": {
    "root_cause": [
      {
        "type": "mapper_parsing_exception",
        "reason": "failed to parse field [age] of type [long] in document with id '2'. Preview of field's value: 'q1'"
      }
    ],
    "type": "mapper_parsing_exception",
    "reason": "failed to parse field [age] of type [long] in document with id '2'. Preview of field's value: 'q1'",
    "caused_by": {
      "type": "illegal_argument_exception",
      "reason": "For input string: \"q1\""
    }
  },
  "status": 400
}

参看文档: elasticsearch 官方文档

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值