簡(jiǎn)介
ElasticSearch的文檔寫(xiě)入是以不可修改的形式寫(xiě)入的,一條文檔記錄一旦被寫(xiě)入其本身就不能被修改了。然而,現(xiàn)實(shí)中存在修改這些數(shù)據(jù)的需求,那怎么辦呢?當(dāng)上帝給你關(guān)上一扇門(mén)的時(shí)候,他一定給你留了一個(gè)窗口。雖然我們不能直接修改這個(gè)文檔本身,但是我們可以通過(guò)更新一條_id一樣的文檔,并更新版本號(hào)的方式來(lái)修改這條記錄。我們可以通過(guò)三種姿勢(shì)進(jìn)行更新。
姿勢(shì)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
按順序執(zhí)行上面的三條put操作,然后查詢(xún),我們可以看到相應(yīng)的查詢(xún)結(jié)果是:
"_version": 1
"_source" : {
"name" : "bbbb"
}
=========================
"_version": 2
"_source" : {
"name" : "bbbb",
"age" : 33
}
=========================
"_version": 3
"_source" : {
"name" : "bbbb"
}
可以看到每次put之后,版本號(hào)都會(huì)遞增1位,同時(shí)后面的數(shù)據(jù)會(huì)覆蓋之前的數(shù)據(jù)。
如果我并不想每次都通過(guò)這樣把全部文檔內(nèi)容再輸入一次的形式來(lái),而是希望基于前一個(gè)版本的文檔進(jìn)行增減或者修改,那又應(yīng)該怎么做呢。ES為我們提供了update API。
姿勢(shì)2,使用update API
ES 提供了update API,使我們可以針對(duì)某個(gè)id的文檔,進(jìn)行局部更新。我們可以使用painless腳本或者直接在update中設(shè)置doc字段的參數(shù)的形式進(jìn)行。
考慮以下文檔。
PUT test14/_doc/1
{
"name": "aaaa",
"age": 15,
"sex": "male"
}
如果我想修改年齡的話(huà),可以有兩種方法來(lái)進(jìn)行:
POST test14/_update/1
{
"doc": {
"age": 14
}
}
POST test14/_update/1
{
"script": {
"lang": "painless",
"source": """
ctx._source.age = 14
"""
}
}
兩種方法都可以將age修改為14。
如果我們想增加一個(gè)屬性”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索引的內(nèi)置版本號(hào),如果強(qiáng)行指定版本號(hào),update操作會(huì)發(fā)生錯(cuò)誤。
上面兩種方法需要指定文檔id,ES還提供了基于search的update API,及update_by_query API。
姿勢(shì)3,使用update_by_query API
update_by_query API的第一種使用方式是什么都不指定,直接使用。
POST twitter/_update_by_query?conflicts=proceed
我一開(kāi)始看到這種用法,覺(jué)得特別疑惑,因?yàn)檫@樣做除了更新了版本號(hào),似乎也沒(méi)有什么變化。后來(lái)讀了官方文檔才了解到這種用法的含義。
在設(shè)置索引配置的時(shí)候,有一個(gè)dynamic屬性,如果設(shè)置成false的話(huà),如果碰到?jīng)]有事先映射過(guò)的字段,是不會(huì)做索引,搜索不到的。需要注意,是搜索不到,但不是沒(méi)有存儲(chǔ),這個(gè)數(shù)據(jù)還是在的。那怎樣能使得這個(gè)數(shù)據(jù)能夠被索引到呢,這個(gè)時(shí)候update_by_query就能排上用場(chǎng)了。我們先更新這個(gè)索引的mapping,然后調(diào)用update_by_query API。對(duì)應(yīng)的文檔會(huì)重新索引一次,之前不能搜索的字段就變得能夠被搜索到了。
和query API一樣,update_by_query也可以擁有一個(gè)query塊,作為update的條件出現(xiàn):
POST twitter/_update_by_query
{
"script": {
"source": "ctx._source.likes++",
"lang": "painless"
},
"query": {
"term": {
"user": "kimchy"
}
}
}
同樣也可以使用painless進(jìn)行update操作。
PUT _ingest/pipeline/set-foo
{
"description" : "sets foo",
"processors" : [ {
"set" : {
"field": "foo",
"value": "bar"
}
} ]
}
POST twitter/_update_by_query?pipeline=set-foo
在進(jìn)行update_by_query的時(shí)候,還可以指定pipeline,使用pipeline的處理器處理文檔。
還有一些其他用法,可以參考官方文檔:
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/docs-update-by-query.html