Index API

index api用来新增文档,支持如下几种方式:

# 指定id创建,如果id已存在,则会进行更新,`_version` + 1
PUT {index}/_doc/{id}# 强制创建,如果id已经存在,409错误(以下二者等价)
PUT {index}/_doc/{id}?op_type=create
PUT {index}/_create/{id}# POST创建,自动生成ID
POST {index}/_doc/

指定ID请求方式为PUT,自动生成ID的请求方式为POST

具体示例:

// 示例1 往"twitter"中插入文档,指定id是1
PUT twitter/_doc/1
{"user" : "Jack","post_date" : "2019-05-15T14:12:12","message" : "trying out Elasticsearch"
}

结果:

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

_shards字段提供了索引操作的副本处理信息:

  • total 应执行的分片数
  • successful 成功执行的分片数
  • failed 失败数

只要successful的值至少为1,那么索引操作就是成功了。

id已经存在的情况下会执行更新操作:

PUT twitter/_doc/1
{"user" : "Jack2","post_date" : "2019-05-15T14:12:12","message" : "trying out Elasticsearch"
}
  "_index" : "twitter","_type" : "_doc","_id" : "1","_version" : 2,"result" : "updated","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 2,"_primary_term" : 1
}

自动创建索引

通过索引插入文档时,如果索引(集)不存在,比如上述的twitter,将会自动创建索引。当然我们可以修改这个设定:

PUT _cluster/settings
{"persistent": {"action.auto_create_index": "false" // false 禁止 true 允许}
}

action.auto_create_index的值支持更为复杂的设定,比如:

"action.auto_create_index": "twitter, facebook,-tieba,+topic*"

+是允许,-是禁止,*是通配符。

以上配置的含义是,允许为twitter, facebook, 以及任何匹配topic*的自动创建索引,禁止为tieba创建索引。

操作类别

索引操作可以接收op_type参数,来强制进行create操作,允许如果确实就修改(put-if-absent)的行为。当指定create时,如果文档的id在索引集中已存在,那么索引操作失败。

示例:

PUT twitter/_doc/1?op_type=create
{"user" : "kimchy","post_date" : "2009-11-15T14:12:12","message" : "trying out Elasticsearch"
}
{"error": {.......},"status": 409
}

op_type=create也可以使用如下方式,二者效果是一样的:

PUT twitter/_doc/1?op_type=create  <=>  PUT twitter/_create/1

自动生成ID

索引操作时如果不指定ID,将自动生成,并且会默认op_typecreate,注意,请求方式是POST

POST twitter/_doc/
{"user" : "kimchy","post_date" : "2009-11-15T14:12:12","message" : "trying out Elasticsearch"
}
{"_index" : "twitter","_type" : "_doc","_id" : "A6y0umsBAkV3IICsYCLL","_version" : 1,"result" : "created","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 1,"_primary_term" : 1
}

Get API

get api根据id,从索引(集)中获取JSON文档,支持如下几种方式

# 获取文档及元信息
GET {index}/_doc/{id}# 仅获取文档字段,不包含元信息
GET {index}/_source/{id}

以上两种方式都支持字段过滤。

示例:

GET twitter/_doc/1
{"_index" : "twitter","_type" : "_doc","_id" : "1","_version" : 2,"_seq_no" : 2,"_primary_term" : 1,"found" : true,"_source" : {"user" : "Jack2","post_date" : "2019-05-15T14:12:12","message" : "trying out Elasticsearch"}
}

如果没找到,返回:

{"_index" : "twitter","_type" : "_doc","_id" : "1","found" : false
}

我们也可以发一个HEAD请求,来查询文档是否存在:

HEAD /twitter/_doc/0
200 - OK  # 存在
404 - Not Found  # 不存在

字段过滤

get操作默认会返回_source字段的所有内容一级文档的元信息,除非你指定stored_fields参数,或者禁用_source字段:

GET twitter/_doc/1?_source=false
{"_index" : "twitter","_type" : "_doc","_id" : "1","_version" : 2,"_seq_no" : 2,"_primary_term" : 1,"found" : true
}

如果,你只需要_source字段中某几个字段,你可以使用如下两个参数指定:

  • _source_includes 指定包含字段,字段间以,号分隔
  • _source_excludes指定丢弃字段,字段间以,号分隔
  • 以上两个参数可以通过&连接一起使用
GET twitter/_doc/2?_source_includes=user,message&_source_excludes=date

如果只是需要指定包含字段,可以简化为_source

GET twitter/_doc/1?_source=user,message
{"_index" : "twitter","_type" : "_doc","_id" : "1","_version" : 2,"_seq_no" : 2,"_primary_term" : 1,"found" : true,"_source" : {"message" : "trying out Elasticsearch","user" : "Jack2"}
}

字段过滤可以节省网络开销。

Stored Fields

创建索引(集)facebook, 并定义mappings

put facebook
{"mappings": {"properties": {"counter": {"type": "integer","store": false},"tags": {"type": "keyword","store": true}}}
}

插入一个文档:

PUT facebook/_doc/2
{"counter": 1,"tags": ["red"]
}

检索刚插入的文档,通过stored_fields参数指定字段:

GET facebook/_doc/2?stored_fields=tags,counter
{"_index" : "facebook","_type" : "_doc","_id" : "2","_version" : 1,"_seq_no" : 1,"_primary_term" : 1,"found" : true,"fields" : {"tags" : ["red"]}
}

由于counter字段在mappings中store: false,当进行检索时,将忽略该字段。

仅获取_source内容

使用{index}/_source/{id}可以仅获取文档的_source字段内容:

GET twitter/_source/1
{"user" : "Jack2","post_date" : "2019-05-15T14:12:12","message" : "trying out Elasticsearch"
}

也可以通过HEAD请求检测文档的_source是否存在。另外,如果在mapping中禁用了_source,存在的文档也不存在_source

HEAD twitter/_source/1

Multi Get API

multi get 支持一次请求,查询多个文档,形式如下:

# 可以从多个索引中查询,需要分别指定_index和_id
GET /_mget# 指定索引,可以直接指定ids
GET /{index}/_mget

示例1:

GET /_mget
{"docs": [{"_index": "twitter","_id": "1"},{"_index": "facebook","_id": "2"}]
}

说明:

  • 查询条件放在docs字段的列表中
  • 可以基于index, id进行查询。基于type查询"_type" : "_doc" 在7.x中已废弃,不需要传_type条件
  • GET /_mget或者_mget都行(其他请求也是,/不影响)

返回结果放在docs字段的列表中

{"docs" : [{"_index" : "twitter","_type" : "_doc","_id" : "1","_version" : 2,"_seq_no" : 2,"_primary_term" : 1,"found" : true,"_source" : {"user" : "Jack2","post_date" : "2019-05-15T14:12:12","message" : "trying out Elasticsearch"}},{"_index" : "facebook","_type" : "_doc","_id" : "2","_version" : 1,"_seq_no" : 1,"_primary_term" : 1,"found" : true,"_source" : {"counter" : 1,"tags" : ["red"]}}]
}

示例2:

GET twitter/_mget
{"docs": [{"_id": "1"},{"_id": "2"}]
}

在上面这种情况,只根据id过滤时,可以简写如下:

GET twitter/_mget
{"ids": ["1", "2"]  // ids字段
}

字段过滤

可以通过_source参数指定返回的字段:

GET _mget
{"docs": [{"_index": "twitter","_id": "1","_source": false},{"_index": "twitter","_id": "2","_source": ["user", "message"]},{"_index": "facebook","_id": "2","_source": {"include": ["counter"],"exclude": []}}]
}

也可以通过stored_fields来指定。

Update API

update api允许基于脚本更新文档,每次修改后,_version + 1, 基本方式:

# 基于script更新
POST {index}/_update/{id}
{"script": {...}
}# 基于文档更新,doc中的字段将会自动与目标文档合并
POST {index}/_update/{id}
{"doc": {...}
}

脚本更新

首先我们插入一个文档:

PUT facebook/_doc/3
{"counter": 1,"tags": ["red"]
}

下面执行更新脚本:

script 1: 增加counter

POST facebook/_update/3
{"script": {"source": "ctx._source.counter += params.count","lang": "painless",  // 使用painless函数"params": {"count": 4}}
}

script 2: 添加tags元素

POST facebook/_update/3
{"script": {"source": "ctx._source.tags.add(params.tag)","lang": "painless","params": {"tag": "blue"}}
}

script 3: 移除tags元素

POST facebook/_update/3
{"script": {"source": "if(ctx._source.tags.contains(params.tag)){ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag))}","lang": "painless","params": {"tag": "red"}}
}

查看最终结果:

{"_index" : "facebook","_type" : "_doc","_id" : "3","_version" : 4,"_seq_no" : 5,"_primary_term" : 1,"found" : true,"_source" : {"counter" : 5,"tags" : ["blue"]}
}

文档更新

更新请求体中使用doc字段传递一个文档,该文档就会与目标文档进行合并

POST facebook/_update/3
{"doc": {"name": "wahaha"}
}

由于目标文档不存在name字段,合并后将会新增name字段。

noop更新

如果更新没有改变任何东西,将返回noop结果,_version不变。比如讲上述文档更新执行两次,第二次将得到如下结果:

{"_index" : "facebook","_type" : "_doc","_id" : "3","_version" : 5,"result" : "noop","_shards" : {"total" : 0,"successful" : 0,"failed" : 0}
}

当然你也可以禁止noop结果:

POST facebook/_update/3
{"doc": {"name": "wahaha"},"detect_noop": false  // 禁止
}

再次执行同样的更新,_version 将 +1

Upserts

存在则更新,不存在则创建:

POST facebook/_update/5
{"script": {  // 更新脚本"source": "ctx._source.counter += params.count","lang": "painless","params": {"count": 4}},"upsert": {  // 如果目标文档不存在,以upsert中的内容创建新的文档"counter": 1}
}

scripted_upsert

如果希望脚本不论目标文档是否存在都执行,可以指定scripted_upserttrue,这样脚本将代替upsert字段执行初始化文档。官网示例本地无法执行,暂不讨论。

doc_as_upsert

适用于文档更新的upsert操作:

POST facebook/_update/6
{"doc": {"name": "wahaha"},"doc_as_upsert": true
}

请求参数

更新操作还支持查询字符串参数,具体参见官网:<https://www.elastic.co/guide/en/elasticsearch/reference/7.2/docs-update.html#_parameters_2>

Update By Query API

_update_by_query适用于执行对索引(集)中全部文档的更新,比如添加新的字段,或者其他mapping更改。该操作也可以指定条件,只对特定文档进行更新。

POST {index}/_update_by_query

https://www.elastic.co/guide/en/elasticsearch/reference/7.2/docs-update-by-query.html

Delete API

用于从索引中删除文档,用法如下:

DELETE {index}/_doc/{id}

比如,从twitter中删除id为1点文档:

DELETE twitter/_doc/1

返回响应:

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

Delete By Query API

该接口可以实现删除一个索引中的所有文档:

POST {index}/_delete_by_query

当然也支持指定筛选条件,实现部分删除。
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/docs-delete-by-query.html

Bulk API

bulk api允许在一次接口调用中,实现多个增删改操作

POST /_bulk
{ "index" : { "_index" : "facebook", "_id" : "2" } }
{ "connter" : 2 }  // index的source
{ "delete" : { "_index" : "twitter", "_id" : "2" } }
{ "create" : { "_index" : "twitter", "_id" : "7" } }
{ "name" : "seven" }  // create的source
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }  // update的doc

说明:

  • index 和 create操作需要在紧接着的下一行提供source,以便进行添加文档,或者更新
  • delete不需要source
  • update需要在下一行指定doc,upsert, script等细节

返回结果:

{"took" : 217,"errors" : true,"items" : [{"index" : {  // 第一个index因为id已经存在,于是根据source更新了文档的内容"_index" : "facebook","_type" : "_doc","_id" : "2","_version" : 4,"result" : "updated","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 14,"_primary_term" : 1,"status" : 200}},{"delete" : {  // 第二个delete没找到目标文档"_index" : "twitter","_type" : "_doc","_id" : "2","_version" : 1,"result" : "not_found","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 8,"_primary_term" : 1,"status" : 404}},{"create" : {  // 第三个以给出的source成功创建文档"_index" : "twitter","_type" : "_doc","_id" : "7","_version" : 1,"result" : "created","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 9,"_primary_term" : 1,"status" : 201}},{"update" : {  // update指定的index不存在,返回404"_index" : "test","_type" : "_doc","_id" : "1","status" : 404,"error" : {"type" : "document_missing_exception","reason" : "[_doc][1]: document missing","index_uuid" : "k7zYEGp8ROuGWkfOprCKvQ","shard" : "0","index" : "test"}}}]
}

Reindex API

reindex最基本的用法是将一个索引中的文档拷贝到另一个文档:

POST _reindex
{"source": {"index": "{index1}"},"dest": {"index": "{index2}"}
}

https://www.elastic.co/guide/en/elasticsearch/reference/7.2/docs-reindex.html

并发控制

Elasticsearch是分布式的。创建,修改,删除文档后,新版的文档必须复制到集群内的其他节点。Elasticsearch同时也是异步和并发的,意味着这些复制请求是并行发送的,不能保证到达目的地的顺序。因此ES需要一种方式确保旧版本的文档不会覆盖较新的文档。

对文档的每次操作都会由主分片(primary shard)分配一个序号,每次操作文档都会增大序号。ES通过序号判断文档的新旧,保证旧文档不会覆盖新文档。

GET获取文档时,可以查看到序号:

{"_index" : "twitter","_type" : "_doc","_id" : "2","_version" : 1,"_seq_no" : 5,  // 序号"_primary_term" : 1, // 主条目"found" : true,"_source" : {"user" : "Jack2","post_date" : "2019-05-15T14:12:12","message" : "trying out Elasticsearch"}
}

因此,通过记下返回的_seq_no_primary_term,可以确保你仅在检索到文档且未有其他任何对该文档的更改时,才更改该文档,比如:

DELETE twitter/_doc/2?if_seq_no=5&if_primary_term=1

如果在删除前,发生了对该文档的其他修改,删除操作将会失败:409响应,并提示版本冲突。

关于文档读写

ES中的每个索引(集)都被分散到分片上,每个分片可以有多个副本。当进行文档添加或移除时,副本必须保持同步。保持分片副本同步并提供读取服务的过程,就是数据副本模型。
ES的数据副本模型基于主备模型。该模型中,某个副本作为主分片(primary shard),其他副本充当副本分片(replica shard)。主分片作为所有索引操作的主入口,负责验证并确保它们是正确的,并将操作复制到其他副本。

基本写模型

ES中的每个索引操作首先通过路由(routing)解析到一个副本组,这通常是基于文档ID。副本组确定后,操作将在内部转发到当前的主分片上。主分片负责验证操作并转发给其他副本。因为副本可以脱机,所以主分片不必复制给所有副本。事实上,es会维护一个接收操作的副本列表,称之为同步副本,并由主节点维护。主分片必须保证将所有的操作复制到同步副本中每个副本。主分片遵循如下基本流程:

  1. 验证操作,比如字段是否相符
  2. 本机执行操作,比如索引或删除相关文档,必要时也会拒绝,比如一个keyword值过长,以至于无法在Lucene中索引
  3. 转发操作给当前同步副本组中的每个副本(并行操作)
  4. 一旦所有副本成功执行了操作并报告给主分片,主分片就会确认成功完成了客户端的请求。

失败处理

索引时可能会出错,比如磁盘故障,节点丢失,或者配置错误。主分片需要对此进行处理。

如果主分片自身故障了,那么其所在的节点将通知主节点。索引操作将最多等待1分钟,直到主节点将某个副本提升为新的的主分片。然后操作被转发到新的主分片进行处理。

在主分片成功执行了操作,副本出错的情况下(比如副本本身故障或者网络问题),主分片将请求主节点将故障副本从同步副本中移除。

基本读模型

在ES中,读取可以是根据id的非常轻量级的查找,也可以是具有复杂聚合,占用cpu的搜索请求。主备模型的优点是所有分片副本保持一致,因此每个副本都能提供读取请求。

处理当前客户端请求的节点称为协调节点(coordinating node),基本流程如下:

  1. 解析请求到相关的分片上。因为大多数搜索会被发送到一个或多个索引,因此需要从多个分片进行读取,每个分片代表数据的不同子集。
  2. 从相关分片的副本组中选取一个副本,这可以是主分片,也可以是副本分片(默认情况下es在会轮流选择)
  3. 发送读取请求给选中的副本
  4. 合并结果并响应。如果是通过id查找,因为只有一个相关分片,所以这步会被跳过。

分片失败

当某个分片响应读取请求时,协调节点将请求发往同一副本组的另一个分片。多次失败会导致没有可用的分片。

为了确保快速响应,下列API在出现分片失败时,会返回部分结果:

  • Search
  • Multi Search
  • Bulk
  • Multi Get

这时仍然是200响应,但是通过time_out_shards字段可以知道出现了分片失败。

Document API相关推荐

  1. document api java_GitHub - liuanxin/api-document: java spring-mvc document collect

    说明 维护过项目的人应该都有体会, 如果接口文档是单独编写的(org-mode.markdown.rap 甚至是 word 等), 随着项目周期的推进, 接口文档和真实代码之间的差距会越来越远. 基于 ...

  2. elasticsearch使用指南之Elasticsearch Document Index API详解、原理与示例

    作者介绍:<RocketMQ技术内幕>作者,中间件兴趣圈微信公众号维护者. 本节将重点介绍ElasticSearch Doucment Index API(新增索引). 从上节可知,Ela ...

  3. Android中所有API和对应权限的数据结构构建

    #写在前面的话 这是一篇有毒博客,我觉得,读者慎入. 我想说,那个最底下的广告怎么去,辣眼睛- T -T 当然,你也可以帮我点下我的,在这里跪谢大家 https://www.captainbed.ne ...

  4. 在nodejs环境里使用浏览器环境下的document对象

    我用nodejs写了一个简单的简书文章导出工具,将我本人的简书问题连同标题和超链接导出到本地. 我用nodejs向如下的url发起http请求,返回的响应是html格式的,每篇文章的明细包含在html ...

  5. 新浪微博、腾讯微博、QQ空间、人人网、豆瓣 一键分享API

    转载链接:http://www.bluesdream.com/blog/sina-tencent-renren-douban-share-a-key-api.html 新浪微博: http://ser ...

  6. 调用SMS腾讯云短信验证码API的几个坑,及详细使用流程

    前言 首先说下,几个坑已解决.准备说一下.使用的一些步骤 因为项目有一个短信验证码登录注册的,首先注册的是阿里的.但是审核没有审核通过,所以有注册了腾讯的 本来向截图一下阿里的,结果登录出错了,这里就 ...

  7. Search API

    Search 搜索条件可以通过查询字符串,也可以在请求体中传递. 搜索接口支持从多个索引中查找文档vj. 基本格式: # 单索引内检索文档 GET /{index}/_search?q={field} ...

  8. DevExpress v18.2版本亮点——Office File API 篇

    行业领先的.NET界面控件--DevExpress v18.2版本亮点详解,本文将介绍了DevExpress Office File API v18.2 的版本亮点,新版30天免费试用!点击下载> ...

  9. python调用腾讯自然语言处理api

    腾讯产品首页:https://cloud.tencent.com/product 开通服务 进入网站:https://console.cloud.tencent.com/nlp,扫微信登录腾讯云,点击 ...

最新文章

  1. Python_基础_3
  2. 字符串Hash的原理与应用
  3. idea创建maven web项目需要注意的一些细节
  4. java 子进程id,Java程序如何获得自己的进程ID?
  5. java写exe程序实例_2012软考软件设计师辅导:利用JAVA执行本地EXE文件
  6. C语言递归算法(二)
  7. 写论文的第三天 自建zookeeper集群
  8. 关于Mysql8.0.26版本与IDEA连接的配置
  9. 电脑鼠标失控自己乱点_在这款沙盒游戏里,你只需要乱点鼠标就能成为建筑艺术家...
  10. 浙江学计算机怎么选课,新高考下浙江孩子应怎么选课(专业人士建议)
  11. 网易2012校园招聘笔试题目
  12. 如何利用Matlab对指定条件下的excel单元格填充颜色
  13. linux nodejs 502错误,node.js应用程序与nginx 502错误的网关错误
  14. 首席新媒体运营商学院创始人黎想:给新媒体运营的7点建议
  15. 数据库设计3个泛式和经验谈
  16. Android6.0风格图标,jQuery仿Android样式扁平风格图标插件
  17. 什么是数据中台系统 - whale帷幄
  18. 视频号运营玩法;以及视频号引流变现赚钱。丨国仁网络资讯
  19. Python:警告 的11种情况
  20. 微服务项目部署服务器,第3章 3.2 部署服务器 - 编排多个微服务

热门文章

  1. (计算机组成原理)第一章计算机系统概述-第一节:计算机发展历程
  2. PyQt5学习笔记05----Qt Designer信号槽
  3. hdoj4710 规律题
  4. C语言中二维数组名与数组地址、首行地址、首行首元素地址关系与区别详解(初学者必须掌握)
  5. uboot主Makefile之9——2589行 x210_sd_config目标
  6. Largest Number 179
  7. 使用FontAwesome
  8. MySQL保留关键字
  9. ASP.NET组件设计Step by Step(8)
  10. postgresql,pgadmin4安装后出错,界面只有文字