Elasticsearch檢索分類深入詳解—基礎篇
題記
Elasticsearch中當我們設定Mapping(分詞器、欄位型別)完畢後,就可以按照設定的方式匯入資料。
有了資料後,我們就需要對資料進行檢索操作。根據實際開發需要,往往我們需要支援包含但不限於以下型別的檢索: 1)精確匹配,類似mysql中的 “=”操作; 2)模糊匹配,類似mysql中的”like %關鍵詞% “查詢操作; 3)字首匹配; 4)萬用字元匹配; 5)正則表示式匹配; 6)跨索引匹配; 7)提升精讀匹配。
細數一下,我們的痛點在於: 1)ES究竟支援哪些檢索操作? 2)如何實現ES精確值檢索、指定索引檢索、全文檢索?
這些就是本文著重參考ES最新官方文件,針對ES5.X版本探討的內容。 0、檢索概覽
檢索子句的行為取決於查詢應用於過濾(filter)上下文還是查詢/分析(query)上下文。
過濾上下文——對應於結構化檢索
1)核心回答的問題是:“這個文件是否符合這個查詢條款?”
2)答案是簡單的是或否,不計算分數。
3)過濾器上下文主要用於過濾結構化資料。類似於Mysql中判定某個欄位是否存在:
1 2 3 4 5
例如: a. 時間戳欄位:是否屬於2015年或2016年? b. 狀態欄位:是否設定為“已釋出”?
經常使用的過濾器將被Elasticsearch**自動快取,以加快效能**。
分析上下文——對應於全文檢索 1)核心回答了“本文件與此查詢子句是否匹配?”的問題。
2)除了決定文件是否匹配之外,查詢子句還會計算一個_score,表示文件與其他文件的匹配程度。
綜合應用場景如下:
GET /_search { "query": { "bool": { "must": [ { "match": { "title": "Search" }}, { "match": { "content": "Elasticsearch" }} ], "filter": [ { "term": { "status": "published" }}, { "range": { "publish_date": { "gte": "2015-01-01" }}} ] } } }
1 2 3 4 5 6 7 8 9 10 11
以上檢索,title中包含”Search”並且content中包含 “Elasticsearch”,status中精確匹配”published”,並且publish_date 大於“2015-01-01”的全部資訊。
以下,以“腦圖”的形式直觀展示檢索分類。 這裡寫圖片描述 其中,3-7根據我隨著我開發深入再做更新。
以下內容的原文需要參考ES官方文件(隨著版本變化,後續會有更新) 1、結構化檢索
針對欄位型別: 日期、時間、數字型別,以及精確的文字匹配。 結構化檢索特點: * 1)結構化查詢,我們得到的結果 總是 非是即否,要麼存於集合之中,要麼存在集合之外。 * 2)結構化查詢不關心檔案的相關度或評分;它簡單的對文件包括或排除處理。 1.1 精確值查詢 1.1.1 單個精確值查詢(term query)
term 查詢會查詢我們指定的精確值。term 查詢是簡單的,它接受一個欄位名以及我們希望查詢的數值。
想要類似mysql中如下sql語句的查詢操作:
SELECT document FROM products WHERE price = 20; DSL寫法:
GET /my_store/products/_search { "query" : { "term" : { "price" : 20 } } }
1 2 3 4 5 6 7 8
當進行精確值查詢時, 我們會使用過濾器(filters)。過濾器很重要,因為它們執行速度非常快,不會計算相關度(直接跳過了整個評分階段)而且很容易被快取。如下: 使用 constant_score 查詢以非評分模式來執行 term 查詢並以一作為統一評分。
GET /my_store/products/_search { "query" : { "constant_score" : { "filter" : { "term" : { "price" : 20 } } } } }
1 2 3 4 5 6 7 8 9 10 11 12
注意:5.xES中,對於字串型別,要進行精確值匹配。需要講型別設定為text和keyword兩種型別。mapping設定如下:
POST testindex/testtype/_mapping { "testtype ":{ "properties":{ "title":{ "type":"text", "analyzer":"ik_max_word", "search_analyzer":"ik_max_word", "fields":{ "keyword":{ "type":"keyword" } } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
精確值java api jest使用方法: searchSourceBuilder.query(QueryBuilders.termQuery(“text.keyword”, “來自新華社的報道”)); 1.1.2 布林過濾器
一個 bool 過濾器由三部分組成:
{ "bool" : { "must" : [], "should" : [], "must_not" : [], "filter": [] } }
1 2 3 4 5 6 7 8
must ——所有的語句都 必須(must) 匹配,與 AND 等價。 must_not ——所有的語句都 不能(must not) 匹配,與 NOT 等價。 should ——至少有一個語句要匹配,與 OR 等價。 filter——必須匹配,執行在非評分&過濾模式。 就這麼簡單! 當我們需要多個過濾器時,只須將它們置入 bool 過濾器的不同部分即可。
舉例:
GET /my_store/products/_search { "query" : { "filtered" : { "filter" : { "bool" : { "should" : [ { "term" : {"price" : 20}},
{ "term" : {"productID" : "XHDK-A-1293-#fJ3"}}
], "must_not" : { "term" : {"price" : 30}
} } } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
1.1.3 多個值精確查詢(terms query)
{ "terms" : { "price" : [20, 30] } }
1 2 3 4 5
如上,terms是包含的意思,包含20或者包含30。 如下實現嚴格意義的精確值檢索, tag_count代表必須匹配的次數為1。
GET /my_index/my_type/_search { "query": { "constant_score" : { "filter" : { "bool" : { "must" : [ { "term" : { "tags" : "search" } }, { "term" : { "tag_count" : 1 } } ] } } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1.2 範圍檢索(range query)
range 查詢可同時提供包含(inclusive)和不包含(exclusive)這兩種範圍表示式,可供組合的選項如下:
gt: > 大於(greater than) lt: < 小於(less than) gte: >= 大於或等於(greater than or equal to) lte: <= 小於或等於(less than or equal to)
1 2 3 4
類似Mysql中的範圍查詢:
SELECT document FROM products WHERE price BETWEEN 20 AND 40
1 2 3
ES中對應的DSL如下:
GET /my_store/products/_search { "query" : { "constant_score" : { "filter" : { "range" : { "price" : { "gte" : 20, "lt" : 40 } } } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1.3 存在與否檢索(exist query)
mysql中,有如下sql: SELECT tags FROM posts WHERE tags IS NOT NULL;
ES中,exist查詢某個欄位是否存在:
GET /my_index/posts/_search { "query" : { "constant_score" : { "filter" : { "exists" : { "field" : "tags" } } } } }
1 2 3 4 5 6 7 8 9 10
若想要exist查詢能匹配null型別,需要設定mapping:
"user": { "type": "keyword", "null_value": "_null_" }
1 2 3 4
missing查詢在5.x版本已經不存在,改成如下的判定形式:
GET /_search { "query": { "bool": { "must_not": { "exists": { "field": "user" } } } } }
1 2 3 4 5 6 7 8 9 10 11 12
1.4 字首檢索( Prefix Query )
匹配包含 not analyzed 的字首字元:
GET /_search { "query": { "prefix" : { "user" : "ki" } } }
1 2 3 4 5
1.5 萬用字元檢索( wildcard query)
匹配具有匹配萬用字元表示式( (not analyzed )的欄位的文件。 支援的萬用字元: 1)*,它匹配任何字元序列(包括空字元序列); 2)?,它匹配任何單個字元。 請注意,此查詢可能很慢,因為它需要遍歷多個術語。 為了防止非常慢的萬用字元查詢,萬用字元不能以任何一個萬用字元*或?開頭。 舉例:
GET /_search { "query": { "wildcard" : { "user" : "ki*y" } } }
1 2 3 4 5 6
1.6 正則表示式檢索(regexp query)
正則表示式查詢允許您使用正則表示式術語查詢。 舉例如下:
GET /_search { "query": { "regexp":{ "name.first": "s.*y" } } }
1 2 3 4 5 6 7 8
注意: *的匹配會非常慢,你需要使用一個長的字首, 通常類似.*?+萬用字元查詢的正則檢索效能會非常低。 1.7 模糊檢索(fuzzy query)
模糊查詢查詢在模糊度中指定的最大編輯距離內的所有可能的匹配項,然後檢查術語字典,以找出在索引中實際存在待檢索的關鍵詞。 舉例如下:
GET /_search { "query": { "fuzzy" : { "user" : "ki" } } }
1 2 3 4 5 6
1.8 型別檢索(type query)
舉例:
GET /my_index/_search { "query": { "type" : { "value" : "xext" } } }
1 2 3 4 5 6 7 8
已驗證,檢索索引my_index中,type為xext的全部資訊。 1.9 Ids檢索(ids query)
返回指定id的全部資訊。
GET /my_index/_search { "query": { "ids" : { "type" : "xext", "values" : ["2", "4", "100"] } } }
1 2 3 4 5 6 7 8 9
2、全文檢索
高階全文查詢通常用於在全文字欄位(如電子郵件正文)上執行全文查詢。他們瞭解如何對被查詢的欄位進行分析,並在執行前將每個欄位的分析器(或search_analyzer)應用於查詢字串。 2.1 匹配檢索(match query)
匹配查詢接受文字/數字/日期型別,分析它們,並構造查詢。 1)匹配查詢的型別為boolean。 這意味著分析所提供的文字,並且分析過程從提供的文字構造一個布林查詢, 可以將運算子標誌設定為或以控制布林子句(預設為或); 2)文字分析取決於mapping中設定的analyzer(中文分詞,我們預設選擇ik分詞器); 3) fuzziness——模糊性允許基於被查詢的欄位的型別進行模糊匹配; 4)”operator”: “and”——匹配與操作(預設或操作); 5) “minimum_should_match”: “75%”——這讓我們可以指定必須匹配的詞項數用來表示一個文件是否相關。 舉例:
GET /_search { "query": { "match" : { "message" : { "query" : "this is a test", "operator" : "and" } } } }
1 2 3 4 5 6 7 8 9 10 11
2.2 匹配解析檢索 match_phrase query
match_phrase查詢分析文字,並從分析文字中建立短語查詢。 類似 match 查詢, match_phrase 查詢首先將查詢字串解析成一個詞項列表,然後對這些詞項進行搜尋,但只保留那些包含 全部 搜尋詞項,且 位置 與搜尋詞項相同的文件。 舉例如下:對於 quick fox 的短語搜尋可能不會匹配到任何文件,因為沒有文件包含的 quick 詞之後緊跟著 fox 。
GET /my_index/my_type/_search { "query": { "match_phrase": { "title": "quick brown fox" } } }
1 2 3 4 5 6 7 8
2.3 匹配解析字首檢索(match_phrase_prefix)
使用者已經漸漸習慣在輸完查詢內容之前,就能為他們展現搜尋結果,這就是所謂的 即時搜尋(instant search) 或 輸入即搜尋(search-as-you-type) 。 不僅使用者能在更短的時間內得到搜尋結果,我們也能引導使用者搜尋索引中真實存在的結果。 例如,如果使用者輸入 johnnie walker bl ,我們希望在它們完成輸入搜尋條件前就能得到: Johnnie Walker Black Label 和 Johnnie Walker Blue Label 。
match_phrase_prefix與match_phrase相同,除了它允許文字中最後一個術語的字首匹配。 舉例:
GET / _search { “query”:{ “match_phrase_prefix”:{ “message”:“quick brown f” } } }
1 2 3 4 5 6 7 8
2.4 多欄位匹配檢索( multi_match query)
multi_match 查詢為能在多個欄位上反覆執行相同查詢提供了一種便捷方式。 預設情況下,查詢的型別是 best_fields, 這表示它會為每個欄位生成一個 match 查詢。 舉例1:”fields”: “*_title” ——任何與模糊模式正則匹配的欄位都會被包括在搜尋條件中, 例如可以左側的方式同時匹配 book_title 、 chapter_title 和 section_title (書名、章名、節名)這三個欄位。 舉例2: “fields”: [ “*_title”, “chapter_title^2” ] ——可以使用 ^ 字元語法為單個欄位提升權重,在欄位名稱的末尾新增 ^boost , 其中 boost 是一個浮點數。 舉例3:”fields”: [ “first_name”, “last_name” ], “operator”: “and” ——兩個欄位必須都包含。
GET /_search { "query": { "multi_match" : { "query": "this is a test", "fields": [ "subject", "message" ] } } }
1 2 3 4 5 6 7 8 9
2.5 字串檢索(query_string)
一個使用查詢解析器解析其內容的查詢。 query_string查詢提供了以簡明的簡寫語法執行多匹配查詢 multi_match queries ,布林查詢 bool queries ,提升得分 boosting ,模糊匹配 fuzzy matching ,萬用字元 wildcards ,正則表示式 regexp 和範圍查詢 range queries 的方式。 支援引數達10幾種。
GET /_search { "query": { "query_string" : { "default_field" : "content", "query" : "this AND that OR thus" } } }
1 2 3 4 5 6 7 8 9
2.6 簡化字串檢索(simple_query_string)
一個使用SimpleQueryParser解析其上下文的查詢。 與常規query_string查詢不同,simple_query_string查詢永遠不會丟擲異常,並丟棄查詢的無效部分。 舉例:
GET /_search { "query": { "simple_query_string" : { "fields" : ["content"], "query" : "foo bar -baz" } } }
1 2 3 4 5 6 7 8 9
支援的操作如下: 1)+表示AND操作 2)| 表示OR操作 3)- 否定操作 4)*在術語結束時表示字首查詢 5)(和)表示優先 3 小結
有的博友可能會問,這和ES官網API有什麼區別。 仔細對比你會發現,ES的中文文件是根據2.X版本翻譯的,ES的英文文件一個版本是沒有更新到5.X版本,另一個已經更新。 當我們進行相關檢索查詢的時候,文件結構一篇一篇翻查,很零散、很不繫統。 本文內容綜合了幾個官網文件,結合自己的實戰經驗進行了總結,是對我開發和認知的梳理。 --------------------- 作者:銘毅天下 來源:CSDN 原文:https://blog.csdn.net/laoyang360/article/details/77623013 版權宣告:本文為博主原創文章,轉載請附上博文連結!