什麼是文檔。
程式中大多的實體或對象能夠被序列化為包含索引值對的JSON對象,鍵(key)是欄位(field)或屬性(property)的名字,值(value)可以是字串、數字、布爾類型、另一個對象、值數組或者其他特殊類型,比如表示日期的字串或者表示地理位置的對象。 1
{ "name": "John Smith", "age": 42, "confirmed": true, "join_date": "2014-06-01", "home": { "lat": 51.5, "lon": 0.1 }, "accounts": [ { "type": "facebook", "id": "johnsmith" }, { "type": "twitter", "id": "johnsmith" } ]}
通常,我們可以認為對象(object)和文檔(document)是等價相通的。不過,他們還是有所差別:對象(Object)是一個JSON結構體——類似於雜湊、hashmap、字典或者關聯陣列;對象(Object)中還可能包含其他對象(Object)。 在Elasticsearch中,文檔(document)這個術語有著特殊含義。它特指最頂層結構或者根對象(root object)序列化成的JSON資料(以唯一ID標識並儲存於Elasticsearch中)。 1
文檔中繼資料
一個文檔不只有資料。它還包含了中繼資料(metadata)——關於文檔的資訊。三個必須的中繼資料節點是: 節點 說明 _index 文檔儲存的地方 _type 文檔代表的對象的類 _id 文檔的唯一標識 _index
索引(index)類似於關係型資料庫裡的“資料庫”——它是我們儲存和索引關聯資料的地方。
提示:
事實上,我們的資料被儲存和索引在分區(shards)中,索引只是一個把一個或多個分區分組在一起的邏輯空間。然而,這隻是一些內部細節——我們的程式完全不用關心分區。對於我們的程式而言,文檔儲存在索引(index)中。剩下的細節由Elasticsearch關心既可。 1
我們將會在《索引管理》章節中探討如何建立並管理索引,但現在,我們將讓Elasticsearch為我們建立索引。我們唯一需要做的僅僅是選擇一個索引名。這個名字必須是全部小寫,不能以底線開頭,不能包含逗號。讓我們使用website做為索引名。 1
_type
在應用中,我們使用對象表示一些“事物”,例如一個使用者、一篇部落格、一個評論,或者一封郵件。每個對象都屬於一個類(class),這個類定義了屬性或與對象關聯的資料。user類的對象可能包含姓名、性別、年齡和Email地址。 1
在關係型資料庫中,我們經常將相同類的Object Storage Service在一個表裡,因為它們有著相同的結構。同理,在Elasticsearch中,我們使用相同類型(type)的文檔表示相同的“事物”,因為他們的資料結構也是相同的。
每個類型(type)都有自己的映射(mapping)或者結構定義,就像傳統資料庫表中的列一樣。所有類型下的文檔被儲存在同一個索引下,但是類型的映射(mapping)會告訴Elasticsearch不同的文檔如何被索引。 我們將會在《映射》章節探討如何定義和管理映射,但是現在我們將依賴Elasticsearch去自動處理資料結構。
_type的名字可以是大寫或小寫,不能包含底線或逗號。我們將使用blog做為類型名。 _id
id僅僅是一個字串,它與_index和_type組合時,就可以在Elasticsearch中唯一標識一個文檔。當建立一個文檔,你可以自訂_id,也可以讓Elasticsearch幫你自動產生。 其它中繼資料
還有一些其它的中繼資料,我們將在《映射》章節探討。使用上面提到的元素,我們已經可以在Elasticsearch中儲存文檔並通過ID檢索——換言說,把Elasticsearch做為文檔儲存空間使用了。
索引一個文檔
文檔通過index API被索引——使資料可以被儲存和搜尋。但是首先我們需要決定文檔所在。正如我們討論的,文檔通過其_index、_type、_id唯一確定。們可以自己提供一個_id,或者也使用index API 為我們產生一個。 1
使用自己的ID
如果你的文檔有自然的標識符(例如user_account欄位或者其他值表示文檔),你就可以提供自己的_id,使用這種形式的index API:
PUT /{index}/{type}/{id}{ "field": "value", ...}
例如我們的索引叫做“website”,類型叫做“blog”,我們選擇的ID是“123”,那麼這個索引請求就像這樣:
PUT /website/blog/123{ "title": "My first blog entry", "text": "Just trying this out...", "date": "2014/01/01"}
Elasticsearch的響應:
{ "_index": "website", "_type": "blog", "_id": "123", "_version": 1, "created": true}
響應指出請求的索引已經被成功建立,這個索引中包含_index、_type和_id中繼資料,以及一個新元素:_version。 2
Elasticsearch中每個文檔都有版本號碼,每當文檔變化(包括刪除)都會使_version增加。在《版本控制》章節中我們將探討如何使用_version號確保你程式的一部分不會覆蓋掉另一部分所做的更改。 自增ID
如果我們的資料沒有自然ID,我們可以讓Elasticsearch自動為我們產生。請求結構發生了變化:PUT方法——“在這個URL中儲存文檔”變成了POST方法——"在這個類型下儲存文檔"。(譯者註:原來是把文檔儲存到某個ID對應的空間,現在是把這個文檔添加到某個_type下)。
URL現在只包含_index和_type兩個欄位:
POST /website/blog/{ "title": "My second blog entry", "text": "Still trying this out...", "date": "2014/01/01"}
響應內容與剛才類似,只有_id欄位變成了自動產生的值: 2
{ "_index": "website", "_type": "blog", "_id": "wM0OSFhDQXGZAWDf0-drSA", "_version": 1, "created": true}
自動產生的ID有22個字元長,URL-safe, Base64-encoded string universally unique identifiers, 或者叫 UUIDs。
檢索文檔
想要從Elasticsearch中擷取文檔,我們使用同樣的_index、_type、_id,但是HTTP方法改為GET:
GET /website/blog/123?pretty
響應包含了現在熟悉的中繼資料節點,增加了_source欄位,它包含了在建立索引時我們發送給Elasticsearch的原始文檔。
{ "_index" : "website", "_type" : "blog", "_id" : "123", "_version" : 1, "found" : true, "_source" : { "title": "My first blog entry", "text": "Just trying this out...", "date": "2014/01/01" }} pretty
在任意的查詢字串中增加pretty參數,類似於上面的例子。會讓Elasticsearch美化輸出(pretty-print)JSON響應以便更加容易閱讀。_source欄位不會被美化,它的樣子與我們輸入的一致。
GET請求返回的響應內容包括{"found": true}。這意味著文檔已經找到。如果我們請求一個不存在的文檔,依舊會得到一個JSON,不過found值變成了false。
此外,HTTP響應狀態代碼也會變成'404 Not Found'代替'200 OK'。我們可以在curl後加-i參數得到回應標頭:
curl -i -XGET http://localhost:9200/website/blog/124?pretty
現在響應類似於這樣:
HTTP/1.1 404 Not FoundContent-Type: application/json; charset=UTF-8Content-Length: 83{ "_index" : "website", "_type" : "blog", "_id" : "124", "found" : false} 檢索文檔的一部分
通常,GET請求將返迴文檔的全部,儲存在_source參數中。但是可能你感興趣的欄位只是title。請求個別欄位可以使用_source參數。多個欄位可以使用逗號分隔:
GET /website/blog/123?_source=title,text
_source欄位現在只包含我們請求的欄位,而且過濾了date欄位:
{ "_index" : "website", "_type" : "blog", "_id" : "123", "_version" : 1, "exists" : true, "_source" : { "title": "My first blog entry" , "text": "Just trying this out..." }}
或者你只想得到_source欄位而不要其他的中繼資料,你可以這樣請求:
GET /website/blog/123/_source
它僅僅返回:
{ "title": "My first blog entry", "text": "Just trying this out...", "date": "2014/01/01"}
檢查文檔是否存在
如果你想做的只是檢查文檔是否存在——你對內容完全不感興趣——使用HEAD方法來代替GET。HEAD請求不會返迴響應體,只有HTTP頭:
curl -i -XHEAD http://localhost:9200/website/blog/123
Elasticsearch將會返回200 OK狀態如果你的文檔存在:
HTTP/1.1 200 OKContent-Type: text/plain; charset=UTF-8Content-Length: 0
如果不存在返回404 Not Found:
curl -i -XHEAD http://localhost:9200/website/blog/124
HTTP/1.1 404 Not FoundContent-Type: text/plain; charset=UTF-8Content-Length: 0
當然,這隻表示你在查詢的那一刻文檔不存在,但並不表示幾毫秒後依舊不存在。另一個進程在這期間可能建立新文檔。
更新整個文檔
文檔在Elasticsearch中是不可變的——我們不能修改他們。如果需要更新已存在的文檔,我們可以使用《索引文檔》章節提到的index API 重建索引(reindex) 或者替換掉它。
PUT /website/blog/123{ "title": "My first blog entry", "text": "I am starting to get the hang of this...", "date": "2014/01/02"}
在響應中,我們可以看到Elasticsearch把_version增加了。 1
{ "_index" : "website", "_type" : "blog", "_id" : "123", "_version" : 2, "created": false <1>} <1> created標識為false因為同索引、同類型下已經存在同ID的文檔。
在內部,Elasticsearch已經標記舊文檔為刪除並添加了一個完整的新文檔。舊版本文檔不會立即消失,但你也不能去訪問它。Elasticsearch會在你繼續索引更多資料時清理被刪除的文檔。
在本章的後面,我們將會在《局部更新》中探討update API。這個API 似乎 允許你修改文檔的局部,但事實上Elasticsearch遵循與之前所說完全相同的過程,這個過程如下: 從舊文檔中檢索JSON 修改它 刪除舊文檔 索引新文檔
唯一的不同是update API完成這一過程只需要一個用戶端請求既可,不再需要get和index請求了。
from: https://es.xiaoleilu.com/030_Data/05_Document.html