在ES中對(duì)索引文檔進(jìn)行更新

簡(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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容