elasticsearch更新文件資料
文字方式批量更新多欄位
使用更新
請求最簡單的一種用途就是新增新資料。新的資料會被合併到現有資料中,而如果存在相同的欄位,就會被新的資料所替換。例如我們可以為我們的部落格新增tags
和views
欄位:
POST /website/blog/1/_update
{
"doc" : {
"tags" : [ "testing" ],
"views": 0
}
}
如果請求成功,我們就會收到一個類似於索引
時返回的內容
使用指令碼進行更新
預設的指令碼語言叫做MVEL,但是Elasticsearch也支援JavaScript, Groovy 以及 Python。MVEL是一個簡單高效的JAVA基礎動態指令碼語言,它的語法類似於Javascript。指令碼語言可以在更新
_source
中的內容,而它在指令碼中被稱為ctx._source
。例如,我們可以使用指令碼來增加博文中views
的數字:
POST /website/blog/1/_update
{
"script" : "ctx._source.views+=1"
}
我們同樣可以使用指令碼在tags
陣列中新增新的tag。在這個例子中,我們把新的tag宣告為一個變數,而不是將他寫死在指令碼中。這樣Elasticsearch就可以重新使用這個指令碼進行tag的新增,而不用再次重新編寫指令碼了:
POST /website/blog/1/_update
{
"script" : "ctx._source.tags+=new_tag" ,
"params" : {
"new_tag" : "search"
}
}
獲取文件,後兩項發生了變化:
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 5,
"found": true,
"_source": {
"title": "My first blog entry",
"text": "Starting to get the hang of this...",
"tags" : ["testing", "search"], <1>
"views": 1 <2>
}
}
tags
陣列中出現了search
。views
欄位增加了。
我們甚至可以使用ctx.op
來根據內容選擇是否刪除一個文件:
POST /website/blog/1/_update
{
"script" : "ctx.op = ctx._source.views == count ? 'delete' : 'none'",
"params" : {
"count": 1
}
}
更新一篇可能不存在的文件
想象一下,我們可能需要在Elasticsearch中儲存一個頁面計數器。每次使用者訪問這個頁面,我們就增加一下當前頁面的計數器。但是如果這是個新的頁面,我們不能確保這個計數器已經存在。如果我們試著去更新一個不存在的文件,更新操作就會失敗。
為了防止上述情況的發生,我們可以使用upsert
引數來設定文件不存在時,它應該被建立:
POST /website/pageviews/1/_update
{
"script" : "ctx._source.views+=1",
"upsert": {
"views": 1
}
}
首次執行這個請求時,upsert
的內容會被索引成新的文件,它將views
欄位初始化為1
。當之後再請求時,文件已經存在,所以指令碼
更新就會被執行,views
計數器就會增加。
為了避免丟失資料,更新
API會在獲取步驟中獲取當前文件中的_version
,然後將其傳遞給重新索引步驟中的索引
請求。如果其他的程序在這兩部之間修改了這個文件,那麼_version
就會不同,這樣更新就會失敗。
對於很多的區域性更新來說,文件有沒有發生變化實際上是不重要的。例如,兩個程序都要增加頁面瀏覽的計數器,誰先誰後其實並不重要 —— 發生衝突時只需要重新來過即可。
你可以通過設定retry_on_conflict
引數來設定自動完成這項請求的次數,它的預設值是0
。
POST /website/pageviews/1/_update?retry_on_conflict=5 <1>
{
"script" : "ctx._source.views+=1",
"upsert": {
"views": 0
}
}
- 失敗前重新嘗試5次