先查看一條數據:
GET /ecommerce/product/5 { "_index" : "ecommerce", "_type" : "product", "_id" : "5", "_version" : 1, "found" : true, "_source" : { "name" : "gaolujie yagao2", "desc" : "gaoxiao meibai2", "price" : 31, "producer" : "gaolujie producer", "tags" : [ "meibai", "fangzhu" ] } }
1、_index元數據
(1)代表一個document存放在哪個index中
(2)類似的數據放在一個索引,非類似的數據放不同索引:product index(包含了所有的商品),sales index(包含了所有的商品銷售數據),inventory index(包含了所有庫存相關的數據)。如果你把比如product,sales,human resource(employee),全都放在一個大的index里面,比如說company index,不合適的。
2.1)類似的數據放在一個索引,因為這批數據的功能和支持的需求,可能類似,與其他不類似的數據,不在一個shard中,就不會互相影響。
2.2)類似的數據放在一個索引,也會避免了性能問題,假如不同類型的數據放在同一個index中,可能某些數據會有比較復雜的操作,非常耗時,這樣會導致讀取某些數據的時候很難,有可能超時。
(3)index中包含了很多類似的document:類似是什么意思,其實指的就是說,這些document的fields很大一部分是相同的,你說你放了3個document,每個document的fields都完全不一樣,這就不是類似了,就不太適合放到一個index里面去了。
(4)索引名稱必須是小寫的,不能用下划線開頭,不能包含逗號
2、_type元數據
(1)代表document屬於index中的哪個類別(type)
(2)一個索引通常會划分為多個type,邏輯上對index中有些許不同的幾類數據進行分類:因為一批相同的數據,可能有很多相同的fields,但是還是可能會有一些輕微的不同,可能會有少數fields是不一樣的,舉個例子,就比如說,商品,可能划分為電子商品,生鮮商品,日化商品,等等。
(3)type名稱可以是大寫或者小寫,但是同時不能用下划線開頭,不能包含逗號
3、_id元數據
(1)代表document的唯一標識,與index和type一起,可以唯一標識和定位一個document
(2)我們可以手動指定document的id(put /index/type/id),也可以不指定,由es自動為我們創建一個id
4、關於document id
1、手動指定document id
1)根據應用情況來說,是否滿足手動指定document id的前提:
一般來說,是從某些其他的系統中,導入一些數據到es時,會采取這種方式,就是使用系統中已有數據的唯一標識,作為es中document的id。舉個例子,比如說,我們現在在開發一個電商網站,做搜索功能,或者是OA系統,做員工檢索功能。這個時候,數據首先會在網站系統或者IT系統內部的數據庫中,會先有一份,此時就肯定會有一個數據庫的primary key(自增長,UUID,或者是業務編號)。如果將數據導入到es中,此時就比較適合采用數據在數據庫中已有的primary key。
如果說,我們是在做一個系統,這個系統主要的數據存儲就是es一種,也就是說,數據產生出來以后,可能就沒有id,直接就放es一個存儲,那么這個時候,可能就不太適合說手動指定document id的形式了,因為你也不知道id應該是什么,此時可以采取下面要講解的讓es自動生成id的方式。
(2)自動生成的id,長度為20個字符,URL安全(可以直接放在url中),base64編碼,GUID,分布式系統並行生成時不可能會發生沖突
4、_source元數據
_source元數據:就是說,我們在創建一個document的時候,使用的那個放在request body中的json串,默認情況下,在get的時候,會原封不動的給我們返回回來。
5、定制返回結果
定制返回的結果,指定_source中,返回哪些field
PUT /test_index/test_type/1 { "test_field1": "test field1", "test_field2": "test field2" }
GET /test_index/test_type/1?_source=test_field1 { "_index" : "test_index", "_type" : "test_type", "_id" : "1", "_version" : 1, "found" : true, "_source" : { "test_field1" : "test field1" } }
6、document的全量替換
(1)語法與創建文檔是一樣的,如果document id不存在,那么就是創建;如果document id已經存在,那么就是全量替換操作,替換document的json串內容
(2)document是不可變的,如果要修改document的內容,第一種方式就是全量替換,直接對document重新建立索引,替換里面所有的內容
(3)es會將老的document標記為deleted,然后新增我們給定的一個document,當我們創建越來越多的document的時候,es會在適當的時機在后台自動刪除標記為deleted的document
7、document的強制創建
(1)創建文檔與全量替換的語法是一樣的,有時我們只是想新建文檔,不想替換文檔,如果強制進行創建呢?
(2)PUT /index/type/id?op_type=create,PUT /index/type/id/_create
8、document的刪除
(1)DELETE /index/type/id
(2)不會理解物理刪除,只會將其標記為deleted,當數據越來越多的時候,在后台自動刪除
9、_version元數據
PUT /test_index/test_type/6 { "test_field": "test test" }
{ "_index" : "test_index", "_type" : "test_type", "_id" : "6", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 0, "_primary_term" : 4 }
第一次創建一個document的時候,它的_version內部版本號就是1;以后,每次對這個document執行修改或者刪除操作,都會對這個_version版本號自動加1;哪怕是刪除,也會對這條數據的版本號加1
接下來刪除該數據
DELETE /test_index/test_type/6 { "_index" : "test_index", "_type" : "test_type", "_id" : "6", "_version" : 2, "result" : "deleted", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 1, "_primary_term" : 4 }
然后在創建該數據
PUT /test_index/test_type/6 { "test_field": "test test" } { "_index" : "test_index", "_type" : "test_type", "_id" : "6", "_version" : 3, "result" : "created", "_shards" : { "total" : 2, "successful" : 1, "failed" : 0 }, "_seq_no" : 3, "_primary_term" : 4 }
我們會發現,在刪除一個document之后,可以從一個側面證明,它不是立即物理刪除掉的,因為它的一些版本號等信息還是保留着的。先刪除一條document,再重新創建這條document,其實會在delete version基礎之上,再把version號加1
關於es后台,多線程異步replica同步並發請求的分析:
10、document的數據路由
(1)什么是document路由到shard上
1.一個index的數據會被分為多片,每片都在一個shard中,所以說,一個document,只能存在於一個shard中
2.當客戶端創建document的時候,es此時就需要決定,這個document是放在這個index的哪個shard上的,這個過程,就稱為document routing,數據路由
(2)路由算法:shard = hash(routing) % number_of_primary_shards
舉個例子,一個index有3個primary shard,P0,P1,P2 每次增刪改查一個document的時候,都會帶過來一個routing number,默認就是這個document的_id(可能是手動指定,也可能是自動生成) routing = _id,假設_id=1 會將這個routing值,傳入一個hash函數中,產出一個routing值的hash值,hash(routing) = 21 然后將hash函數產出的值對這個index的primary shard的數量求余數,21 % 3 = 0 就決定了,這個document就放在P0上。 決定一個document在哪個shard上,最重要的一個值就是routing值,默認是_id,也可以手動指定,相同的routing值,每次過來,從hash函數中,產出的hash值一定是相同的 無論hash值是幾,無論是什么數字,對number_of_primary_shards求余數,結果一定是在0~number_of_primary_shards-1之間這個范圍內的。0,1,2。
(3)自定義routing value
默認的routing就是_id 也可以在發送請求的時候,手動指定一個routing value,比如說put /index/type/id?routing=user_id 手動指定routing value是很有用的,可以保證說,某一類document一定被路由到一個shard上去,那么在后續進行應用級別的負載均衡,以及提升批量讀取的性能的時候,是很有幫助的
(4)為什么primary shard數量不可變
1.primary shard一旦index建立,是不允許修改的。但是replica shard可以隨時修改 2.假設有3個primary shard,我們在某個index下創建一個document,id=1 ,hash=21,此時計算出的shard=21%3=0 3.如果修改為4個primary shard,則此時計算出的shard=21%4=1,結果發現沒有找到,就會間接導致數據丟失。
11、關於document的增刪改根據coordinating node(協調節點)實現路由原理
(1)客戶端選擇一個node發送請求過去,這個node就是coordinating node(協調節點) (2)coordinating node,對document進行路由,將請求轉發給對應的node(有primary shard) (3)實際的node上的primary shard處理請求,然后將數據同步到replica node (4)coordinating node,如果發現primary node和所有replica node都搞定之后,就返回響應結果給客戶端
11、關於document的寫一致性和quorum機制
寫一致性分析:
1)consistency,one(primary shard),all(all shard),quorum(default) 我們在發送任何一個增刪改操作的時候,比如說put /index/type/id,都可以帶上一個consistency參數,指明我們想要的寫一致性是什么? put /index/type/id?consistency=quorum one:要求我們這個寫操作,只要有一個primary shard是active活躍可用的,就可以執行 all:要求我們這個寫操作,必須所有的primary shard和replica shard都是活躍的,才可以執行這個寫操作 quorum:默認的值,要求所有的shard中,必須是大部分的shard都是活躍的,可用的,才可以執行這個寫操作
quorum機制:
(2)quorum機制,寫之前必須確保大多數shard都可用,int( (primary + number_of_replicas) / 2 ) + 1,當number_of_replicas>1時才生效 quroum = int( (primary + number_of_replicas) / 2 ) + 1 舉個例子,3個primary shard,number_of_replicas=1,總共有3 + 3 * 1 = 6個shard quorum = int( (3 + 1) / 2 ) + 1 = 3 所以,要求6個shard中至少有3個shard是active狀態的,才可以執行這個寫操作
(3)如果節點數少於quorum數量,可能導致quorum不齊全,進而導致無法執行任何寫操作 3個primary shard,replica=1,要求至少3個shard是active,3個shard按照之前學習的shard&replica機制,必須在不同的節點上,如果說只有2台機器的話,是不是有可能出現說,3個shard都沒法分配齊全,此時就可能會出現寫操作無法執行的情況 es提供了一種特殊的處理場景,就是說當number_of_replicas>1時才生效,因為假如說,你就一個primary shard,replica=1,此時就2個shard (1 + 1 / 2) + 1 = 2,要求必須有2個shard是活躍的,但是可能就1個node,此時就1個shard是活躍的,如果你不特殊處理的話,導致我們的單節點集群就無法工作
12、關於document的查詢根據coordinating node(協調節點)實現路由原理
1、客戶端發送請求到任意一個node,成為coordinate node(協調節點)
2、coordinate node對document進行路由,將請求轉發到對應的node,此時會使用round-robin隨機輪詢算法,在primary shard以及其所有replica中隨機選擇一個,讓讀請求負載均衡
3、接收請求的node返回document給coordinate node
4、coordinate node返回document給客戶端
5、特殊情況:document如果還在建立索引過程中,可能只有primary shard有,任何一個replica shard都沒有,此時可能會導致無法讀取到document,但是document完成索引建立之后,primary shard和replica shard就都有了
分析: