ElasticSearch
- 一 ElasticSearch
- 二 Elasticsearch的核心概念
-
- 2.1 Lucene和ElasticSearch的前世今生
- 2.2 elasticsearch的核心概念
- 2.3 full-text search(全文检索)
- 2.4 phrase search (短语搜索)
- 2.5 elasticsearch 聚合分析
- 2.6 ES的基础分布式结构
- 2.7 primary&replica shard
- 2.8 ES横向扩容
- 2.9 ES容错机制
- 2.10 ES _index/_type/_id 元数据介绍
- 2.11 ES id生成的两种方式
- 2.12 _source元数据
- 2.13 document的全量替换、强制创建、删除
- 2.13 ES并发冲突
- 2.14 ES内部如何基于_version进行乐观锁并发控制
- 2.15 partial update实现原理
- 2.16 mget 批量查询
- 2.17 bulk 批量增删改
- 2.18 distributed document system
- 2.19 初识搜索引擎
-
- search 结果深入解析
- 分页搜索与deep paging性能问题
- 快速掌握query string search
- mapping
- 精确匹配与全文搜索的对比分析
- 倒排索引
- 分词器的内部组成
- query string的分词以及mapping
- mapping
- dynamic mapping
- 手动建立mapping以及定制string类型数据是否分词
- mapping复杂数据类型以及object类型数据底层结构
- search api的基础语法
- Query DSL搜索语法
- query与filter深入对比解密:相关度、性能
- query常用搜索语法
- 多搜索条件组合查询
- 如何定位不合法的搜索及其原因
- 定制搜索结果的排序规则
- 如何将一个field索引两次来解决字符串排序问题
- 相关度评分TF&IDF算法
- 内核级知识点之doc _value
- 内核级知识点之query phase
- 内核级知识点之fetch phase
- 搜索相关参数梳理以及bouncing results问题解决方案
- scoll技术滚动搜索大量数据
- 2.20 索引管理
- 2.21 内核原理
- Elasticsearch顶尖高手系列-快速入门篇原视频
一 ElasticSearch
1.1 全文检索,倒排索引
倒排索引:给每一个数据都设定一个id,倒排索引看起来类似下图,是将每一个词条都拆开来,将所有的拆出来的词全部排列,建立倒排索引,搜索的时候也会将搜索词进行拆分,然后将拆分后的词放入倒排索引进行查询
倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引。通俗地来讲,正向索引是通过key找value,反向索引则是通过value找key。
利用倒排索引进行全文索引,假设100万条数据,拆分出来的词语,假设有100万个词语,那么在倒排索引中,就有1000万行,优化搜索算法,有可能快速的查询到想要查询的词 。
1.2 Lucene
就是一个jar包,里面包含了封装好的各种建立倒排索引,以及进行搜索的代码,包括各种算法。一般就用Java开发时,引用Lucene jar,基于Lucene的api进行开发就可以了。我们就可以去将已有的数据建立索引,Lucene会在本地磁盘上面,给我们组织索引的数据结构。另外的话,我们也可以用Lucene提供的一些功能和api来针对磁盘上的索引数据,进行搜索。
1.3 什么是ElasticSearch
Lucene封装了搜索引擎的功能
ElasticSearch 底层会封装Lucene,elasticSearch是多个节点
es的特点和优点:
1.自动维护数据的冗余副本,保证数据不丢失,由于宕机
2.封装了Lucene,提升高级api,能快速开发复杂的功能
3.基于地理位置的搜索,搜索距离我当前一公里的烤肉店
4.自动维护数据的分布到多个节点的索引的建立,还有搜索请求分布到多个节点的执行
Elasticsearch 分布式,高可用,可伸缩,高性能
1.4 Elasticsearch的功能
1)分布式的搜索引擎和数据分析引擎
搜索:百度,网站的站内搜索,IT系统的检索
数据分析:电商网站,最近七天牙膏这种商品销量排名前十的商家有哪些
分布式,搜索,数据分析
2)全文检索,结构化检索,数据分析
全文检索:我想搜索商品名称包含牙膏的商品 like
结构化搜索:我想搜索商品分类为日化用品的商品有哪些 =
部分匹配,自动完成,搜索纠错,搜索推荐
数据分析:我想分析每一个商品分类下有多少个商品 group by
3)对海量数据进行近实时的处理
分布式:ES自动可以将海量数据分散到多台服务器上存储和检索
海量数据的处理:分布式以后,就可以采用大量的服务器和检索数据,自然而然就可以实现海量数据的处理了
近实时:在秒级别对数据进行搜索和分析
跟分布式/海量数据相反的:lucene,单机应用,只能在单台机器上使用,最多只能处理单台服务器的数据量
1.5 elasticsearch的适用场景
维基百科
国外新闻网站,类似搜狐新闻
Stack Overflow
GitHub
电商网站
日志数据分析,Logstash采集日志,es进行复杂的数据分析
商品价格监控网站,用户设定某商品的价格阈值的时候,发送通知消息给用户
BI系统,ES执行数据分析和挖掘,Kibana进行数据可视化
1.6 elasticsearch的特点
- 可以作为一个大型分布式集群(数百台服务器)技术,处理PB级数据
- Elasticsearch不是什么新技术,主要是将全文检索、数据分析以及分布式技术,合并成了独一无二的ES
- 对用户而言,是开箱即用的,非常简单,作为中小型的应用,直接3分支部署一下es,就可以作为生产环境的系统来使用,数据量不大,操作不是太复杂
- 数据库的功能面对很多领域是不够用的(事务,还有各种联机事务型操作);特殊的功能,比如,相关度排名,复杂数据分析,海量数据的近实时处理;Elasticsearch作为传统数据库的一个补充,提供了数据库所不能提供的很多功能
二 Elasticsearch的核心概念
2.1 Lucene和ElasticSearch的前世今生
Lucene:最先进、功能最强大的搜索库,直接基于Lucene开发,非常复杂,api复杂,需要深入理解原理
elasticsearch,基于Lucene,隐藏复杂性,提供简单易用的restful api接口、java api接口(还有其他语言的api接口)
- 分布式文档存储引擎
- 分布式的搜索引擎和分析引擎
- 分布式,支持PB级数据
开箱即用,优秀的默认参数,不需要任何额外设置,完全开源
2.2 elasticsearch的核心概念
Near Realtime(NRT):近实时,两个意思,从写入数据到数据可以被搜索到有一个延迟(大概1秒);基于es执行搜索和分析可以达到秒级
cluster:集群,包含多个节点,每个节点属于哪个集群是通过一个配置(集群名称,默认是elasticsearch)来决定的,对于中小型应用来说,刚开始一个集群就一个节点很正常
Node:节点,集群中的一个节点,节点也有一个名称(默认随机分配的),节点名称很重要(在执行运维管理操作的时候),默认节点会去加入一个名称为“elasticsearch”的集群,如果直接启动一堆节点,那么它们会自动组成一个elasticsearch集群,当然一个节点也可以组成一个elasticsearch集群
Document:文档,es中最小数据单元,一个document可以是一条客户数据,通常用JSON数据结构表示,每个Index下的type中,都可以存储多个document,一个document里面有多个field,每个field就是一个数据字段
Index:索引,包含一堆有相似的文档数据,比如可以有一个客户索引,商品分类索引,订单索引。
Type:类型,每个索引里都可以有一个或多个type,type是index中的一个逻辑数据分类,一个type下的document,都有相同的field。
shard:单台机器无法存储大量数据,es可以将一个索引中的数据切分为多个shard,分布在多台服务器上存储。有了shard就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。每个shard都是一个lucene index。
replica:任何一个服务器随时可能故障或宕机,此时shard可能就会丢失,因此可以为每个shard创建多个replica副本。replica可以在shard故障时提供备用服务,保证数据不丢失,多个replica还可以提升搜索操作的吞吐量和性能。primary shard(建立索引时一次设置,不能修改,默认5个),replica shard(随时修改数量,默认1个),默认每个索引10个shard,5个primary shard,5个replica shard,最小的高可用配置,是2台服务器。
2.3 full-text search(全文检索)
get /ecommerce/product/_search
{
"query": {
"match": {
"producer": "yagao producer"
}
}
}
producer 这个字段,会先被拆解,建立倒排索引
special 4
yago 4
producer 1,2,3,4
gaolujie 1
zhonghua 3
jiajieshi 2
2.4 phrase search (短语搜索)
match_phrase
跟全文检索相对应,相反,全文检索会将输入的搜索串拆解开来,去倒排索引里面去一一匹配,只要能匹配上任意一个拆解后的单词,就可以作为结果返回
phrase search 要求输入的搜索串,必须在指定的字段文本中,完全包含一模一样的,才可以算匹配,才能作为结果返回
2.5 elasticsearch 聚合分析
聚合分析的需求:先分组,再算每组的平均值,计算每个tag下的商品的平均价格
GET /ecommerce/product/_search
{
"size": 0,
"aggs" : {
"group_by_tags" : {
"terms" : {
"field" : "tags" },
"aggs" : {
"avg_price" : {
"avg" : {
"field" : "price" }
}
}
}
}
}
数据分析需求:计算每个tag下的商品的平均价格,并且按照平均价格降序排序
GET /ecommerce/product/_search
{
"size": 0,
"aggs" : {
"all_tags" : {
"terms" : {
"field" : "tags", "order": {
"avg_price": "desc" } },
"aggs" : {
"avg_price" : {
"avg" : {
"field" : "price" }
}
}
}
}
}
数据分析需求:按照指定的价格范围区间进行分组,然后在每组内再按照tag进行分组,最后再计算每组的平均价格
GET /ecommerce/product/_search
{
"size": 0,
"aggs": {
"group_by_price": {
"range": {
"field": "price",
"ranges": [
{
"from": 0,
"to": 20
},
{
"from": 20,
"to": 40
},
{
"from": 40,
"to": 50
}
]
},
"aggs": {
"group_by_tags": {
"terms": {
"field": "tags"
},
"aggs": {
"average_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
}
}
2.6 ES的基础分布式结构
1.ElasticSearch对复杂分布式机制的透明隐藏特性
2.ElasticSearch的垂直扩容与水平扩容
3.增减或减少节点的数据rebalance
4.master节点
5.节点对等的分布式架构
2.7 primary&replica shard
1)index包含多个shard
2)每个shard都是一个最小工作单元,承载部分数据,Lucene实例,完整的建立索引和处理请求的能力
3)增减节点时,shard 会自动在nodes中负载均衡
4)primary shard和replica shard,每个document肯定只存在某一个primary shard以及其对应的replica shard中,不可能存在于多个primary shard
5)replica shard是primary shard的副本,负责容错,以及承担读请求负载
6)primary shard的数量在创建索引的时候就固定了,replica shard的数量可以随时修改
7)primary shard的默认数量是5,replica默认是1,默认有10个shard,5个primary shard,5个replica shard
8)primary shard不能和自己的replica shard放在同一个节点上,但是可以和其他primary shard的replica shard放在同一个节点上
2.8 ES横向扩容
图解横向扩容过程,如何超出扩容极限,以及如何提升容错性
1)primary&replica自动负载均衡,6个shard,3 primary,3 replica
2)每个node有更少的shard,IO/CPU/Memory资源给每个shard分配更多,每个shard性能更好
3)扩容的极限,6个shard(3 primary,3 replica),最多扩容到6台机器,每个shard可以占用单台服务器的所有资源,性能最好
4)超出扩容极限,动态修改replica数量,9个shard(3 primary,6 replica),扩容到9台机器,比3台机器时,拥有3倍的读吞吐量
5)3台机器下,9个shard(3 primary ,6 replica),资源更少,但是容错性更好,做多容纳2台机器宕机,6个shard只能容纳1台机器宕机
6)这里的这些知识点,你综合起来看,就是说,一方面告诉你扩容的原理,怎么扩容,怎么提升系统整体吞吐量:另一方面要考虑到系统的容错性,怎么保证提高容错性,让尽可能多的服务器宕机,保证数据不丢失
2.9 ES容错机制
ElasticSearch容错机制:master选举,replica容错,数据恢复
1)9 shard, 3 node
2)master node宕机,自动master选举,red
3)replica容错:新master将replica提升为primary shard,yellow
4)重启宕机node,master copy replica到该node,使用原有的shard并同步宕机后的修改,green
2.10 ES _index/_type/_id 元数据介绍
{
"_index": "test_index",
"_type": "test_type",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"test_content": "test test"
}
}
1、_index元数据
(1)代表一个document存放在哪个index中
(2)类似的数据放在一个索引,非类似的数据放不同索引:product index(包含了所有的商品),sales index(包含了所有的商品销售数据),inventory index(包含了所有库存相关的数据)。如果你把比如product,sales,human resource(employee),全都放在一个大的index里面,比如说company index,不合适的。
(3)index中包含了很多类似的document:类似是什么意思,其实指的就是说,这些document的fields很大一部分是相同的,你说你放了3个document,每个document的fields都完全不一样,这就不是类似了,就不太适合放到一个index里面去了。
(4)索引名称必须是小写的,不能用下划线开头,不能包含逗号:product,website,blog
2、_type元数据
(1)代表document属于index中的哪个类别(type)
(2)一个索引通常会划分为多个type,逻辑上对index中有些许不同的几类数据进行分类:因为一批相同的数据,可能有很多相同的fields,但是还是可能会有一些轻微的不同,可能会有少数fields是不一样的,举个例子,就比如说,商品,可能划分为电子商品,生鲜商品,日化商品,等等。
(3)type名称可以是大写或者小写,但是同时不能用下划线开头,不能包含逗号
3、_id元数据
(1)代表document的唯一标识,与index和type一起,可以唯一标识和定位一个document
(2)我们可以手动指定document的id(put /index/type/id),也可以不指定,由es自动为我们创建一个id
2.11 ES id生成的两种方式
一般来说,是从某些其他的系统中,导入一些数据到es时,会采取这种方式,就是使用系统中已有数据的唯一标识,作为es中document的id。举个例子,比如说,我们现在在开发一个电商网站,做搜索功能,或者是OA系统,做员工检索功能。这个时候,数据首先会在网站系统或者IT系统内部的数据库中,会先有一份,此时就肯定会有一个数据库的primary key(自增长,UUID,或者是业务编号)。如果将数据导入到es中,此时就比较适合采用数据在数据库中已有的primary key。
如果说,我们是在做一个系统,这个系统主要的数据存储就是es一种,也就是说,数据产生出来以后,可能就没有id,直接就放es一个存储,那么这个时候,可能就不太适合说手动指定document id的形式了,因为你也不知道id应该是什么,此时可以采取下面要讲解的让es自动生成id的方式。
1、手动指定document id
put /index/type/id
PUT /test_index/test_type/2
{
"test_content": "my test"
}
2、自动生成document id
POST /index/type
POST /test_index/test_type
{
"test_content": "my test"
}
{
"_index": "test_index",
"_type": "test_type",
"_id": "AVp4RN0bhjxldOOnBxaE",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
自动生成的id,长度为20个字符,URL安全,base64编码,GUID,分布式系统并行生成时不可能会发生冲突
GUID算法不冲突解释:
2.12 _source元数据
1、_source元数据
put /test_index/test_type/1
{
"test_field1": "test field1",
"test_field2": "test field2"
}
get /test_index/test_type/1
result:
{
"_index": "test_index",
"_type": "test_type",
"_id": "1",
"_version": 2,
"found": true,
"_source": {
"test_field1": "test field1",
"test_field2": "test field2"
}
}
_source元数据:就是说,我们在创建一个document的时候,使用的那个放在request body中的json串,默认情况下,在get的时候,会原封不动的给我们返回回来。
2、定制返回结果
定制返回的结果,指定_source中,返回哪些field
GET /test_index/test_type/1?_source=test_field1,test_field2
result:
{
"_index": "test_index",
"_type": "test_type",
"_id": "1",
"_version": 2,
"found": true,
"_source": {
"test_field2": "test field2"
}
}
2.13 document的全量替换、强制创建、删除
1、document的全量替换
(1)语法与创建文档是一样的,如果document id不存在,那么就是创建;如果document id已经存在,那么就是全量替换操作,替换document的json串内容
(2)document是不可变的,如果要修改document的内容,第一种方式就是全量替换,直接对document重新建立索引,替换里面所有的内容
(3)es会将老的document标记为deleted,然后新增我们给定的一个document,当我们创建越来越多的document的时候,es会在适当的时机在后台自动删除标记为deleted的document
2、document的强制创建
(1)创建文档与全量替换的语法是一样的,有时我们只是想新建文档,不想替换文档,如果强制进行创建呢?
(2)PUT /index/type/id?op_type=create,PUT /index/type/id/_create
3、document的删除
(1)DELETE /index/type/id
(2)不会理解物理删除,只会将其标记为deleted,当数据越来越多的时候,在后台自动删除
2.13 ES并发冲突
2.14 ES内部如何基于_version进行乐观锁并发控制
悲观锁与乐观锁两种并发控制方案
mysql 采用悲观锁技术
ES 采用乐观锁技术,乐观锁引入 version
悲观锁与乐观锁
1.悲观锁的优点是:方便,直接加锁,对应用程序来说,透明,不需要做额外的操作;缺点,并发能力很低,同一时间只能有一条线程操作数据
2.乐观锁的优点是:并发能力很高,不给数据加锁,大量线程并发操作;缺点,麻烦,每次更新的时候,都要先对比版本号,然后可能需要重新加载数据,再次修改,再写;这个过程可能要重复好几次。
_version
每一次创建一个document的时候,它的_version内部版本号就是1;以后,每次对这个document执行修改或者删除操作,都会对这个_version版本号自动加1;哪怕是删除,也会对这条数据的版本号加1
PUT /test_index/test_type/6
{
"test_field": "test test"
}
{
"_index": "test_index",
"_type": "test_type",
"_id": "6",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
{
"found": true,
"_index": "test_index",
"_type": "test_type",
"_id": "6",
"_version": 4,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
我们会发现,在删除一个document之后,可以从侧面证明,它不是立即物理删除的,因为它的一些版本号信息还是保留着的。先删除一条document,再重新创建这条document,其实会在delete version基础之上,再把version号加1。
es 中的数据的版本号,跟客户端中的数据的版本号是相同才能修改
基于最新的数据和版本号,去进行修改,修改后,带上最新的版本号,可能这个步骤会需要反复执行好几次,才能成功,特别是在多线程并发更新同一条数据很频繁的情况下
external version
es 提供了一个feature,就是说,你可以不用它提供的内部_version 版本号来进行并发控制,可以基于你自己维护的一个版本号来进行并发控制。举个例子,加入你的数据在mysql里也有一份,然后你的应用系统本身就维护了一个版本号,无论是自己生成的,程序控制的。这个时候,你进行乐观锁并发控制的时候,可能并不是想要的es 内部的_version 来进行控制,而是用你自己维护的那个version 来进行控制。
?version=1
?version=1&version_type=external
version_type=external,唯一的区别在于,_version,只有当你提供的version 与 es 中的_version一模一样的时候,才可以进行修改,只要不一样,就报错;当version_type=external的时候,只有当你提供的version比es中的_version大的时候,才能完成修改
es,_version=1,?version=1,才能更新成功
es,_version=1,?version>1&version_type=external,才能成功,比如说?version=2&version_type=external
2.15 partial update实现原理
1. 什么是 partial update?
PUT /index/type/id,创建文档&替换文档,就是一样的语法
一般对应到应用程序中,每次的执行流程基本是这样的:
(1)应用程序先发起一个get请求,获取到document,展示到前台界面,供用户查看和修改
(2)用户在前台界面修改数据,发送到后台
(3)后台代码,会将用户修改的数据在内存中进行执行,然后封装好修改后的全量数据
(4)然后发送PUT请求,到es中,进行全量替换
(5)es将老的document标记为deleted,然后重新创建一个新的document
partial update
post /index/type/id/_update
{
"doc": {
"要修改的少数几个field即可,不需要全量的数据"
}
}
看起来,好像就比较方便了,每次就传递少数几个发生修改的field即可,不需要将全量的document数据发送过去
PUT /test_index/test_type/10
{
"test_field1": "test1",
"test_field2": "test2"
}
POST /test_index/test_type/10/_update
{
"doc": {
"test_field2": "updated test2"
}
}
partial update 相较于全量替换的优点
1.所有的查询、修改和写回操作,都发生在es中的一个shard 内部,避免了所有的网络数据传输的开销(减少2次网络请求),大大提升了性能(全量替换的查询、修改是发生在java或别的程序中的)
2.减少了查询和修改中的时间间隔,可以有效减少并发冲突的情况
groovy 脚本进行 partial update
es,有个内置脚本支持,可以基于groovy实现各种各样复杂操作
(1)内置脚本
POST /test_index/test_type/11/_update
{
"script" : "ctx._source.num+=1"
}
result:
{
"_index": "test_index",
"_type": "test_type",
"_id": "11",
"_version": 2,
"found": true,
"_source": {
"num": 1,
"tags": []
}
}
(2)外部脚本
脚本文件test-add-tags.groovy
ctx._source.tags+=new_tag
“file”: “test-add-tags”
POST /test_index/test_type/11/_update
{
"script": {
"lang": "groovy",
"file": "test-add-tags",
"params": {
"new_tag": "tag1"
}
}
}
(3)用脚本删除文档
脚本文件:test-delete-document.groovy
ctx.op = ctx._source.num == count ? ‘delete’ : ‘none’
POST /test_index/test_type/11/_update
{
"script": {
"lang": "groovy",
"file": "test-delete-document",
"params": {
"count": 1
}
}
}
(4)upsert操作
POST /test_index/test_type/11/_update
{
"doc": {
"num": 1
}
}
{
"error": {
"root_cause": [
{
"type": "document_missing_exception",
"reason": "[test_type][11]: document missing",
"index_uuid": "6m0G7yx7R1KECWWGnfH1sw",
"shard": "4",
"index": "test_index"
}
],
"type": "document_missing_exception",
"reason": "[test_type][11]: document missing",
"index_uuid": "6m0G7yx7R1KECWWGnfH1sw",
"shard": "4",
"index": "test_index"
},
"status": 404
}
如果指定的document不存在,就执行upsert中的初始化操作;如果指定的document存在,就执行doc或者script指定的partial update操作
POST /test_index/test_type/11/_update
{
"script" : "ctx._source.num+=1",
"upsert": {
"num": 0,
"tags": []
}
}
partial update 内置乐观锁并发控制
partial update 内置乐观锁并发控制
retry_on_conflict
_version
post /index/type/id/_update?retry_on_conflict=5&version=6
2.16 mget 批量查询
1、批量查询的好处
就是一条一条的查询,比如说要查询100条数据,那么就要发送100次网络请求,这个开销还是很大的
如果进行批量查询的话,查询100条数据,就只要发送1次网络请求,网络请求的性能开销缩减100倍
2、mget的语法
(1)一条一条的查询
GET /test_index/test_type/1
GET /test_index/test_type/2
(2)mget批量查询
GET /_mget
{
"docs" : [
{
"_index" : "test_index",
"_type" : "test_type",
"_id" : 1
},
{
"_index" : "test_index",
"_type" : "test_type",
"_id" : 2
}
]
}
result:
{
"docs": [
{
"_index": "test_index",
"_type": "test_type",
"_id": "1",
"_version": 2,
"found": true,
"_source": {
"test_field1": "test field1",
"test_field2": "test field2"
}
},
{
"_index": "test_index",
"_type": "test_type",
"_id": "2",
"_version": 1,
"found": true,
"_source": {
"test_content": "my test"
}
}
]
}
(3)如果查询的document是一个index下的不同type种的话
GET /test_index/_mget
{
"docs" : [
{
"_type" : "test_type",
"_id" : 1
},
{
"_type" : "test_type",
"_id" : 2
}
]
}
(4)如果查询的数据都在同一个index下的同一个type下,最简单了
GET /test_index/test_type/_mget
{
"ids": [1, 2]
}
3、mget的重要性
可以说mget是很重要的,一般来说,在进行查询的时候,如果一次性要查询多条数据的话,那么一定要用batch批量操作的api
尽可能减少网络开销次数,可能可以将性能提升数倍,甚至数十倍,非常非常之重要
2.17 bulk 批量增删改
1、bulk语法
POST /_bulk
{
"delete": {
"_index": "test_index", "_type": "test_type", "_id": "3" }}
{
"create": {
"_index": "test_index", "_type": "test_type", "_id": "12" }}
{
"test_field": "test12" }
{
"index": {
"_index": "test_index", "_type": "test_type", "_id": "2" }}
{
"test_field": "replaced test2" }
{
"update": {
"_index": "test_index", "_type": "test_type", "_id": "1", "_retry_on_conflict" : 3} }
{
"doc" : {
"test_field2" : "bulk test1"} }
每一个操作要两个json串,语法如下:
{
"action": {
"metadata"}}
{
"data"}
举例,比如你现在要创建一个文档,放bulk里面,看起来会是这样子的:
{
"index": {
"_index": "test_index", "_type", "test_type", "_id": "1"}}
{
"test_field1": "test1", "test_field2": "test2"}
有哪些类型的操作可以执行呢?
(1)delete:删除一个文档,只要1个json串就可以了
(2)create:PUT /index/type/id/_create,强制创建
(3)index:普通的put操作,可以是创建文档,也可以是全量替换文档
(4)update:执行的partial update操作
bulk api对json的语法,有严格的要求,每个json串不能换行,只能放一行,同时一个json串和一个json串之间,必须有一个换行
{
"took": 41,
"errors": true,
"items": [
{
"delete": {
"found": true,
"_index": "test_index",
"_type": "test_type",
"_id": "10",
"_version": 3,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 200
}
},
{
"create": {
"_index": "test_index",
"_type": "test_type",
"_id": "3",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true,
"status": 201
}
},
{
"create": {
"_index": "test_index",
"_type": "test_type",
"_id": "2",
"status": 409,
"error": {
"type": "version_conflict_engine_exception",
"reason": "[test_type][2]: version conflict, document already exists (current version [1])",
"index_uuid": "6m0G7yx7R1KECWWGnfH1sw",
"shard": "2",
"index": "test_index"
}
}
},
{
"index": {
"_index": "test_index",
"_type": "test_type",
"_id": "4",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true,
"status": 201
}
},
{
"index": {
"_index": "test_index",
"_type": "test_type",
"_id": "2",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,<