mapping json中包含了諸如properties
,matadata(_id,_source,_type)
,settings(analyzer)
已經其餘的settingshtml
PUT my_index { "mappings": { "my_index": { "properties": { "my_field1": { "type": "integer" }, "my_field2": { "type": "float" }, "my_field2": { "type": "scaled_float", "scaling_factor": 100 } } } } }
當咱們往ES中插入一條document時,它裏面包含了多個fireld, 此時,ES會自動的將多個field的值,串聯成一個字符串,做爲_all屬性,同時會創建索引,當用戶再次檢索卻沒有指定查詢的字段 時,就會在這個_all中進行匹配前端
示例:node
# Example documents PUT my_index/_doc/1 { "title": "This is a document" } PUT my_index/_doc/2?refresh=true { "title": "This is another document", "body": "This document has a body" } GET my_index/_search { "query": { "terms": { "_field_names": [ "title" ] } } }
禁用:程序員
PUT tweets { "mappings": { "_doc": { "_field_names": { "enabled": false } } } }
shard_num = hash(_routing) % num_primary_shards
能夠像下面這樣定製路由規則es6
PUT my_index/_doc/1?routing=user1&refresh=true { "title": "This is a document" } GET my_index/_doc/1?routing=user1
禁用算法
PUT tweets { "mappings": { "_doc": { "_source": { "enabled": false } } } }
這個字段標識doc的類型,是一個邏輯上的劃分, field中的value在頂層的lucene創建索引的時候,所有使用的opaque bytes類型,不區分類型的lucene是沒有type概念的, 在document中,實際上將type做爲一個document的field,什麼field呢? _type
sql
ES會經過_type
進行type的過濾和篩選,一個index中是存放的多個type其實是存放在一塊兒的,所以一個index下,不可能存在多個重名的typejson
首先一點,在ES5中容許建立多個index,這在ES6中繼續被沿用,可是在ES7將被廢棄,甚至在ES8中將被完全刪除跨域
其次:在一開始咱們將Elastic的index必作Mysql中的database, 將type比做table,其實這種比喻是錯誤的,由於在Mysql中不一樣表之間的列在物理上是沒有關係的,各自佔有本身的空間,可是在ES中不是這樣,可能type=Student中的name和type=Teacher中的name在存儲在徹底相同的字段中,換句話說,type是在邏輯上的劃分,而不是在物理上的劃分數組
這個copy_to其實是在容許咱們自定義一個_all字段, 程序員能夠將多個字段的值複製到一個字段中,而後再次檢索時目標字段就使用咱們經過copy_to建立出來的_all新字段中
它解決了一個什麼問題呢? 假設咱們檢索的field的value="John Smith",可是doc中存放名字的field卻有兩個,分別是firstName和lastName中,就意味着cross field檢索,這樣一來再通過TF-IDF算法一算,可能結果就不是咱們預期的樣子,所以使用copy_to 作這件事
示例:
PUT my_index { "mappings": { "_doc": { "properties": { "first_name": { "type": "text", "copy_to": "full_name" }, "last_name": { "type": "text", "copy_to": "full_name" }, "full_name": { "type": "text" } } } } } PUT my_index/_doc/1 { "first_name": "John", "last_name": "Smith" } GET my_index/_search { "query": { "match": { "full_name": { "query": "John Smith", "operator": "and" } } } }
ES使用_type
來描述doc字段的類型,原來咱們直接往ES中存儲數據,並無指定字段的類型,緣由是ES存在類型推斷,默認的mapping中定義了每一個field對應的數據類型以及如何進行分詞
null --> no field add true flase --> boolean 123 --> long 123.123 --> double 1999-11-11 --> date "hello world" --> string Object --> object
示例
PUT /my_index/ { "mappings":{ "dynamic":"strict" } }
PUT my_index { "mappings": { "_doc": { "date_detection": false } } } PUT my_index/_doc/1 { "create": "2015/09/02" }
PUT my_index { "mappings": { "_doc": { "dynamic_date_formats": ["MM/dd/yyyy"] } } } PUT my_index/_doc/1 { "create_date": "09/25/2015" }
PUT my_index { "mappings": { "_doc": { "numeric_detection": true } } } PUT my_index/_doc/1 { "my_float": "1.0", "my_integer": "1" }
各類類型的使用及範圍參見官網,點擊進入
long, integer, short, byte, double, float, half_float, scaled_float
示例:
PUT my_index { "mappings": { "_doc": { "properties": { "number_of_bytes": { "type": "integer" }, "time_in_seconds": { "type": "float" }, "price": { "type": "scaled_float", "scaling_factor": 100 } } } } }
date
示例:
PUT my_index { "mappings": { "_doc": { "properties": { "date": { "type": "date" } } } } } PUT my_index/_doc/1 { "date": "2015-01-01" }
string類型的字符串能夠被ES解釋成boolean
boolean
示例:
PUT my_index { "mappings": { "_doc": { "properties": { "is_published": { "type": "boolean" } } } } }
binary
示例
PUT my_index { "mappings": { "_doc": { "properties": { "name": { "type": "text" }, "blob": { "type": "binary" } } } } } PUT my_index/_doc/1 { "name": "Some binary blob", "blob": "U29tZSBiaW5hcnkgYmxvYg==" }
integer_range, float_range, long_range, double_range, date_range
示例
PUT range_index { "settings": { "number_of_shards": 2 }, "mappings": { "_doc": { "properties": { "expected_attendees": { "type": "integer_range" }, "time_frame": { "type": "date_range", "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } } } } PUT range_index/_doc/1?refresh { "expected_attendees" : { "gte" : 10, "lte" : 20 }, "time_frame" : { "gte" : "2015-10-31 12:00:00", "lte" : "2015-11-01" } }
對象類型,嵌套對象類型
示例:
PUT my_index/_doc/1 { "region": "US", "manager": { "age": 30, "name": { "first": "John", "last": "Smith" } } }
在ES內部這些值被轉換成這種樣式
{ "region": "US", "manager.age": 30, "manager.name.first": "John", "manager.name.last": "Smith" }
ES支持地理上的定位點
PUT my_index { "mappings": { "_doc": { "properties": { "location": { "type": "geo_point" } } } } } PUT my_index/_doc/1 { "text": "Geo-point as an object", "location": { "lat": 41.12, "lon": -71.34 } } PUT my_index/_doc/4 { "text": "Geo-point as an array", "location": [ -71.34, 41.12 ] }
更多內容參見官網**,點擊進入
GET /index/_mapping/type
能夠給現存的type添加field,可是不能修改,不然就會報錯
PUT twitter { "mappings": { "user": { "properties": { "name": { "type": "text" , # 會被所有檢索 "analyzer":"english" # 指定當前field使用 english分詞器 }, "user_name": { "type": "keyword" }, "email": { "type": "keyword" } } }, "tweet": { "properties": { "content": { "type": "text" }, "user_name": { "type": "keyword" }, "tweeted_at": { "type": "date" }, "tweeted_at": { "type": "date" "index": "not_analyzeed" # 設置爲當前field tweeted_at不能被分詞 } } } } }
Object類型
{ "address":{ "province":"shandong", "city":"dezhou" }, "name":"zhangsan", "age":"12" }
轉換
{ "name" : [zhangsan], "name" : [12], "address.province" : [shandong], "address.city" : [dezhou] }
Object數組類型
{ "address":[ {"age":"12","name":"張三"}, {"age":"12","name":"張三"}, {"age":"12","name":"張三"} ] }
轉換
{ "address.age" : [12,12,12], "address.name" : [張三,張三,張三] }
搜索時,輸入的value必須和目標徹底一致纔算做命中
"query": { "match_phrase": { "address": "mill lane" } }, # 短語檢索 address徹底匹配 milllane纔算命中,返回
全文檢索時存在各類優化處理以下:
示例
GET /_search { "query": { "match" : { "message" : "this is a test" } } }
倒排索引指向全部document分詞的field
假設咱們存在這樣兩句話
doc1 : hello world you and me doc2 : hi world how are you
創建倒排索引就是這樣
- | doc1 | doc2 |
---|---|---|
hello | * | - |
world | * | * |
you | * | * |
and | * | - |
me | * | - |
hi | - | * |
how | - | * |
are | - | * |
這時,咱們拿着hello world you 來檢索,通過分詞後去上面索引中檢索,doc12都會被檢索出,可是doc1命中了更多的詞,所以doc1得分會更高
doc value
實際上指向全部不分詞的document的field
ES中,進行搜索動做時須要藉助倒排索引,可是在排序,聚合,過濾時,須要藉助正排索引,所謂正排索引就是其doc value在創建正排索引時一遍創建正排索引一遍創建倒排索引, doc value
會被保存在磁盤上,若是內存充足也會將其保存在內存中
正排索引大概長這樣
document | name | age |
---|---|---|
doc1 | 張三 | 12 |
doc2 | 李四 | 34 |
正排索引也會寫入磁盤文件 中,而後os cache會對其進行緩存,以提成訪問doc value
的速度,當OS Cache中內存大小不夠存放整個正排索引時,doc value
中的值會被寫入到磁盤中
關於性能方面的問題: ES官方建議,大量使用OS
Cache來進行緩存和提高性能,不建議使用jvm內存來進行緩存數據,那樣會致使必定的gc開銷,甚至可能致使oom問題,因此官方的建議是,給JVM更小的內存,給OS Cache更大的內存, 假如咱們的機器64g,只須要給JVM 16g便可
doc value
存儲壓縮 -- column
壓縮爲了減小doc value佔用內存空間的大小,採用column對其進行壓縮, 好比咱們存在三個doc, 以下
doc 1: 550 doc 2: 550 doc 3: 500
合併相同值,doc1,doc2的值相同都是550,保存一個550標識便可
如: doc1: 24 doc2 :36 除以最大公約數 6 doc1: 4 doc2 : 6 保存下最大公約數6
doc value
假設,咱們不使用聚合等操做,爲了節省空間,在建立mappings
時,能夠選擇禁用doc value
PUT /index { "mappings":{ "my_type":{ "properties":{ "my_field":{ "type":"text", "doc_values":false # 禁用doc value } } } } }
relevance score 相關度評分算法, 直白說就是算出一個索引中的文本和搜索文本之間的類似程度
Elasticsearch使用的是 TF-IDF算法 (term-frequency / inverser document frequency)
向量空間模式
ES會根據用戶輸入的詞條在全部document中的評分狀況計算出一個空間向量模型 vector model, 他是空間向量中的一個點
而後會針對全部的doc都計算出一個vector model出來, 將這個
若是存在多個term,那麼就是一個多維空間向量之間的運算,可是咱們假設是二維的,就像下面這張圖
一目瞭然,Doc2和目標詞條之間的弧度小,因而認爲他們最類似,它的得分也就越高
咱們使用分詞將將一段話拆分紅一個一個的單詞,甚至進一步對分出來的單詞進行詞性的轉換,師太的轉換,單複數的轉換的操做, 爲何使用分詞器? 就是爲了提升檢索時的召回率,讓更多的doc被檢索到
在一段文本在分詞前先進行預處理,好比過濾html標籤, 將特殊符號轉換成123..這種阿拉伯數字等特殊符號的轉換
進行分詞,拆解句子,記錄詞條的位置(在當前doc中佔第幾個位置term position)及順序
進行同義詞的轉換,去除同義詞,單複數的轉換等等
每個分片地位相同,都能接受請求,處理請求,噹噹用戶的一個請求發送到某一個shard中後,這個shard會自動就請求路由到真正存儲數據的shard上去,可是最終老是由接受請求的節點響應請求
圖解: master的選舉,容錯,以及數據的恢復
如上圖爲初始狀態圖
假如,圖上的第一個節點是master節點,而且它掛掉,在掛掉的一瞬間,整個cluster的status=red,表示存在數據丟失了集羣不可用
下面要作的第一步就是完成master的選舉,自動在剩下的節點中選出一個節點當成master節點, 第二步選出master節點後,這個新的master節點會將Po在第三個節點中存在一個replica shard提高爲primary shard,此時cluster 的 status = yellow,表示集羣中的數據是能夠被訪問的可是存在部分replica shard不可用,第三步,從新啓動由於故障宕機的node,而且將右邊兩個節點中的數據拷貝到第一個節點中,進行數據的恢復
ES內部的多線程異步併發修改時,是經過_version版本號進行併發控制的,每次建立一個document,它的_version內部版本號都是1,之後對這個doc的修改,刪除都會使這個版本號增1
ES的內部需在Primary shard 和 replica shard之間同步數據,這就意味着多個修改請求實際上是亂序的不必定按照前後順序執行
相關語法:
PUT /index/type/2?version=1{ "name":"XXX" }
上面的命令中URL中的存在?version=1
,此時,若是存在其餘客戶端將id=2的這條記錄修改過,致使id=2的版本號不等於1了,那麼這條PUT語句將會失敗並有相應的錯誤提示
基於external的版本號控制,ES提供了一個Futrue,也就是說用戶可使用本身維護的版本號進行併發訪問控制,好比:
PUT /index/type/2?version=1&version_type=external
假設當前ES中的版本號是1, 那麼只有當用戶提供的版本號大於1時,PUT纔會成功
一個index被分紅了多個shard,文檔被隨機的存在某一個分片上,客戶端一個請求打向index中的一個分片,可是請求的doc可能不存在於這個分片上,接受請求的shard會將請求路由到真正存儲數據的shard上,這個過程叫作數據路由
其中接受到客戶端請求的節點稱爲coordinate node,協調節點,好比如今是客戶端往服務端修改一條消息,接受A接受到請求了,那麼A就是 coordnate node協調節點,數據存儲在B primary shard 上,那麼協調節點就會將請求路由到B primary shard中,B處理完成後再向 B replica shard同步數據,數據同步完成後,B primary shard響應 coordinate node, 最後協調節點響應客戶端結果
shard = hash(routing) % number_of_primary_shards
其實這個公式並不複雜,能夠將上面的routing當成doc的id,不管是用戶執行的仍是自動生成的,反正確定是惟一,既然是惟一的通過每次hash獲得的結果也是同樣的, 這樣一個惟一的數對主分片的數進行取餘數,獲得的結果就會在0-最大分片數之間
能夠手動指定routing value的值,好比PUT /index/type/id?routing=user_id
,在保證這類doc必定被路由到指定的shard上,並且後續進行應用級負載均衡時會批量提高讀取的性能
咱們在發送任何一個增刪改查時,均可以帶上一個 consistency 參數,指明咱們想要的寫一致性是什麼,以下
PUT /index/type/id?consistency=quorum
有哪些可選參數呢?
quorum數量的計算公式: int((primary+number_of_replicas)/2)+1, 算一算,假如咱們的集羣中存在三個node,replica=1,那麼cluster中就存在3+3*1=6個shard
int((3+1)/2)+1 = 3
結果顯示,咱們只有當quorum=3,即replica_shard=3時,集羣纔是可用的,可是當咱們的單機部署時,因爲ES不容許同一個server的primary_shard和replica_shard共存,也就是說咱們的replica數目爲0,爲何ES依然能夠用呢? 這是ES提供了一種特殊的處理場景,即當number_of_replicas>1時纔會生效
quorum不全時,集羣進入wait()狀態, 默認1分鐘,,在等待期間,指望活躍的shard的數量能夠增長,到最後都沒有知足這個數量的話就會timeout
咱們在寫入時也可使用timeout參數, 好比: PUT /index/type/id?timeout=30
經過本身設置超時時間來縮短超時時間
用戶的寫請求將doc寫入內存緩衝區,寫的動做被記錄在translog日誌文件中,每隔一秒中內存中的數據就會被刷新到index segment file中,index segment file中的數據隨機被刷新到os cache中,而後index segement file處理打開狀態,對外提供檢索服務,ES會重複這個過程,每次重複這個過程時,都會先清空內存buffer,處理打開狀態的 index segment file能夠對外提供檢索
直到translog日誌文件體積太大了,就會進一步觸發flush操做,這個flush操做會將buffer中所有數據刷新進新的segment file中,將index segment file刷新進os cache, 寫一個commit point 到磁盤上,標註有哪些index segment,並將OS cache中的數據刷新到OS Disk中,完成數據的持久化
上面的flush動做,默認每隔30分鐘執行一次,或者當translog文件體積過大時也會自動flush
數據恢復時,是基於translog文件和commit point二者判斷,究竟哪些數據在日誌中存在記錄,卻沒有被持久化到OSDisk中,從新執行日誌中的邏輯,等待下一次的flush完成持久化
看上面的圖中,爲了實現近實時的搜索,每1秒鐘就會產生一個segment文件,文件數目會特別多,而恰巧對外提供搜索的就是這些segment文件,所以ES會在後臺進行segement 文件的合併,在合併的時候,被標記deleted的docment會會被完全的物理刪除
每次merge的操做流程