ElasticSearch 文件併發處理以及文件路由
@[toc]
ElasticSearch 系列教程我們前面已經連著發了兩篇了,今天第三篇,我們來聊一聊 Es 中的文件併發處理和文件路由問題。
本文是松哥所錄影片教程的一個筆記,筆記簡明扼要,完整內容小夥伴們可以參考影片,影片下載連結:pan.baidu.com/s/1TwyOm2i28fDZh7rkNF-jww 提取碼: aee2
1. ElasticSearch 文件基本操作
1.1 新建文件
首先新建一個索引。
然後向索引中新增一個文件:
PUT blog/_doc/1
{
"title":"6. ElasticSearch 文件基本操作",
"date":"2020-11-05",
"content":"微信公眾號**江南一點雨**後臺回覆 **elasticsearch06** 下載本筆記。首先新建一個索引。"
}
1 表示新建文件的 id。
新增成功後,響應的 json 如下:
{
"_index" : "blog",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
- _index 表示文件索引。
- _type 表示文件的型別。
- _id 表示文件的 id。
- _version 表示文件的版本(更新文件,版本會自動加 1,針對一個文件的)。
- result 表示執行結果。
- _shards 表示分片資訊。
-
_seq_no
和_primary_term
這兩個也是版本控制用的(針對當前 index)。
新增成功後,可以檢視新增的文件:
當然,新增文件時,也可以不指定 id,此時系統會預設給出一個 id,如果不指定 id,則需要使用 POST 請求,而不能使用 PUT 請求。
POST blog/_doc
{
"title":"666",
"date":"2020-11-05",
"content":"微信公眾號**江南一點雨**後臺回覆 **elasticsearch06** 下載本筆記。首先新建一個索引。"
}
1.2 獲取文件
Es 中提供了 GET API 來檢視儲存在 es 中的文件。使用方式如下:
GET blog/_doc/RuWrl3UByGJWB5WucKtP
上面這個命令表示獲取一個 id 為 RuWrl3UByGJWB5WucKtP 的文件。
如果獲取不存在的文件,會返回如下資訊:
{
"_index" : "blog",
"_type" : "_doc",
"_id" : "2",
"found" : false
}
如果僅僅只是想探測某一個文件是否存在,可以使用 head 請求:
如果文件不存在,響應如下:
如果文件存在,響應如下:
當然也可以批次獲取文件。
GET blog/_mget
{
"ids":["1","RuWrl3UByGJWB5WucKtP"]
}
這裡可能有小夥伴有疑問,GET 請求竟然可以攜帶請求體?
某些特定的語言,例如 JavaScript 的 HTTP 請求庫是不允許 GET 請求有請求體的,實際上在 RFC7231 文件中,並沒有規定 GET 請求的請求體該如何處理,這樣造成了一定程度的混亂,有的 HTTP 伺服器支援 GET 請求攜帶請求體,有的 HTTP 伺服器則不支援。雖然 es 工程師傾向於使用 GET 做查詢,但是為了保證相容性,es 同時也支援使用 POST 查詢。例如上面的批次查詢案例,也可以使用 POST 請求。
1.3 文件更新
1.3.1 普通更新
注意,文件更新一次,version 就會自增 1。
可以直接更新整個文件:
PUT blog/_doc/RuWrl3UByGJWB5WucKtP
{
"title":"666"
}
這種方式,更新的文件會覆蓋掉原文件。
大多數時候,我們只是想更新文件欄位,這個可以透過指令碼來實現。
POST blog/_update/1
{
"script": {
"lang": "painless",
"source":"ctx._source.title=params.title",
"params": {
"title":"666666"
}
}
}
更新的請求格式: POST {index}/_update/{id}
在指令碼中,lang 表示指令碼語言,painless 是 es 內建的一種指令碼語言。source 表示具體執行的指令碼,ctx 是一個上下文物件,透過 ctx 可以訪問到 _source
、_title
等。
也可以向文件中新增欄位:
POST blog/_update/1
{
"script": {
"lang": "painless",
"source":"ctx._source.tags=["java","php"]"
}
}
新增成功後的文件如下:
透過指令碼語言,也可以修改陣列。例如再增加一個 tag:
POST blog/_update/1
{
"script":{
"lang": "painless",
"source":"ctx._source.tags.add("js")"
}
}
當然,也可以使用 if else 構造稍微複雜一點的邏輯。
POST blog/_update/1
{
"script": {
"lang": "painless",
"source": "if (ctx._source.tags.contains("java")){ctx.op="delete"}else{ctx.op="none"}"
}
}
1.3.2 查詢更新
透過條件查詢找到文件,然後再去更新。
例如將 title 中包含 666 的文件的 content 修改為 888。
POST blog/_update_by_query
{
"script": {
"source": "ctx._source.content="888"",
"lang": "painless"
},
"query": {
"term": {
"title":"666"
}
}
}
1.4 刪除文件
1.4.1 根據 id 刪除
從索引中刪除一個文件。
刪除一個 id 為 TuUpmHUByGJWB5WuMasV 的文件。
DELETE blog/_doc/TuUpmHUByGJWB5WuMasV
如果在新增文件時指定了路由,則刪除文件時也需要指定路由,否則刪除失敗。
1.4.2 查詢刪除
查詢刪除是 POST 請求。
例如刪除 title 中包含 666 的文件:
POST blog/_delete_by_query
{
"query":{
"term":{
"title":"666"
}
}
}
也可以刪除某一個索引下的所有文件:
POST blog/_delete_by_query
{
"query":{
"match_all":{
}
}
}
1.5 批次操作
es 中透過 Bulk API 可以執行批次索引、批次刪除、批次更新等操作。
首先需要將所有的批次操作寫入一個 JSON 檔案中,然後透過 POST 請求將該 JSON 檔案上傳並執行。
例如新建一個名為 aaa.json 的檔案,內容如下:
首先第一行:index 表示要執行一個索引操作(這個表示一個 action,其他的 action 還有 create,delete,update)。_index
定義了索引名稱,這裡表示要建立一個名為 user 的索引,_id
表示新建文件的 id 為 666。
第二行是第一行操作的引數。
第三行的 update 則表示要更新。
第四行是第三行的引數。
注意,結尾要空出一行。
aaa.json 檔案建立成功後,在該目錄下,執行請求命令,如下:
curl -XPOST "" -H "content-type:application/json" --data-binary @aaa.json
執行完成後,就會建立一個名為 user 的索引,同時向該索引中新增一條記錄,再修改該記錄,最終結果如下:
2. ElasticSearch 文件路由
es 是一個分散式系統,當我們儲存一個文件到 es 上之後,這個文件實際上是被儲存到 master 節點中的某一個主分片上。
例如新建一個索引,該索引有兩個分片,0個副本,如下:
接下來,向該索引中儲存一個文件:
PUT blog/_doc/a
{
"title":"a"
}
文件儲存成功後,可以檢視該文件被儲存到哪個分片中去了:
GET _cat/shards/blog?v
檢視結果如下:
index shard prirep state docs store ip node
blog 1 p STARTED 0 208b 127.0.0.1 slave01
blog 0 p STARTED 1 3.6kb 127.0.0.1 master
從這個結果中,可以看出,文件被儲存到分片 0 中。
那麼 es 中到底是按照什麼樣的規則去分配分片的?
es 中的路由機制是透過雜湊演算法,將具有相同雜湊值的文件放到一個主分片中,分片位置的計算方式如下:
shard=hash(routing) % number_of_primary_shards
routing 可以是一個任意字串,es 預設是將文件的 id 作為 routing 值,透過雜湊函式根據 routing 生成一個數字,然後將該數字和分片數取餘,取餘的結果就是分片的位置。
預設的這種路由模式,最大的優勢在於負載均衡,這種方式可以保證資料平均分配在不同的分片上。但是他有一個很大的劣勢,就是查詢時候無法確定文件的位置,此時它會將請求廣播到所有的分片上去執行。另一方面,使用預設的路由模式,後期修改分片數量不方便。
當然開發者也可以自定義 routing 的值,方式如下:
PUT blog/_doc/d?routing=javaboy
{
"title":"d"
}
如果文件在新增時指定了 routing,則查詢、刪除、更新時也需要指定 routing。
GET blog/_doc/d?routing=javaboy
自定義 routing 有可能會導致負載不均衡,這個還是要結合實際情況選擇。
典型場景:
對於使用者資料,我們可以將 userid 作為 routing,這樣就能保證同一個使用者的資料儲存在同一個分片中,檢索時,同樣使用 userid 作為 routing,這樣就可以精準的從某一個分片中獲取資料。
3. ElasticSearch 版本控制
當我們使用 es 的 API 去進行文件更新時,它首先讀取原文件出來,然後對原文件進行更新,更新完成後再重新索引整個文件。不論你執行多少次更新,最終儲存在 es 中的是最後一次更新的文件。但是如果有兩個執行緒同時去更新,就有可能出問題。
要解決問題,就是鎖。
3.1 鎖
悲觀鎖
很悲觀,每一次去讀取資料的時候,都認為別人可能會修改資料,所以遮蔽一切可能破壞資料完整性的操作。關係型資料庫中,悲觀鎖使用較多,例如行鎖、表鎖等等。
樂觀鎖
很樂觀,每次讀取資料時,都認為別人不會修改資料,因此也不鎖定資料,只有在提交資料時,才會檢查資料完整性。這種方式可以省去鎖的開銷,進而提高吞吐量。
在 es 中,實際上使用的就是樂觀鎖。
3.2 版本控制
es6.7之前
在 es6.7 之前,使用 version+version_type 來進行樂觀併發控制。根據前面的介紹,文件每被修改一個,version 就會自增一次,es 透過 version 欄位來確保所有的操作都有序進行。
version 分為內部版本控制和外部版本控制。
3.2.1 內部版本
es 自己維護的就是內部版本,當建立一個文件時,es 會給文件的版本賦值為 1。
每當使用者修改一次文件,版本號就回自增 1。
如果使用內部版本,es 要求 version 引數的值必須和 es 文件中 version 的值相當,才能操作成功。
3.2.2 外部版本
也可以維護外部版本。
在新增文件時,就指定版本號:
PUT blog/_doc/1?version=200&version_type=external
{
"title":"2222"
}
以後更新的時候,版本要大於已有的版本號。
- vertion_type=external 或者 vertion_type=external_gt 表示以後更新的時候,版本要大於已有的版本號。
- vertion_type=external_gte 表示以後更新的時候,版本要大於等於已有的版本號。
3.2.3 最新方案(Es6.7 之後)
現在使用 if_seq_no
和 if_primary_term
兩個引數來做併發控制。
seq_no
不屬於某一個文件,它是屬於整個索引的(version 則是屬於某一個文件的,每個文件的 version 互不影響)。現在更新文件時,使用 seq_no
來做併發。由於 seq_no
是屬於整個 index 的,所以任何文件的修改或者新增,seq_no
都會自增。
現在就可以透過 seq_no
和 primary_term
來做樂觀併發控制。
PUT blog/_doc/2?if_seq_no=5&if_primary_term=1
{
"title":"6666"
}
最後,松哥還蒐集了 50+ 個專案需求文件,想做個專案練練手的小夥伴不妨看看哦~
需求文件地址:github.com/lenve/javadoc
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4479/viewspace-2826609/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- jQuery 篩選&文件處理jQuery
- Apache POI處理Excel文件ApacheExcel
- Elasticsearch 刪除文件Elasticsearch
- Elasticsearch安裝文件Elasticsearch
- ElasticSearch 文件及操作Elasticsearch
- Elasticsearch6.5中文文件-刪除文件Elasticsearch
- 用於處理wps文件的快捷鍵,wps文件的快捷鍵大全
- ComPDFKit - 專業的PDF文件處理SDK
- 從零玩轉jQuery-文件處理jQuery
- 【筆記】jQuery原始碼(文件處理3)筆記jQuery原始碼
- 文件處理效能飆升!浩鯨科技“文件大模型”核心技術揭秘!大模型
- SharePlex安裝配置、常用功能配置文件、常見故障處理文件
- Elasticsearch——併發衝突以及解決方案Elasticsearch
- Postgres併發處理
- MySQL 併發處理MySql
- ElasticSearch核心概念和文件的CRUDElasticsearch
- Elasticsearch——叢集管理及文件CRUDElasticsearch
- 從資料提取到管理:合合資訊的智慧文件處理全方位解析【合合資訊智慧文件處理百寶箱】
- 處理併發衝突
- Elasticsearch——分散式文件系統之documentElasticsearch分散式
- 技術文件:基於 Python 的影像處理系統Python
- web前端分享:效能最佳化之文件碎片處理Web前端
- Koa v2.x 中文文件 錯誤處理
- 併發問題處理方式
- ElasticSearch 文件(document)內部機制詳解Elasticsearch
- .Net Api 之如何使用Elasticsearch儲存文件APIElasticsearch
- 【Elasticsearch學習】文件搜尋全過程Elasticsearch
- vue路由處理Vue路由
- 手寫 p-map(控制併發數以及迭代處理 promise 的庫)Promise
- 智慧文件處理IDP關鍵技術與實踐-高翔
- PDFsam Basic for mac合併拆分PDF文件Mac
- 聊聊介面最大併發處理數
- 前端優化之高併發處理前端優化
- 海量資料的併發處理
- 達觀智慧文件審閱系統,推動證券非結構化文件處理提質提效
- MyScript 開發文件
- Python基礎教程:Day15-影象和辦公文件處理Python
- 使用dumi生成react元件庫文件併發布到github pagesReact元件Github