01.elasticsearch-mapping全面解析
文章目錄
- 1. es index mapping內容概述
- 2. field data type
- 1. keyword類型
- 1. string.text 分詞文本
- 2. string.keyword 關鍵字文本
- 3. numeric 數字
- 4. date 日期
- 5. date nanoseconds 納秒日期
- 6. boolean 布爾類型
- 7. binary 二進制類型
- 8. range 范圍類型的數據
- 2. 復合數據類型
- 1. object 對象類型
- 2. nested 嵌套類型
- 3. GEO 地理信息類型
- 1. geo-point類型,點表示的地理位置信息
- 2. geo-shape類型,框表示的地理位置信息,一般是標識一個區域范圍
- 簡單api樣例
- 4. 專用的數據類型
- 1. ip 類型數據
- 2. completion 類型數據,主要是為了支撐查詢提示詞自動補全功能
- 3. token count 類型,統計string中的token數量
- 4. mapper-murmurs 類型,計算value的hash值并存儲,對于一些長字段精確檢索有用
- 5. mapper-annotated-text 類型,在索引該文檔的時候增加一個特殊的mark標識
- 6. percolator 類型:索引中存儲的是query,然后允許根據document來查詢索引中的哪些query和這個doc有關
- 7. join 類型: 在一個索引中定義具有父子關系的doc
- 8. rank future 類型:一個數字類型的存儲,在query的時候允許用來作為boost的一部分時使用
- 9. rank futures 類型:多個rank future ,在query的時候允許用來作為boost的一部分時使用
- 10. dense vector : 稠密向量,float類型的向量
- 11. sparse vector: 稀疏向量,float 類型向量
- 12. search-as-you-type: 按照你的輸入查詢,類似前綴查詢,更加高效
- 13. alias 類型:是別的字段的一個別名
- 14. flattened: 把json類型的復合字段當做一個field進行索引,mapping中不會產生多個字段。
- 5. Arrays數組類型
- 6. 多字段類型支持
1. es index mapping內容概述
接下來的這個章節主要介紹es的index的mapping相關的內容。es 的index 像是mysql的一個table,而index的mapping這像是一個table的定義DDL。
比如下面的一個mysql的表定義
這個是一個mysql中的table的定義,
1.他定義了該table的name,
2.table有哪些字段field,
3.每個字段的數據類型,
4.每個字段的非空約束,
5.每個字段的默認值和說明內容,
5.還有一些是自增字段的定義AUTO_INCREMENT
6.以及一些索引的定義,PRIMARY KEY,UNIQUE KEY 等
7.table的引擎定義,字符編碼定義等
而es的index mapping的作用也和這個類似,主要是為了約束每個索引中的字段類型,同時因為es和mysql的實現不一樣,所以也會有自己的特別配置,比如分詞器等配置,數據類型支持的可能也并不一樣。當然,es還有index setting相關的設置,那個更多的是類似于對table的設置,index mapping更多的是對每個字段的定義。后面我們也會討論對index 的setting。
es mapping的內容主要有以下幾部分
2. field data type
es是一個很靈活的存儲系統,可以直接使用json文檔進行插入,即使是多層的json,json字段類型都不同也沒有關系。所以他支持的數據類型就要比較靈活才行。下面來學習一下es的數據類型。
類型集合綜述
keyword類型
復合數據類型
GEO 地理信息類型
專用的數據類型
Arrays數組類型
多字段類型
1. keyword類型
1. string.text 分詞文本
PUT my_index {"mappings": {"properties": {"full_name": {"type": "text"}}} }這個字段主要用來搜索,很少用來的做聚合操作(當然也可以做聚合操作)
可以有的設置有
analyzer
boost
eager_global_ordinals
fielddata
fields
index
index_options
index_prefixes
index_phrases
norms
position_increment_gap
store
search_analyzer
search_quote_analyzer
similarity
term_vector
這些設置被稱為mapping param,將在后續的博客進行講述
2. string.keyword 關鍵字文本
這個就是用來做filter,sort和聚合查詢使用的
PUT my_index {"mappings": {"properties": {"tags": {"type": "keyword"}}} }值得注意的是,對于數值型數據,如果不需要進行范圍查詢,像status僅僅是用來過濾的話,那么可以考慮使用keyword來存儲數值,
es的term查詢,keyword類型要比數值類型更加高效。
如果你不太確定的話,可以使用multi-field特性來保存keyword和numeric兩種類型。
可以有的設置有
boost
doc_values
eager_global_ordinals
fields
ignore_above
index
index_options
norms
null_value
store
similarity
normalizer
split_queries_on_whitespace
meta
3. numeric 數字
long : 64位整數,負的2的63次方----> 2的63次方-1
integer: 32位整數,負的2的32次方----> 2的32次方-1
short: 16位整數,-32,768 -----> 32,767.
byte: 單字節 -128 -----> 127
double: 64位浮點數,準尋IEEE 754 標準
float: 32位浮點數,準尋IEEE 754 標準
half_float: 16位浮點數,準尋IEEE 754 標準
scaled_float: 一個浮點數,由一個長整數支持,并由一個固定的雙比例縮放因子縮放
PUT my_index {"mappings": {"properties": {"number_of_bytes": {"type": "integer"},"time_in_seconds": {"type": "float"},"price": {"type": "scaled_float","scaling_factor": 100}}} }需要注意的的對于float,double,half_float類型的數據 -0.0 和 +0.0 是不相等的,查詢的之后需要注意。
選取的時候根據數值的范圍選擇夠用的即可。
可以設置的mapping param
coerce
boost
doc_values
ignore_malformed
index
null_value
store
meta
4. date 日期
因為json沒有json類型,所以es是根據下面的方式來識別date的
1.特殊類型的string,比如"2015-01-01" or “2015/01/01 12:10:30”.
2.long類型毫秒級的時間戳
3.int類型秒級時間戳
在es內部都是被轉成utc時間,然后存儲為long型的時間戳
針對date的query都被轉成了range查詢,然后在返回的時候再轉回對應的string pattern,同一個索引中的同一個date field 的數據格式可能是不一樣的,result返回的是你寫入的格式。
date類型可以設置日期的pattern(通過format屬性進行設置),默認情況下使用 strict_date_optional_time||epoch_millis作為約束
strict_date_optional_time 這個類型的要求是ISO要求的標準必須是 yyyy-MM-dd'T'HH:mm:ss.SSSZ or yyyy-MM-dd
我測驗了一下yyyy-MM-dd'T'HH:mm:ss.SSS也是可以的,也就是沒有帶Z,但是這個時候默認加了一個Z,等于是0時區的這個時間。
樣例
PUT my_index {"mappings": {"properties": {"date": {"type": "date" }}} }PUT my_index/_doc/1 { "date": "2015-01-01" } PUT my_index/_doc/2 { "date": "2015-01-01T12:10:30Z" } PUT my_index/_doc/3 { "date": 1420070400001 } 然后使用date升序查詢 GET my_index/_search {"sort": { "date": "asc"} }返回
"took" : 209,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 3,"relation" : "eq"},"max_score" : null,"hits" : [{"_index" : "my_index","_type" : "_doc","_id" : "1","_score" : null,"_source" : {"date" : "2015-01-01"},"sort" : [1420070400000]},{"_index" : "my_index","_type" : "_doc","_id" : "3","_score" : null,"_source" : {"date" : 1420070400001},"sort" : [1420070400001]},{"_index" : "my_index","_type" : "_doc","_id" : "2","_score" : null,"_source" : {"date" : "2015-01-01T12:10:30Z"},"sort" : [1420114230000]}]} }可以看到sort字段都是long類型的timestamp
同時對于_id=1的doc來說,date字段的值是 1420070400000 ,在本地服務器上轉換為本地時間
得到的是 ‘2015-01-01 08:00:00’,這也就說明了如果時間沒有攜帶時間戳,那么就是直接按照utc時間進行計算的,這樣的話,如果這個時間用來在kibana展示的時候可能會有問題,所以如果使用kibana展示的話,時間字段還是要轉成utc這種帶有時區的時間比較準確,否則在es中存儲的就是不準確的時間。
可以設置的mapping param有
boost
doc_values
format: 設置時間格式
locale
ignore_malformed
index
null_value
store
meta
你也可以自己設置format屬性,比如
PUT my_index {"mappings": {"properties": {"date": {"type": "date","format": "yyyy-MM-dd"}}} }5. date nanoseconds 納秒日期
這個存儲的是一個long的類型,標識納秒的時間戳,因為long的限制,只能表示1970-2262
在返回時再轉換成原來的格式。
date類型可以設置index時候日期的pattern,默認情況下使用 strict_date_optional_time||epoch_millis作為約束
strict_date_optional_time 這個類型的要求是ISO要求的標準必須是 yyyy-MM-dd'T'HH:mm:ss.SSSZ or yyyy-MM-dd
我測驗了一下yyyy-MM-dd'T'HH:mm:ss.SSS也是可以的,也就是沒有帶Z,但是這個時候默認加了一個Z,等于是0時區的這個時間。
但是這個時候其實是會丟失精度的,因為精度只能到毫秒級別。
建議使用 strict_date_optional_time_nanos
這個類型的格式是 yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ or yyyy-MM-dd
6. boolean 布爾類型
這個字段相對來說比較簡單,就是 true|false, 就是在index的時候可以寫入string類型的true,false
返回的時候也還是原來的文檔的模樣,也就是index的是帶字符的返回的也是帶字符的
在 term agg 查詢的時候返回的是0,1
POST my_index/_doc/1 {"is_published": true }POST my_index/_doc/2 {"is_published": false }GET my_index/_search {"aggs": {"publish_state": {"terms": {"field": "is_published"}}},"script_fields": {"is_published": {"script": {"lang": "painless","source": "doc['is_published']"}}} }返回
{"took" : 4,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "my_index","_type" : "_doc","_id" : "1","_score" : 1.0,"fields" : {"is_published" : [true]}},{"_index" : "my_index","_type" : "_doc","_id" : "2","_score" : 1.0,"fields" : {"is_published" : [false]}}]},"aggregations" : {"publish_state" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : 0,"key_as_string" : "false","doc_count" : 1},{"key" : 1,"key_as_string" : "true","doc_count" : 1}]}} }在script_field 中返回的是true,false
7. binary 二進制類型
二進制類型寫入的時候必須是base64類型的字符串,這個字段默認不會單獨存儲,而且不能被搜索。
PUT my_index {"mappings": {"properties": {"name": {"type": "text"},"blob": {"type": "binary"}}} }PUT my_index/_doc/1 {"name": "Some binary blob","blob": "U29tZSBiaW5hcnkgYmxvYg==" }可以有的mapping param
doc_values
store
8. range 范圍類型的數據
range 類型很有意思,比如淘寶經常做活動,活動都有開始時間和結束時間,正常情況下需要在mysql中使用兩個字段存儲,但是在es中只使用一個field就可存儲并且可以用來查詢。
類型有
integer_range: 范圍同integer
float_range: 范圍同float
long_range: 范圍同long
double_range: 范圍同double
date_range: 64為毫秒
ip_range: ipv4 ipv6都支持
numberic range 樣例
PUT range_index {"settings": {"number_of_shards": 2},"mappings": {"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"} }GET range_index/_search {"query" : {"term" : {"expected_attendees" : {"value": 12}}} }GET range_index/_search {"query" : {"range": {"expected_attendees": {"gte": 11,"lte": 20 }}} }GET range_index/_search {"query" : {"range": {"expected_attendees": {"gte": 10,"lte": 21,"relation" : "within"}}} }relation 標識目標文檔和當前條件的關系,within,標識目標文檔的字段范圍是條件的子集(可以完全重合)。
time range 樣例
GET range_index/_search {"query" : {"range" : {"time_frame" : { "gte" : "2015-10-31","lte" : "2015-11-01","relation" : "within" }}} }ip range 樣例
PUT range_index/_mapping {"properties": {"ip_allowlist": {"type": "ip_range"}} }PUT range_index/_doc/2 {"ip_allowlist" : "192.168.0.0/16" }GET range_index/_search {"query": {"term": {"ip_allowlist": {"value": "192.168.0.1"}}} }ip地址使用CIDR表示方法:IP地址/網絡ID的位數
比如
192.168.23.35/21
子網的網絡ID: 192.168.16.0
子網掩碼:255.255.248.0
起止IP地址: 192.168.16.1-192.168.23.254
參考這里
2. 復合數據類型
1. object 對象類型
object 是一個嵌套結構,就是內部又有一些子屬性
PUT my_index/_doc/1 { "region": "US","manager": { "age": 30,"name": { "first": "John","last": "Smith"}} }在實際的存儲當中,這個對象是展開了存儲的就像下面這樣
{"region": "US","manager.age": 30,"manager.name.first": "John","manager.name.last": "Smith" }對應的index mapping 是
PUT my_index {"mappings": {"properties": { "region": {"type": "keyword"},"manager": { "properties": {"age": { "type": "integer" },"name": { "properties": {"first": { "type": "text" },"last": { "type": "text" }}}}}}} }你不用顯式的去指定manage 或者 manage.name的type,默認就是object。
但是如果你存儲的是array類型的object的話,建議使用nested type
可以設置的mapping param
dynamic:
enabled:json是否應該被識別轉換并放進該field
properties: object 內部對應的fields
2. nested 嵌套類型
類似于object類型,區別是,如果存儲的是數組對象的話,數組中的每個對象能夠以獨立的方式被檢索出來。
PUT my_index/_doc/1 {"group" : "fans","user" : [ {"first" : "John","last" : "Smith"},{"first" : "Alice","last" : "White"}] }上面的寫入產生的的默認mapping中user就是object類型的,他的存儲會變成這樣
{"group" : "fans","user.first" : [ "alice", "john" ],"user.last" : [ "smith", "white" ] }當我們用
GET my_index/_search {"query": {"bool": {"must": [{ "match": { "user.first": "Alice" }},{ "match": { "user.last": "Smith" }}]}} }這樣的query會把這個doc查出來,這顯然是不對的。
但是當我們使用nested 類型定義的時候就不會出現這個問題了。
同時,也要使用nested query進行查詢。
由于嵌套文檔被索引為單獨的文檔,因此只能在nested查詢,nested/ reverse_nested agg 或nested inner hits 內訪問它們。
由于嵌套文檔被索引為單獨的文檔,所以包含多個nested object的數組會占用很多個doc,算是一個比較昂貴的mappings.因此es還增加了一些設置進行限制。
index.mapping.nested_fields.limit: nested field 的數量,默認50
index.mapping.nested_objects.limit: 每個doc中所有nested字段中可以存儲的nested對象的數量。
可以設置的mapping param
dynamic
properties
include_in_parent
include_in_root
3. GEO 地理信息類型
1. geo-point類型,點表示的地理位置信息
存儲的是geo的點數據,可以使用geo-box,或者distance 距離進行查詢
可以按照距離或者geographically進行agg
把score和距離相關
使用distance對doc進行sort 排序
geo-box查詢樣例
PUT my_index {"mappings": {"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/2 {"text": "Geo-point as a string","location": "41.12,-71.34" }PUT my_index/_doc/3 {"text": "Geo-point as a geohash","location": "drm3btev3e86" }PUT my_index/_doc/4 {"text": "Geo-point as an array","location": [ -71.34, 41.12 ] }PUT my_index/_doc/5 {"text": "Geo-point as a WKT POINT primitive","location" : "POINT (-71.34 41.12)" }GET my_index/_search {"query": {"geo_bounding_box": { "location": {"top_left": {"lat": 42,"lon": -72},"bottom_right": {"lat": 40,"lon": -74}}}} }可以有的mapping param
ignore_malformed
ignore_z_value: true的話,會接收3維的point數據,但是只有二維的進行索引。
null_value
2. geo-shape類型,框表示的地理位置信息,一般是標識一個區域范圍
geo-shape顧名思義,就像是range-number一樣,表達的是一個區域的地理位置
實際上他支持點,線,面 的存儲,具體的原理好像比較復雜,等后面看具體的查詢的時候再回過來看。
這里只簡單看一下支持的數據類型
支持的shape的類型
簡單api樣例
mapping param
orientation: 對于多邊形的多個點,按照什么方向連點成線再成多邊形
ignore_malformed
ignore_z_value
coerce
4. 專用的數據類型
1. ip 類型數據
可以存儲ipv4 ipv6數據
PUT my_index {"mappings": {"properties": {"ip_addr": {"type": "ip"}}} }PUT my_index/_doc/1 {"ip_addr": "192.168.1.1" }GET my_index/_search {"query": {"term": {"ip_addr": "192.168.0.0/16"}} }這里因為網絡地址是前面16位,主機地址是后面16位,所以可以查出來對應的文檔
對應的mapping param
boost
doc_values
index
null_value
store
2. completion 類型數據,主要是為了支撐查詢提示詞自動補全功能
這種類型是為了completion suggester 而創建的,就是為了查詢補全提供的功能,不具備糾錯的能力
同時es也做了很多優化使查詢很快,但是代價就是index的時候比較慢,而且都存儲于內存當中,對于數據量較小的情況下比較適合。
寫入文檔
PUT music/_doc/1?refresh {"suggest" : {"input": [ "Nevermind", "Nirvana" ],"weight" : 34} }PUT music/_doc/1?refresh {"suggest" : [{"input": "Nevermind","weight" : 10},{"input": "Nirvana","weight" : 3}] }PUT music/_doc/1?refresh {"suggest" : [ "Nevermind", "Nirvana" ] }PUT music/_doc/2?refresh {"suggest" : [ "my house is beautiful" ] }查詢文檔
POST music/_search?pretty {"suggest": {"song-suggest" : {"prefix" : "nir", "completion" : { "field" : "suggest" }}} } POST music/_search?pretty {"suggest": {"song-suggest" : {"prefix" : "nor","completion" : {"field" : "suggest","size" : 5 ,"skip_duplicates": true}}上面的查詢結果都是
... {"took" : 1,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 0,"relation" : "eq"},"max_score" : null,"hits" : [ ]},"suggest" : {"song-suggest" : [{"text" : "nir","offset" : 0,"length" : 3,"options" : [{"text" : "Nirvana","_index" : "music","_type" : "_doc","_id" : "1","_score" : 34.0,"_source" : {"suggest" : {"input" : ["Nevermind","Nirvana"],"weight" : 34}}}]}]} }下面這個查詢沒有結果,因為他只能從文檔的頭部開始命中,把house替換為my,則查詢結果就出來了
POST music/_search?pretty {"suggest": {"song-suggest" : {"prefix" : "house","completion" : {"field" : "suggest"}}} }可以使用的mapping param
analyzer : index使用的analyzer默認為simple
search_analyzer: 默認同analyzer
preserve_separators: 是否保留分割符,默認是true,如果是false, Foo Fighters的內容會被 foof的suggest的查詢命中
preserve_position_increments:
max_input_length
3. token count 類型,統計string中的token數量
token_count 類型的field實際上是一個integer類型,他接收一個text字段,然后將其分詞,存儲其token的數量,一般情況下會使用fileds功能作為一個text字段的輔助字段來使用
PUT my_index {"mappings": {"properties": {"name": { "type": "text","fields": {"length": { "type": "token_count","analyzer": "standard"}}}}} }PUT my_index/_doc/1 { "name": "John Smith" }PUT my_index/_doc/2 { "name": "Rachel Alice Williams" }GET my_index/_search {"query": {"term": {"name.length": 3 }} }mapping param
analyzer
enable_position_increments
boost
doc_values
index
null_value
store
4. mapper-murmurs 類型,計算value的hash值并存儲,對于一些長字段精確檢索有用
這個需要先裝插件才行
sudo bin/elasticsearch-plugin install mapper-murmur3 PUT my_index {"mappings": {"properties": {"my_field": {"type": "keyword","fields": {"hash": {"type": "murmur3"}}}}} } # Example documents PUT my_index/_doc/1 {"my_field": "This is a document" }PUT my_index/_doc/2 {"my_field": "This is another document" }GET my_index/_search {"aggs": {"my_field_cardinality": {"cardinality": {"field": "my_field.hash" }}} }使用hash進行聚合操作的話效率會高出很多。
5. mapper-annotated-text 類型,在索引該文檔的時候增加一個特殊的mark標識
類似于命名實體識別能力,給一個field 進行標記,增加一些特定的詞匯
這個也要插件支持
使用樣例
PUT my_index {"mappings": {"properties": {"my_field": {"type": "annotated_text"}}} }PUT my_index/_doc/1 {"my_field": "[Beck](Beck) announced a new tour" }PUT my_index/_doc/2 {"my_field": "[Jeff Beck](Jeff+Beck&Guitarist) plays a strat" }# Example search GET my_index/_search {"query": {"term": {"my_field": "Beck" }} }這種情況下只有第一個文檔會被檢索出來,第二個不會
因為 Jeff Beck 這個是一個固定的格式,中括號中的會被識別為一個token,小括號內會識別成同義詞。
比如下面的實驗
GET my_index/_analyze {"field": "my_field","text":"Investors in [Apple](Apple+Inc.) rejoiced." }返回
{"tokens": [{"token": "investors","start_offset": 0,"end_offset": 9,"type": "<ALPHANUM>","position": 0},{"token": "in","start_offset": 10,"end_offset": 12,"type": "<ALPHANUM>","position": 1},{"token": "Apple Inc.", "start_offset": 13,"end_offset": 18,"type": "annotation","position": 2},{"token": "apple","start_offset": 13,"end_offset": 18,"type": "<ALPHANUM>","position": 2},{"token": "rejoiced","start_offset": 19,"end_offset": 27,"type": "<ALPHANUM>","position": 3}] }可以看到apple 和Apple Inc. 的索引位置position是一樣的,被識別為同義詞一樣的東西。
6. percolator 類型:索引中存儲的是query,然后允許根據document來查詢索引中的哪些query和這個doc有關
這個可能是在需要對文檔進行反向查詢的時候使用更加合適,參考這里
舉例:提供一個存儲用戶興趣的平臺,以便在每次有新內容進入時將正確的內容(通知警報)發送給正確的用戶。
舉例:用戶訂閱了特定主題,以便一旦該主題的新文章出現,就會向感興趣的用戶發送通知。
有些對doc進行分類的意思
應用場景如下:
價格監控
新聞警報
…
他的使用方式是
但是實際上使用起來看著有點不是很習慣,可能還是看的少
PUT index {"mappings": {"properties": {"query" : {"type" : "percolator"},"body" : {"type": "text"}}} }PUT index/_doc/1?refresh {"query" : {"match" : {"body" : "quick brown fox"}} }PUT index/_doc/2?refresh {"query" : {"match" : {"body" : "fox jumps over"}} }GET /index/_search {"query": {"percolate" : {"field" : "query","document" : {"body" : "fox jumps over the lazy dog"}}} }返回
{"took" : 6,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.39229372,"hits" : [{"_index" : "index","_type" : "_doc","_id" : "2","_score" : 0.39229372,"_source" : {"query" : {"match" : {"body" : "fox jumps over"}}},"fields" : {"_percolator_document_slot" : [0]}},{"_index" : "index","_type" : "_doc","_id" : "1","_score" : 0.13076457,"_source" : {"query" : {"match" : {"body" : "quick brown fox"}}},"fields" : {"_percolator_document_slot" : [0]}}]} }這個返回的結構似乎和其他的略有不同
樣例二
PUT percolator {"mappings": {"properties": {"dsl":{"type": "percolator"},"message":{"type": "text"}}} }POST percolator/_doc/2 {"dsl": {"match": {"message": "to be better or bad " # 這里dsl字段中使用的query對應的message字段必須在percolator 的mapping當中已經定義了才能正常的使用}} }GET percolator/_search {"query": {"percolate": {"field": "dsl","document": {"message":"bad information"}}} }返回 "hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 0.13076457,"hits" : [{"_index" : "percolator","_type" : "_doc","_id" : "2","_score" : 0.13076457,"_source" : {"dsl" : {"match" : {"message" : "to be better or bad "}}},"fields" : {"_percolator_document_slot" : [0]}}]}percolator 的查詢原理是存儲 query到index01中,然后使用document查詢的時候,使用該doc對query進行一次召回,然后再將該doc創建內存索引index02,使用召回的query在index02中進行查詢,然后進行相關度打分并返回
7. join 類型: 在一個索引中定義具有父子關系的doc
join 類型主要是輔助你在一個索引中定義具有父子關系的doc
使用樣例
PUT my_index {"mappings": {"properties": {"my_join_field": { "type": "join","relations": {"question": "answer" }}}} }PUT my_index/_doc/1?refresh {"text": "This is a question","my_join_field": {"name": "question" } }PUT my_index/_doc/2?refresh {"text": "This is another question","my_join_field": {"name": "question"} }PUT my_index/_doc/3?routing=1&refresh {"text": "This is an answer","my_join_field": {"name": "answer", "parent": "1" } }PUT my_index/_doc/4?routing=1&refresh {"text": "This is another answer","my_join_field": {"name": "answer","parent": "1"} }GET my_index/_search查詢返回
... "hits" : {"total" : {"value" : 4,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "my_index","_type" : "_doc","_id" : "1","_score" : 1.0,"_source" : {"text" : "This is a question","my_join_field" : {"name" : "question"}}},{"_index" : "my_index","_type" : "_doc","_id" : "2","_score" : 1.0,"_source" : {"text" : "This is another question","my_join_field" : {"name" : "question"}}},{"_index" : "my_index","_type" : "_doc","_id" : "3","_score" : 1.0,"_routing" : "1","_source" : {"text" : "This is an answer","my_join_field" : {"name" : "answer","parent" : "1"}}},{"_index" : "my_index","_type" : "_doc","_id" : "4","_score" : 1.0,"_routing" : "1","_source" : {"text" : "This is another answer","my_join_field" : {"name" : "answer","parent" : "1"}}}]}然后使用更加復雜的查詢試試
GET my_index/_search {"query": {"parent_id": { "type": "answer","id": "1"}},"aggs": {"parents": {"terms": {"field": "my_join_field#question", "size": 10}}},"script_fields": {"parent": {"script": {"source": "doc['my_join_field#question']" }}} }查詢返回
"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.35667494,"hits" : [{"_index" : "my_index","_type" : "_doc","_id" : "3","_score" : 0.35667494,"_routing" : "1","fields" : {"parent" : ["1"]}},{"_index" : "my_index","_type" : "_doc","_id" : "4","_score" : 0.35667494,"_routing" : "1","fields" : {"parent" : ["1"]}}]},"aggregations" : {"parents" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : "1","doc_count" : 2}]}}為了加速join查詢,會使用全局基數來進行加速,這就需要當前shard的doc發生變化之后重建全局基數。parent id越多,重建的代價也約高。
對于有join field的index來說,全局基數默認會進行重建,重建的任務稱為refresh任務的一部分。
如果禁用了立即重建,會在第一次使用join查詢或者agg查詢的時候進行重建,有可能導致查詢超時。
同時使用上還有一些限制
感覺這個在大規模的數據當中使用可能還是會有一些性能問題,尤其是那種頻繁更新的數據。
8. rank future 類型:一個數字類型的存儲,在query的時候允許用來作為boost的一部分時使用
聽說這個是es支持機器學習的一個部分
查詢的時候也必須用rank_feture 查詢哦,就是一種特殊的查詢,類似term,match_all 等,具體看下面的例子
查詢返回
{"took" : 1,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.5142857,"hits" : [{"_shard" : "[my_index][0]","_node" : "ADi2c-NmTnWhTmb2dDlCeA","_index" : "my_index","_type" : "_doc","_id" : "2","_score" : 0.5142857,"_source" : {"pagerank" : 9,"url_length" : 22},"_explanation" : {"value" : 0.5142857,"description" : "Saturation function on the _feature field for the pagerank feature, computed as w * S / (S + k) from:","details" : [{"value" : 1.0,"description" : "w, weight of this function","details" : [ ]},{"value" : 8.5,"description" : "k, pivot feature value that would give a score contribution equal to w/2","details" : [ ]},{"value" : 9.0,"description" : "S, feature value","details" : [ ]}]}},{"_shard" : "[my_index][0]","_node" : "ADi2c-NmTnWhTmb2dDlCeA","_index" : "my_index","_type" : "_doc","_id" : "1","_score" : 0.4848485,"_source" : {"pagerank" : 8,"url_length" : 22},"_explanation" : {"value" : 0.4848485,"description" : "Saturation function on the _feature field for the pagerank feature, computed as w * S / (S + k) from:","details" : [{"value" : 1.0,"description" : "w, weight of this function","details" : [ ]},{"value" : 8.5,"description" : "k, pivot feature value that would give a score contribution equal to w/2","details" : [ ]},{"value" : 8.0,"description" : "S, feature value","details" : [ ]}]}}]} }這個公式我暫時先不聊,應該在rank_feature query中會再出現的。
9. rank futures 類型:多個rank future ,在query的時候允許用來作為boost的一部分時使用
這個和上一個類似,只是可以存儲特征向量
使用樣例
PUT my_index {"mappings": {"properties": {"topics": {"type": "rank_features" }}} }PUT my_index/_doc/1 {"topics": { "politics": 20,"economics": 50.8} }PUT my_index/_doc/2 {"topics": {"politics": 5.2,"sports": 80.1} }GET my_index/_search {"query": {"rank_feature": {"field": "topics.politics"}} }10. dense vector : 稠密向量,float類型的向量
稠密向量,這個簡直是顧名思義,哈哈
一般是用來計算文檔的score的時候使用
理論上一個向量的維度不應該超過1024
返回
"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.5674877,"hits" : [{"_index" : "my_index","_type" : "_doc","_id" : "1","_score" : 0.5674877,"_source" : {"my_text" : "text1","my_vector" : [0.5,10,6]}},{"_index" : "my_index","_type" : "_doc","_id" : "2","_score" : 0.4035343,"_source" : {"my_text" : "text2","my_vector" : [-0.5,10,10]}}]}11. sparse vector: 稀疏向量,float 類型向量
稀疏向量,為了應對多維度但是又比較稀疏的向量
DELETE my_index PUT my_index {"mappings": {"properties": {"my_vector": {"type": "sparse_vector"},"my_text" : {"type" : "keyword"}}} }PUT my_index/_doc/1 {"my_text" : "text1","my_vector" : {"1": 0.5, "5": -0.5, "100": 1} }PUT my_index/_doc/2 {"my_text" : "text2","my_vector" : {"103": 0.5, "4": -0.5, "5": 1, "11" : 1.2} }GET my_index/_search {"query": {"script_score": {"query": {"match_all": {}},"script": {"source": "cosineSimilaritySparse(params.queryVector, doc['my_vector'])","params": {"queryVector": {"2": 0.5, "10" : 111.3, "50": -1.3, "113": 14.8, "4545": 156.0}}}}} }返回
..."hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.0,"hits" : [{"_index" : "my_index","_type" : "_doc","_id" : "1","_score" : 0.0,"_source" : {"my_text" : "text1","my_vector" : {"1" : 0.5,"5" : -0.5,"100" : 1}}},{"_index" : "my_index","_type" : "_doc","_id" : "2","_score" : 0.0,"_source" : {"my_text" : "text2","my_vector" : {"103" : 0.5,"4" : -0.5,"5" : 1,"11" : 1.2}}}]}12. search-as-you-type: 按照你的輸入查詢,類似前綴查詢,更加高效
感覺這個有點類似prefix query,底層做了不少優化,使查詢的效率更高
但是代價是增加了不少存儲。看下面的一個例子
上面的mapping會產生下面幾個字段
my_field: 使用對應的analyzer 產生該字段的token
my_field._2gram: 使用shingle token filter 對my_field產出的token按照2gram處理形成當前字段的token
my_field._3gram: 使用shingle token filter 對my_field產出的token按照3gram處理形成當前字段的token
my_field._index_prefix: 使用 edge ngram token filter 對my_field._3gram產出的token進行處理形成當前字段的token
使用analyze api測試
POST my_index/_analyze {"field": "my_field","text": ["quick brown fox "]}返回{"tokens" : [{"token" : "quick","start_offset" : 0,"end_offset" : 5,"type" : "<ALPHANUM>","position" : 0},{"token" : "brown","start_offset" : 6,"end_offset" : 11,"type" : "<ALPHANUM>","position" : 1},{"token" : "fox","start_offset" : 12,"end_offset" : 15,"type" : "<ALPHANUM>","position" : 2}] }測試2gram
POST my_index/_analyze {"field": "my_field._2gram","text": ["quick brown fox"]}返回 {"tokens" : [{"token" : "quick brown","start_offset" : 0,"end_offset" : 11,"type" : "shingle","position" : 0},{"token" : "brown fox","start_offset" : 6,"end_offset" : 15,"type" : "shingle","position" : 1}] }測試3gram
POST my_index/_analyze {"field": "my_field._3gram","text": ["quick brown fox"]}返回 {"tokens" : [{"token" : "quick brown fox","start_offset" : 0,"end_offset" : 15,"type" : "shingle","position" : 0}] }測試_index_prefix
POST my_index/_analyze {"field": "my_field._index_prefix","text": ["quick brown fox"]}返回{"tokens" : [{"token" : "q", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "qu", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "qui", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quic", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick ", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick b", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick br", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick bro", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick brow", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick brown", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick brown ", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick brown f", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick brown fo", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "quick brown fox", "start_offset" : 0, "end_offset" : 15, "type" : "shingle", "position" : 0 },{"token" : "b", "start_offset" : 6, "end_offset" : 15, "type" : "shingle", "position" : 1 },{"token" : "br", "start_offset" : 6, "end_offset" : 15, "type" : "shingle", "position" : 1 },{"token" : "bro", "start_offset" : 6, "end_offset" : 15, "type" : "shingle", "position" : 1 },{"token" : "brow", "start_offset" : 6, "end_offset" : 15, "type" : "shingle", "position" : 1 },{"token" : "brown", "start_offset" : 6, "end_offset" : 15, "type" : "shingle", "position" : 1 },{"token" : "brown ", "start_offset" : 6, "end_offset" : 15, "type" : "shingle", "position" : 1 },{"token" : "brown f", "start_offset" : 6, "end_offset" : 15, "type" : "shingle", "position" : 1 },{"token" : "brown fo", "start_offset" : 6, "end_offset" : 15, "type" : "shingle", "position" : 1 },{"token" : "brown fox", "start_offset" : 6, "end_offset" : 15, "type" : "shingle", "position" : 1 },{"token" : "brown fox ", "start_offset" : 6, "end_offset" : 15, "type" : "shingle", "position" : 1 },{"token" : "f", "start_offset" : 12, "end_offset" : 15, "type" : "shingle", "position" : 2 },{"token" : "fo", "start_offset" : 12, "end_offset" : 15, "type" : "shingle", "position" : 2 },{"token" : "fox", "start_offset" : 12, "end_offset" : 15, "type" : "shingle", "position" : 2 },{"token" : "fox ", "start_offset" : 12, "end_offset" : 15, "type" : "shingle", "position" : 2 },{"token" : "fox ", "start_offset" : 12, "end_offset" : 15, "type" : "shingle", "position" : 2 }] }這里因為產出的數據太多,所以為了方便并航,做了處理
至于為什么是這個樣子,還不是很清晰,感覺對于單個詞都增加了一個空格,好奇怪
比如下面這個樣子的
POST my_index/_analyze {"field": "my_field._3gram","text": ["quick"]}返回 {"tokens" : [ ] }POST my_index/_analyze {"field": "my_field._index_prefix","text": ["quick"]}返回 {"tokens" : [{"token" : "q", "start_offset" : 0, "end_offset" : 5, "type" : "shingle", "position" : 0 },{"token" : "qu", "start_offset" : 0, "end_offset" : 5, "type" : "shingle", "position" : 0 },{"token" : "qui", "start_offset" : 0, "end_offset" : 5, "type" : "shingle", "position" : 0 },{"token" : "quic", "start_offset" : 0, "end_offset" : 5, "type" : "shingle", "position" : 0 },{"token" : "quick", "start_offset" : 0, "end_offset" : 5, "type" : "shingle", "position" : 0 },{"token" : "quick ", "start_offset" : 0, "end_offset" : 5, "type" : "shingle", "position" : 0 },{"token" : "quick ", "start_offset" : 0, "end_offset" : 5, "type" : "shingle", "position" : 0 }] }可以看到也會多出來兩個空格,不知道是干什么用的。
13. alias 類型:是別的字段的一個別名
這個就是對一個字段設置別名,感覺作用好像不是很大,這個別名search操作起來和對別名指向的真實field一樣,但是對于index和update操作則是不行的。
樣例
PUT trips {"mappings": {"properties": {"distance": {"type": "long"},"route_length_miles": {"type": "alias","path": "distance" },"transit_mode": {"type": "keyword"}}} }PUT trips/_doc/1 {"distance":12345 }PUT trips/_doc/2 {"distance":12 }GET trips/_search {"query": {"range" : {"route_length_miles" : {"lte" : 39}}} }14. flattened: 把json類型的復合字段當做一個field進行索引,mapping中不會產生多個字段。
這個的作用,對于一個對象字需要定一個一個filed mapping,他內部將各個層級個字段處理成了類似keyword進行存儲,這樣就可以用更簡單的方式來進行查詢。
實際上這個的作用也沒有看太明白。唯一的好處就是防止了mapping爆炸吧。
使用樣例
PUT bug_reports {"mappings": {"properties": {"title": {"type": "text"},"labels": {"type": "flattened"}}} }POST bug_reports/_doc/1 {"title": "Results are not sorted correctly.","labels": {"priority": "urgent","release": ["v1.2.5", "v1.3.0"],"timestamp": {"created": 1541458026,"closed": 1541457010}} }POST bug_reports/_search {"query": {"term": {"labels": "urgent"}} }POST bug_reports/_search {"query": {"term": {"labels.release": "v1.3.0"}} }這些查詢都能正常使用
他的使用和keyword有很多相似之處。
可以支持的查詢有
可以設置的mapping param
boost
depth_limit
doc_values
eager_global_ordinals
ignore_above
index
index_options
null_value
similarity
split_queries_on_whitespace : full text query 是不是應該被空格切分。
5. Arrays數組類型
es天然支持了數組類型, 假如是動態類型的話,加入的第一個doc中的當前filed的類型決定了數據的類型,數組中類型要保持一致性。
像 [ 10, "some string" ]這樣的數據也是會報錯的。
樣例
PUT my_index/_doc/1 {"message": "some arrays in this document...","tags": [ "elasticsearch", "wow" ], "lists": [ {"name": "prog_list","description": "programming list"},{"name": "cool_list","description": "cool stuff list"}] }PUT my_index/_doc/2 {"message": "no arrays in this document...","tags": "elasticsearch","lists": {"name": "prog_list","description": "programming list"} }GET my_index/_search {"query": {"match": {"tags": "elasticsearch" }} }可以看到第二個文檔不是數組但是還是可以正常的加入進去,所以說es對數組的支持是自然的,主要是因為lucene的設計的支持,lucene將text分成了多個token存儲,所以很方便的可以存儲數組。
6. 多字段類型支持
就是說一個字段可以通過不同的存儲方式存進索引,主要是通過mapping param中的 fields 特性來支持
樣例
PUT my_index {"mappings": {"properties": {"city": {"type": "text","fields": {"raw": { "type": "keyword"}}}}} }總結
以上是生活随笔為你收集整理的01.elasticsearch-mapping全面解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 05.analysis-normaliz
- 下一篇: 02.elasticsearch-met