一、文檔
最頂層結構或者根對象(root object)序列化成的JSON數據(以唯一ID標識並存儲於Elasticsearch中),可以認爲對象(object)和文檔(document)是等價相通的。
文檔元數據
節點 | 說明 |
---|---|
_index | 文檔存儲的地方 |
_type | 文檔代表的對象的類 |
_id | 文檔的唯一標識 |
_index
索引(index)類似於關係型數據庫裏的“數據庫”——它是我們存儲和索引關聯數據的地方。數據被存儲和索引在分片(shards)中, 索引只是一個把一個或多個分片分組在一起的邏輯空間。索引名必須是全部小寫, 不能以下劃線開頭, 不能包含逗號
_type
在關係型數據庫中, 我們經常將相同類的對象存儲在一個表裏, 因爲它們有着相同的結構。 同理, 在Elasticsearch中, 我們使用相同類型(type)的文檔表示相同的“事物”, 因爲他們的數據結構也是相同的
_id
id僅僅是一個字符串, 它與 _index 和 _type 組合時, 就可以在ELasticsearch中唯一標識一個文檔。 當創建一個文檔, 你可以自定義 _id , 也可以讓Elasticsearch幫你自動生成
二、文檔CRUD操作
1. 索引文檔
指定id創建文檔 ,使用put
put /website/blog/1
{
"title":"first blog",
"date":"2019/10/28"
}
響應
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
響應指出請求的索引已經被成功創建, 這個索引中包含 _index 、 _type 和 _id 元數據,版本號是1
注意使用put並不能保證每次都是新建文檔,如果再次put相同id的文檔,會對原有的文檔進行覆蓋。
PUT /website/blog/1
{
"title": "three blog",
"feel":"nice",
"date": "2019/10/28"
}
//響應
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 2, //版本號自增
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": false //表示不是新建,而是覆蓋
}
在內部, Elasticsearch已經標記舊文檔爲刪除並添加了一個完整的新文檔。 舊版本文檔不會立即消失, 但你也不能去訪問它。 Elasticsearch會在你繼續索引更多數據時清理被刪除的文檔
不指定id,使用post
post /website/blog
{
"title":"second blog",
"date":"2019/10/28"
}
//響應
{
"_index": "website",
"_type": "blog",
"_id": "AW4TC7FgHfHdzvmX4JMA",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
自動生成id:AW4TC7FgHfHdzvmX4JMA,每次都是新建文檔,不會覆蓋
自動生成的id,長度爲20個字符,URL安全,base64編碼,GUID,分佈式系統並行生成時不可能會發生衝突
使用put創建新文檔
PUT /website/blog/1?op_type=create
{
"title": "four blog",
"feel":"nice",
"date": "2019/10/28"
}
//響應
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[blog][1]: version conflict, document already exists (current version [2])",
"index_uuid": "oqUDP19MSL2Y9XmPxCf1cA",
"shard": "3",
"index": "website"
}
],
"type": "version_conflict_engine_exception",
"reason": "[blog][1]: version conflict, document already exists (current version [2])",
"index_uuid": "oqUDP19MSL2Y9XmPxCf1cA",
"shard": "3",
"index": "website"
},
"status": 409
}
存在不會進行覆蓋,報409錯誤
也可以這樣寫,效果和上面相同
PUT /website/blog/3/_create
{
"title": "five blog",
"feel":"nice",
"date": "2019/10/28"
}
2. 檢索文檔
使用Get
GET /website/blog/1
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"title": "first blog",
"date": "2019/10/28"
}
}
響應包含了現在熟悉的元數據節點, 增加了 _source 字段, 它包含了在創建索引時我們發送給Elasticsearch的原始文檔
檢索文檔部分內容
get /website/blog/1?_source=title
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"title": "first blog"
}
}
只需要返回source字段
get /website/blog/1/_source
{
"title": "first blog",
"date": "2019/10/28"
}
查詢對應索引下所有文檔
get /website/_search
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "website",
"_type": "blog",
"_id": "AW4TC7FgHfHdzvmX4JMA",
"_score": 1,
"_source": {
"title": "second blog",
"date": "2019/10/28"
}
},
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_score": 1,
"_source": {
"title": "first blog",
"date": "2019/10/28"
}
}
]
}
}
字段解釋:
took
整個搜索請求花費的毫秒數。
timeout
查詢超時與否,如果響應速度比完整的結果更重要,可以指定超時時間
get /website/_search?timeout=10ms
shards
- total 字段 參與查詢的分片數
- successful 字段 有多少是成功的
- failed 字段 有多少的是失敗的
hits
total 字段 表示匹配到的文檔總數
hits 數組包含了匹配到的前10條數據,hits 數組中的每個結果都包含 _index 、 _type 和文檔的 _id 字段,每個節點都有一個 _score 字段, 這是相關性得分(relevance score), 它衡量了文檔與查詢的匹配程度。 默認的, 返回的結果中關聯性最大的文檔排在首位; 這意味着, 它是按照 _score 降序排列的。max_score 指的是所有文檔匹配查詢中 _score 的最大值
3. 修改文檔
-
put是對原有文檔的覆蓋,使用新的文檔替換舊文檔
-
update API對文檔可以進行局部更新
post /website/blog/1/_update
{
"doc":{
"action":"go to the moives",
"date":"2019/10/29"
}
}
get /website/blog/1
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 5,
"found": true,
"_source": {
"title": "one blog",
"feel": "nice",
"date": "2019/10/29",
"action": "go to the moives"
}
}
最簡單的 update 請求表單接受一個局部文檔參數 doc , 它會合併到現有文檔中,存在的標量字段被覆蓋, 新字段被添加。例如上述例子新加了action字段,修改了date值
可以使用Groovy實現局部更新,我們可以在腳本中寫各種邏輯,然後執行即可。
4. 刪除文檔
DELETE /website/blog/AW4TDmKTHfHdzvmX4JMC
{
"found": true,
"_index": "website",
"_type": "blog",
"_id": "AW4TDmKTHfHdzvmX4JMC",
"_version": 2,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
刪除一個文檔也不會立即從磁盤上移除, 它只是被標記成已刪除。 Elasticsearch
將會在你之後添加更多索引的時候纔會在後臺進行刪除內容的清理。
未找到對應刪除文檔,刪除失敗
DELETE /website/blog/AW4
{
"found": false,
"_index": "website",
"_type": "blog",
"_id": "AW4",
"_version": 1,
"result": "not_found",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
三、版本控制與更新衝突
對於多用戶的局部更新,由於網絡原因,可能會出現舊值覆蓋新值的情況,或者多線程常見的問題。
ES使用樂觀版本併發控制,爲每個文檔指定版本號,通過CAS比較,如果不是期望的版本號,也就是說中間被人修改過該文檔,就讓本次更新請求失敗
使用內部版本號
PUT /website/blog/3?version=2
{
"title": "five blog",
"feel":"sad",
"date": "2019/10/29"
}
//響應
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[blog][3]: version conflict, current version [1] is different than the one provided [2]",
"index_uuid": "lhDIRTZ7S9mYFUIj9z6AcA",
"shard": "4",
"index": "website"
}
],
"type": "version_conflict_engine_exception",
"reason": "[blog][3]: version conflict, current version [1] is different than the one provided [2]",
"index_uuid": "lhDIRTZ7S9mYFUIj9z6AcA",
"shard": "4",
"index": "website"
},
"status": 409
}
文檔3的版本號是1,這裏傳入的version參數值爲2,所以發生衝突,更新失敗
注意,這裏傳入參數version值必須和文檔現有的version值完全相等,精確匹配,否則失敗
使用外部版本號
PUT /website/blog/4?version=3&version_type=external
{
"title": "six blog",
"feel":"funny",
"date": "2019/10/29"
}
指定該文檔的版本爲4,外部版本號必須是整數, 大於0小於 9.2e+18
PUT /website/blog/4?version=3&version_type=external
{
"title": "six blog",
"feel":"funny",
"date": "2019/10/29"
}
//響應
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[blog][4]: version conflict, current version [3] is higher or equal to the one provided [2]",
"index_uuid": "lhDIRTZ7S9mYFUIj9z6AcA",
"shard": "2",
"index": "website"
}
],
"type": "version_conflict_engine_exception",
"reason": "[blog][4]: version conflict, current version [3] is higher or equal to the one provided [2]",
"index_uuid": "lhDIRTZ7S9mYFUIj9z6AcA",
"shard": "2",
"index": "website"
},
"status": 409
}
報錯的原因是因爲外部版本號要求更新傳入的version > 當前文檔版本號,而不是精確匹配,否則報錯,這裏講version值傳入4即可成功更新