简介
ElasticSearch的文档写入是以不可修改的形式写入的,一条文档记录一旦被写入其本身就不能被修改了。然而,现实中存在修改这些数据的需求,那怎么办呢?当上帝给你关上一扇门的时候,他一定给你留了一个窗口。虽然我们不能直接修改这个文档本身,但是我们可以通过更新一条_id
一样的文档,并更新版本号的方式来修改这条记录。我们可以通过三种姿势进行更新。
姿势1,直接index
PUT test1/_doc/1
{
"name": "bbbb"
}
# Do query
PUT test1/_doc/1
{
"name": "bbbb",
"age": 33
}
# Do query
PUT test1/_doc/1
{
"name": "bbbb"
}
# Do query
按顺序执行上面的三条put操作,然后查询,我们可以看到相应的查询结果是:
"_version": 1
"_source" : {
"name" : "bbbb"
}
=========================
"_version": 2
"_source" : {
"name" : "bbbb",
"age" : 33
}
=========================
"_version": 3
"_source" : {
"name" : "bbbb"
}
可以看到每次put之后,版本号都会递增1位,同时后面的数据会覆盖之前的数据。
如果我并不想每次都通过这样把全部文档内容再输入一次的形式来,而是希望基于前一个版本的文档进行增减或者修改,那又应该怎么做呢。ES为我们提供了update API。
姿势2,使用update API
ES 提供了update API,使我们可以针对某个id的文档,进行局部更新。我们可以使用painless脚本或者直接在update中设置doc字段的参数的形式进行。
考虑以下文档。
PUT test14/_doc/1
{
"name": "aaaa",
"age": 15,
"sex": "male"
}
如果我想修改年龄的话,可以有两种方法来进行:
POST test14/_update/1
{
"doc": {
"age": 14
}
}
POST test14/_update/1
{
"script": {
"lang": "painless",
"source": """
ctx._source.age = 14
"""
}
}
两种方法都可以将age修改为14。
如果我们想增加一个属性”weight“该怎么做呢?
POST test14/_update/1
{
"doc": {
"weight": 90
}
}
POST test14/_update/1
{
"script": {
"lang": "painless",
"source": """
ctx._source.weight = 90
"""
}
}
如果我们想移除”sex“字段,这种情况下,只能用painless脚本了。
POST test14/_update/1
{
"script": {
"lang": "painless",
"source": """
ctx._source.remove("sex");
"""
}
}
这三种情况是最基本的,还有一些其他用法,可以参考update的官方文档。
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/docs-update.html
需要注意,使用update api只能使用ES索引的内置版本号,如果强行指定版本号,update操作会发生错误。
上面两种方法需要指定文档id,ES还提供了基于search的update API,及update_by_query API。
姿势3,使用update_by_query API
update_by_query API的第一种使用方式是什么都不指定,直接使用。
POST twitter/_update_by_query?conflicts=proceed
我一开始看到这种用法,觉得特别疑惑,因为这样做除了更新了版本号,似乎也没有什么变化。后来读了官方文档才了解到这种用法的含义。
在设置索引配置的时候,有一个dynamic
属性,如果设置成false的话,如果碰到没有事先映射过的字段,是不会做索引,搜索不到的。需要注意,是搜索不到,但不是没有存储,这个数据还是在的。那怎样能使得这个数据能够被索引到呢,这个时候update_by_query就能排上用场了。我们先更新这个索引的mapping,然后调用update_by_query API。对应的文档会重新索引一次,之前不能搜索的字段就变得能够被搜索到了。
和query API一样,update_by_query也可以拥有一个query块,作为update的条件出现:
POST twitter/_update_by_query
{
"script": {
"source": "ctx._source.likes++",
"lang": "painless"
},
"query": {
"term": {
"user": "kimchy"
}
}
}
同样也可以使用painless进行update操作。
PUT _ingest/pipeline/set-foo
{
"description" : "sets foo",
"processors" : [ {
"set" : {
"field": "foo",
"value": "bar"
}
} ]
}
POST twitter/_update_by_query?pipeline=set-foo
在进行update_by_query的时候,还可以指定pipeline,使用pipeline的处理器处理文档。
还有一些其他用法,可以参考官方文档:
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/docs-update-by-query.html
网友评论