在Elasticsearch中,文檔(document)是全部可搜索數據的最小單位。它被序列化成JSON存儲在Elasticsearch中。每一個文檔都會有一個惟一ID,這個ID你能夠本身指定或者交給Elasticsearch自動生成。 html
若是延續咱們以前不恰當的對比RDMS的話,我認爲文檔能夠類比成關係型數據庫中的表。node
前面咱們提到,每一個文檔都有一個惟一ID來標識,獲取文檔時,「_id」字段記錄的就是文檔的惟一ID,它是元數據之一。固然,文檔還有一些其餘的元數據,下面咱們來一一介紹數據庫
有了這三個,咱們就能夠惟一肯定一個document了,固然,7.0版本之後咱們已經不須要_type了。接下來咱們再來看看其餘的一些元數據json
建立文檔有如下4種方法:api
這四種方法的區別是,若是不指定id,則Elasticsearch會自動生成一個id。若是使用_create的方法,則必須保證文檔不存在,而使用_doc方法的話,既能夠建立新的文檔,也能夠更新已存在的文檔。安全
在建立文檔時,還能夠選擇一些參數。bash
咱們在建立文檔時,若是指定的索引不存在,則ES會自動爲咱們建立索引。這一操做是能夠經過設置中的action.auto_create_index字段來控制的,默認是true。你能夠修改這個字段,實現指定某些索引能夠自動建立或者全部索引都不能自動建立的目的。併發
瞭解瞭如何建立文檔以後,咱們再來看看應該如何更新一個已經存在的文檔。其實在建立文檔時咱們就提到過,使用PUT /<index>/_doc/<id>的方法就能夠更新一個已存在的文檔。除此以外,咱們還有另外一種更新文檔的方法:app
POST /<index>/_update/<_id>less
這兩種更新有所不一樣。_doc方法是先刪除原有的文檔,再建立新的。而_update方法則是增量更新,它的更新過程是先檢索到文檔,而後運行指定腳本,最後從新索引。
還有一個區別就是_update方法支持使用腳本更新,默認的語言是painless,你能夠經過參數lang來進行設置。在請求參數方面,_update相較於_doc多瞭如下幾個參數:
下面的一個例子是用腳原本更新文檔
curl -X POST "localhost:9200/test/_update/1?pretty" -H 'Content-Type: application/json' -d' { "script" : { "source": "ctx._source.counter += params.count", "lang": "painless", "params" : { "count" : 4 } } } '
curl -X POST "localhost:9200/test/_update/1?pretty" -H 'Content-Type: application/json' -d' { "script" : { "source": "ctx._source.counter += params.count", "lang": "painless", "params" : { "count" : 4 } }, "upsert" : { "counter" : 1 } } '
當指定的文檔不存在時,可使用upsert參數,建立一個新的文檔,而當指定的文檔存在時,該請求會執行script中的腳本。若是不想使用腳本,而只想新增/更新文檔的話,可使用doc_as_upsert。
curl -X POST "localhost:9200/test/_update/1?pretty" -H 'Content-Type: application/json' -d' { "doc" : { "name" : "new_name" }, "doc_as_upsert" : true } '
這個API是用於批量更新檢索出的文檔的,具體能夠經過一個例子來了解。
curl -X POST "localhost:9200/twitter/_update_by_query?pretty" -H 'Content-Type: application/json' -d' { "script": { "source": "ctx._source.likes++", "lang": "painless" }, "query": { "term": { "user": "kimchy" } } } '
ES獲取文檔用的是GET API,請求的格式是:
GET /<index>/_doc/<_id>
它會返回文檔的數據和一些元數據,若是你只想要文檔的內容而不須要元數據時,可使用
GET /<index>/_source/<_id>
獲取文檔的有幾個請求參數以前已經提到過,這裏再也不贅述,它們分別是:
而還有一些以前沒提到過的參數,咱們來具體看一下
mget是批量獲取的方法之一,請求的格式有兩種:
第一種是在請求體中寫index。第二種是把index放到url中,不過這種方式可能會觸發ES的安全檢查。
mget的請求參數和get相同,只是須要在請求體中指定doc的相關檢索條件
request
GET /_mget { "docs" : [ { "_index" : "jackey", "_id" : "1" }, { "_index" : "jackey", "_id" : "2" } ] }
response
{ "docs" : [ { "_index" : "jackey", "_type" : "_doc", "_id" : "1", "_version" : 5, "_seq_no" : 6, "_primary_term" : 1, "found" : true, "_source" : { "user" : "ja", "tool" : "ES", "message" : "qwer" } }, { "_index" : "jackey", "_type" : "_doc", "_id" : "2", "_version" : 1, "_seq_no" : 2, "_primary_term" : 1, "found" : true, "_source" : { "user" : "zhe", "post_date" : "2019-11-15T14:12:12", "message" : "learning Elasticsearch" } } ] }
CURD操做只剩下最後一個D了,下面咱們就一塊兒來看看ES中如何刪除一個文檔。
刪除指定id使用的請求是
DELETE /<index>/_doc/<_id>
在併發量比較大的狀況下,咱們在刪除時一般會指定版本,以肯定刪除的文檔是咱們真正想要刪除的文檔。刪除請求的參數咱們在以前也都介紹過,想要具體瞭解的同窗能夠直接查看官方文檔。
相似於update,delete也有一個delete by query的API。
POST /<index>/_delete_by_query
它也是要先按照條件來查詢匹配的文檔,而後刪除這些文檔。在執行查詢以前,Elasticsearch會先爲指定索引作一個快照,若是在執行刪除過程當中,要索引起生改變,則會致使操做衝突,同時返回刪除失敗。
若是刪除的文檔比較多,也可使這個請求異步執行,只須要設置wait_for_completion=false便可。
這個API的refresh與delete API的refresh參數有所不一樣,delete中的refresh參數是設置操做是否當即可見,即只刷新一個分片,而這個API中的refresh參數則是須要刷新受影響的全部分片。
最後,咱們再來介紹一種特殊的API,批量操做的API。它支持兩種寫法,能夠將索引名寫到url中,也能夠寫到請求體中。
POST /_bulk
POST /<index>/_bulk
在這個請求中,你能夠任意使用以前的CRUD請求的組合。
curl -X POST "localhost:9200/_bulk?pretty" -H 'Content-Type: application/json' -d' { "index" : { "_index" : "test", "_id" : "1" } } { "field1" : "value1" } { "delete" : { "_index" : "test", "_id" : "2" } } { "create" : { "_index" : "test", "_id" : "3" } } { "field1" : "value3" } { "update" : {"_id" : "1", "_index" : "test"} } { "doc" : {"field2" : "value2"} } '
請求體中使用的語法是newline delimited JSON(NDJSON)。具體怎麼用呢?其實咱們在上面的例子中已經有所展示了,對於index或create這樣的請求,若是請求自己是有包體的,那麼用換行符來表示下面的內容與子請求分隔,即爲包體的開始。
例如上面例子中的index請求,它的包體就是{ "field1" : "value1" },因此它會在index請求的下一行出現。
對於批量執行操做來講,單條操做失敗並不會影響其餘操做,而最終每條操做的結果也都會返回。
上面的例子執行完以後,咱們獲得的結果應該是
{ "took": 30, "errors": false, "items": [ { "index": { "_index": "test", "_type": "_doc", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "status": 201, "_seq_no" : 0, "_primary_term": 1 } }, { "delete": { "_index": "test", "_type": "_doc", "_id": "2", "_version": 1, "result": "not_found", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "status": 404, "_seq_no" : 1, "_primary_term" : 2 } }, { "create": { "_index": "test", "_type": "_doc", "_id": "3", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "status": 201, "_seq_no" : 2, "_primary_term" : 3 } }, { "update": { "_index": "test", "_type": "_doc", "_id": "1", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "status": 200, "_seq_no" : 3, "_primary_term" : 4 } } ] }
批量操做的執行過程相比屢次單個操做而言,在性能上會有必定的提高。但同時也會有必定的風險,因此咱們在使用的時候要很是的謹慎。
本文咱們先介紹了文檔的基本概念和文檔的元數據。接着又介紹了文檔的CRUD操做和Bulk API。相信看完文章你對Elasticsearch的文檔也會有必定的瞭解。那最後就請你啓動你的Elasticsearch,而後親自動手試一試這些操做,看看各類請求的參數究竟有什麼做用。相信親手實驗過一遍以後你會對這些API有更深的印象。