Elasticsearch教程 — Document APIs

Elasticsearch文档的操作可以理解成MySQL中的增删改查操作。

单个文档操作

# 索引中添加数据,如果目标索引的文档已存在,则更新文档并增加版本。当不指定id时为创建文档。
PUT  /<target>/_doc/<_id>
POST /<target>/_doc/
PUT  /<target>/_create/<_id>
POST /<target>/_create/<_id>

# 使用示例
POST my-index-000001/_doc/
{
  "@timestamp": "2099-11-15T13:12:00",
  "message": "GET /search HTTP/1.1 200 1070000",
  "user": {
    "id": "kimchy"
  }
}


# 查询文档
GET <index>/_doc/<_id> # 获取文档详情
HEAD <index>/_doc/<_id> # 使用 HEAD 验证文档是否存在
GET <index>/_source/<_id> # 获取文档
HEAD <index>/_source/<_id> # 验证文档是否存在
# 删除文档
DELETE /<index>/_doc/<_id>

# 更新文档
POST /<index>/_update/<_id>

POST test/_update/1
{
  "doc": {
    "name": "new_name"
  }
}

POST test/_update/1
{
  "script" : {
    "source": "ctx._source.counter += params.count",
    "lang": "painless",
    "params" : {
      "count" : 4
    }
  }
}

批量操作

# 从一个或多个索引中检索多个文档。如果在请求 URI 中指定索引,则只需在请求正文中指定文档 ID。
GET /_mget
GET /<index>/_mget

GET /_mget
{
  "docs": [
    {
      "_index": "testindex", # 如果在查询参数中没指定索引,这里就需指定索引
      "_id": "1", # 必须,文档id
      "_source": [ "field3", "field4" ] # 返回字段
    },
    {
      "_index": "testindex",
      "_id": "2",
      "_source": {
        "include": [ "user" ], # 返回的字段
        "exclude": [ "user.location" ] # 过滤字段
      }
    }
  ]
}

GET /my-index-000001/_mget
{
  "ids" : ["1", "2"]
}

# 在单个 API 调用中执行多个索引或删除操作。这减少了开销并且可以大大提高索引速度。
POST /_bulk
POST /<target>/_bulk
# 请求主体中包含的新行分隔的列表create,delete,index,和update行动及其相关的源数据。
# create(可选,字符串)创建文档,如果它不存在。下一行必须包含要建立索引的源数据。不过不存在_id那么自动生成id
# delete(可选,字符串)从索引中删除指定的文档。_id必须
# index(可选,字符串)替换指定文档。_id如果存在,则替换文档并增加版本。以下行必须包含要建立索引的源数据。_id如果不存在自动生成新文档
# update(可选,字符串)执行部分文档更新。以下行必须包含部分文档和更新选项。_id必须
# doc(可选,对象)要索引的部分文档。update操作的下一行所需。
# 批量API的响应包含请求中每个操作的单独结果,按提交的顺序返回。单个操作的成功或失败不会影响请求中的其他操作。

# 示例,注意其语法格式。
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }

# retry_on_conflict 指定一个更新应重试多少次
# 在update操作时,支持的选项包括 doc script lang params upsert doc_as_upsert _source
POST _bulk
{ "update" : { "_id" : "0", "_index" : "index1", "retry_on_conflict" : 3} }
{ "script" : { "source": "ctx._source.counter += params.param1", "lang" : "painless", "params" : {"param1" : 1}}, "upsert" : {"counter" : 1}}
{ "update" : {"_id" : "2", "_index" : "index1", "retry_on_conflict" : 3} }
{ "doc" : {"field" : "value"}, "doc_as_upsert" : true }

# 注意
# index/create 

# 删除查询到的文档
POST /<target>/_delete_by_query
# 更新查询到的文档
POST /<target>/_update_by_query

index/create

  第一步判断是确定插入的文档是否指定id,如果没有指定id,系统会默认生成一个唯一id。

  这种情况下,不管index还是create会直接add文档。如果用户指定了id,那么就会走update,update成本比add要高。

  第二步判断,会检查版本号是否冲突,只有正确的版本号才会执行插入,否则会插入失败。

  通过源码分析可以了解到,获取版本号的这个过程,是通过id来get文档,但无论是index还是create都不会get整个doc的全部内容,只是get出了版号。这也从一定程度上减少了系统开销。

总结:

  • 自动生成的 id,则 index/create 都采用 add 方式
  • 业务指定的 id,则 index/create 都采用 update 方式
  • 检查版本号是否冲突

update

  由于 Lucene 中的 update 其实就是覆盖替换,并不支持针对特定 Field 进行修改,Elasticsearch 中的 update 为了实现针对特定字段修改,在 Lucene 的基础上做了一些改动。

  每次 update 都会调用 InternalEngine 中的 get 方法,来获取整个文档信息,从而实现针对特定字段进行修改,这也就导致了每次更新要获取一遍原始文档,性能上会有很大影响。

  所以根据使用场景,有时候使用 index 会比 update 好很多。

index和create区别

  index 和 create 都会检查 _version 版本号。

  index 插入时分两种情况:

  • 没有指定 _version,那对于已有的doc,_version会递增,并对文档覆盖。
  • 指定_version,如果与已有的文档 _version 不相等,则插入失败;如果相等则覆盖,_version递增。

  create 插入时对于已有的文档,不会创建新文档,即插入失败,会抛出一个已经存在的异常。

用途解释:

  在批量请求的时候最好使用 create 方式进行导入。假如你批量导入一个大小为500MB 的文件,中途突然网络中断,可能其中有5万条数据已经导入,那么第二次尝试导入的时候,如果选用 index 方式,那么前5万条数据又会重复导入,增加了很多额外的开销,如果是 create 的话,elasticsearch 针对 bulk 操作机制是忽略已经存在的(当然在 bulk 完成后会返回哪些数据是重复的),这样就不会重复被导入了

相关文章

此处评论已关闭