1 ES數據讀寫流程¶
ES中,每個索引都將被划分為若干分片,每個分片可以有多個副本。這些副本共同組成復制組,復制組中的分片在添加或刪除文檔時必須保持同步,否則,從一個副本中讀取的數據將與從另一個副本讀取的結果有差異。保持復制組中分片數據同步以及從它們中讀取的過程稱為數據復制模型。
ES的數據復制模型基於主備份模型,這種模型使用復制組的一個分片作為主分片,復制組中其他分片作為副本分片。主分片是所有索引操作的主要入口點,負責驗證操作的有效性。一旦主分片通過操作驗證,主數據庫還負責將該操作復制到其他副本。
1.1 數據寫入流程¶
ES中的每個索引操作首先解析到對應的復制組中,通常基於文檔 ID,確定復制組后,操作將在內部轉發到復制組的當前主分片。主分片介紹到操作請求后,將對操作請求進行驗證再轉發到其他副本中。
主分片遵循以下基本流:
(1)驗證傳入操作,並在結構無效時拒絕它(例如:給定值與字段類型不匹配)
(2)在本地執行操作,即索引或刪除相關文檔。這也需要驗證字段的內容,並根據需要拒絕(例如:關鍵字值太長)。
(3)將操作轉發到當前同步副本集的每個副本。如果有多個副本,則並行執行。
(4)一旦所有副本成功執行了該操作並響應了主副本,主副本將確認成功完成對客戶端的請求。
1.2 數據讀取流程¶
ES中的讀取可以是非常輕量級的按 ID 查找,也可以是具有復雜聚合的重搜索請求。ES所采用的主備份模型的一大亮點就是它使所有分片副本保持同步,因此,單個同步副本足以提供讀取請求。
當節點收到讀取請求時,該節點負責將該請求轉發到包含相關數據的分片節點、整理響應以及響應客戶端。基本流程如下:
(1)將讀取請求解析為相關分片。請注意,由於大多數搜索將發送到一個或多個索引,因此它們通常需要從多個分片讀取,每個分片表示數據的不同子集。
(2)從分片復制組中選擇每個相關分片的活動副本。這可以是主分片,也可以是副本分片。默認情況下,彈性搜索將只是在分片副本之間循環。
(3)將各分片讀取請求發送到所選副本分片。
(4)合並結果並做出響應。注意,在通過 ID 查找的情況下,只有一個分片是相關的,可以跳過此步驟。
2 文檔寫入操作¶
使用下列API可以將一個JSON文檔添加到指定的索引中,如果在指定索引中已存在該文檔,那么這一操作將會更新文檔,並使文檔的version自增1。
PUT /<target>/_doc/<_id>
POST /<target>/_doc/
PUT /<target>/_create/<_id>
POST /<target>/_create/<_id>
其中,target
是一個必填參數,指的是目標索引,如果目標索引不存在,那么將會自動創建一個索引;_id
是一個可選參數,指的是為文檔指定的唯一標識,如果省略_id
參數的話,將會和POST /<target>/_doc/
API一樣,自動為文檔設定一個id。
- 唯一標識(_id)
上圖實例中,users索引原本是不存在的,創建文檔時,將自動創建索引,另外,由於創建文檔時,並未指定_id
,ES將自動為文檔設置一個_id
,注意,_id
是ES對文檔的唯一標識,與文檔內容中的id
是不一樣的。如下所示,添加文檔時指定_id
參數:
- 禁止更新(op_type)
在上文中,我們說到,在默認情況下,如果向索引中插入已存在的文檔,那么將執行更新操作,但是,如果我們需要執行的是如果已存在,則停止執行的操作,那么就需要傳遞op_type
參數,並將值設置為create。如下所示,再次向索引中插入已存在文檔時,將提示沖突。
- 文檔版本(_version)
在上述示例的返回結果中,有一個_version
字段,該字段用於標識文檔的版本,初始值默認為1,每一次對文檔進行更新等操作時,都會自增1。如下所示,我們繼續使用_id
為2的文檔進行操作,因為文檔已存在,所以將會對文檔進行更新,從查詢結果可知,_version
值變成了2。
- 超時控制(timeout)
由於網絡等等原因,我們向某一索引中插入文檔時,可能遲遲得不到響應,默認情況下,1分鍾后,將返回錯誤信息,通過傳遞timeout參數,可以設置其他的超時時間。如下所示,我們將超時時間設置為5分鍾。
3 文檔批量寫入¶
ES中提供了Bulk API來支持批量操作,也就是在一個API請求中包含多個文檔操作,可以是若干個增、刪、改的操作。本篇博客我們以介紹寫入文檔為主。Bulk API請求方式如下:
POST /_bulk
POST /<target>/_bulk
使用Bulk API時,操作類型和數據內容寫在請求體中,操作類型與數據內容各占一行。上述第一種請求方式需將操作目標(索引)寫在操作類型一行中,每一個操作類型可以指定不同的目標索引。
上述例子中,執行了兩個插入操作,從返回結果可以看到,第一個插入操作因為文檔已存在,所以執行了更新操作。再來看看第二種請求方式:
可見,與第一種API請求方式在於,不需要再指定目標索引,但缺點在於所有批量操作只能針對一個索引。