前面我们说了ES本质上还是一个数据库,既然是数据库就必然存在被无数程序员所鄙视的CRUD,那我们就来看下ES身上的CRUD是如何操作的。
注意我们使用的是ES7.x,所以所有关于操作中的type都是约定好的_doc。
此外ES支持完整的restful风格的请求,所以我们所有的操作其实都可以在rest api中做调用,但是后面我们大部分操作在上代码之前都是在kibana中操作的。OK,前提就这么多,下面开始了解具体内容。
一、增
对于增加一个文档在ES语法中是PUT命令。
- 支持自动生成文档id和指定文档id两种方式。
- 通过调用 post /indexname/_doc 系统会自动为你生成doc id
- 如果你使用HTTP PUT indexName/_create/id 创建的时候,URI中显式的指定了_create,此时如果该id的文档已经存在了,那么就会操作失败。
二、查
对于ES查询一个文档,只需要使用GET命令即可。具体语法是GET indexname/_doc/id
查询结果分为两种。
- 找到文档,返回HTTP 200
- 文档元数据信息,这里说一下version版本信息,这个东西如果你是同一个ID的文档,即使是被删除了,version也会递增的。
- source中默认包含了文档的所有原始数据信息,也就是那个json数据。
- 找不到文档,返回HTTP 404
三、改
在ES中,修改文档有两个操作方式。
1、Index
index和create有点渊源。他和create不一样的地方在于,如果你操作的文档本身不存在,那就索引创建新的文档。否则现在存在的文档会被·删除,然后创建新的文档。同时新的文档版本号是在原来基础上加一。
2、post
post操作就是真的我们理解中的修改,他不会删除原来文档,只是做数据更新。还能添加字段的更新。
post方法需要把数据请求体放到doc数组里面,下面看例子。
四、具体操作验证上述语法
1、创建文档
create document. 创建一个文档并且自动生成 _id
此时我们看一下这个索引的结构:
create document. 指定Id。如果id已经存在,报错。
id是我们自己指定的1,此时你再执行这个语句就会报错。
一般我们使用下面这个比较多,比较简洁。PUT users/_create/1
2、查看/修改文档
GET users/_doc/1
我们看到此时这个文档可以被查出来,而且版本是4,不好意思,因为我中间操作了几次。
此时我们修改一下这个文档、
他此时是删除旧的,插入新的。我们再查看一下,发现已经全部变了。
我们post加了字段,我们验证一下是不是改了索引结构。
1、先删除这个索引。然后插入一个文档。
此时索引这样的。
我们再加字段进去再查看索引结构。发现索引结构变了,可见他其实是修改了索引结构。
3、删除文档
DELETE users/_doc/1
4、批量操作文档
每一次我们都操作一条文档,每次操作都是需要建立连接,然后发出http调用,这个性能损耗是有的。所以我们的思路就是合并请求,批量操作数据。这个操作思路也是屡见不鲜了。REDIS中就有各种批量命令。
Bulk Api支持在一次API调用中,对不同文档,不同索引进行操作。注意,支持同时操作不同索引。
支持四种类型操作。
- Index
- create
- update
- delete
你可以在URI中指定index,也可以在请求的Payload载荷中进行
操作单条失败,不会影响其他操作,也就不不具备事务的原子性。
返回结果包括每一条操作的执行结果。
4.1、批量操作命令解读
#执行第1次
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } } 指定操作的索引是test,操作类型是index,操作文档是1号,
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test2", "_id" : "3" } }指定操作的索引是test2,操作类型是create,操作文档是3号,
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
看下执行结果:
{
"took" : 577,
"errors" : false,
"items" : [
{
"index" : {
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",index是不存在就创建,存在先删除,再创建,因为此时根本没有id为1的数据,所以创建成功
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 201
}
},
{
"delete" : {
"_index" : "test",
"_type" : "_doc",
"_id" : "2",
"_version" : 1,
"result" : "not_found", 根本id为2现在就不存在
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1,
"status" : 404
}
},
{
"create" : {
"_index" : "test2",
"_type" : "_doc",
"_id" : "3",
"_version" : 1,
"result" : "created", 创建成功
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 201
}
},
{
"update" : {
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"result" : "updated", 更新成功
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1,
"status" : 200
}
}
]
}
可以看到一个失败不影响其他的指令执行。
4.2、批量读取
### mget 操作
GET /_mget
{
"docs" : [
{
"_index" : "test", # 可以指定不同的索引
"_id" : "1"
},
{
"_index" : "test2",
"_id" : "2"
}
]
}
#URI中指定index
GET /test/_mget # 在路径中指定索引
{
"docs" : [
{
"_id" : "1"
},
{
"_id" : "2"
}
]
}
GET /_mget
{
"docs" : [
{
"_index" : "test",
"_id" : "1",
"_source" : false # 全部字段都返回显示,默认就是
},
{
"_index" : "test",
"_id" : "2",
"_source" : ["field3", "field4"] # 只返回field3", "field4两个属性的值
},
{
"_index" : "test",
"_id" : "3",
"_source" : {
"include": ["user"],
"exclude": ["user.location"] # 排除那些字段返回
}
}
]
}
### msearch 操作,下面是对索引kibana_sample_data_ecommerce的查询,包含两个查询两个query
每个query上面都带一个{}
POST kibana_sample_data_ecommerce/_msearch
{}
{"query" : {"match_all" : {}},"size":1}
{}
{"query" : {"match_all" : {}},"size":2}
注意,即便是批量查询也不要一次查太多,网络开销,查询开销都是很大的。自己衡量。
五、常见问题返回码
六、总结一下
上面的那个crud的类型没说好,这里总结一下。
文档的crud有什么post get put这都是restful的东西,他的操作里面有几种类型,读和删除不说了。文章来源:https://uudwc.com/A/LWWE
- 带上Create 就是说如果ID已经存在,会创建失败。不管你是PUT还是POST
- 带上Index,不存在就创建,存在就删了在创建,版本增加。
- Update,文档必须存在,更新只会对你指定的字段做更新。增量更新。
上述都是语法,需要多多练习才行。
增加理解:
对于创建修改文档的时候有时候会懵逼,到底啥时候是创建,啥时候是更新,这里总结一下。
1、create类型的就会存在ID冲突。比如:文章来源地址https://uudwc.com/A/LWWE
PUT操作是要带上id的,不然就报错。
PUT users/_create/1
{
"user" : "Jack",
"post_date" : "2019-05-15T14:12:12",
"message" : "trying out Elasticsearch"
}
PUT users/_doc/1?op_type=create
{
"user" : "Jack",
"post_date" : "2019-05-15T14:12:12",
"message" : "trying out Elasticsearch"
}
PUT users/_doc/200 这种没有create就是Index,先删除后添加,版本加一,不会冲突。
{
"user" : "Jack",
"post_date" : "2019-05-15T14:12:12",
"message" : "trying out Elasticsearch"
}
POST操作也是一样,但是post不需要带ID也可以,ES自己生成。
POST users/_doc
{
"user" : "Mike",
"post_date" : "2019-04-15T14:12:12",
"message" : "trying out Kibana"
}
POST users/_doc/100?op_type=create 这里你带上了create,指定了ID,就会有冲突问题。
{
"user" : "Mike",
"post_date" : "2019-04-15T14:12:12",
"message" : "trying out Kibana"
}
create是要判断id的,所以你不管是post还是put只要你create都要加上id才行。
#在原文档上增加字段
POST users/_update/1/ 这是update类型,你要操作的文档必须存在,他是增量更新的。很灵活。
{
"doc":{
"post_date" : "2019-05-15T14:12:12",
"message" : "trying out Elasticsearch"
}
}