DSL查詢ES文件
1.DSL查詢分類
Elasticsearch提供了基於JSON的DSL(
-
查詢所有:查詢出所有資料,一般測試用。例如:match_all
-
全文檢索(full text)查詢:利用分詞器對使用者輸入內容分詞,然後去倒排索引庫中匹配。例如:
-
match_query
-
multi_match_query
-
-
精確查詢:根據精確詞條值查詢資料,一般是查詢keyword、數值、日期、boolean等型別欄位。例如:
-
ids
-
range
-
term
-
-
地理(geo)查詢:根據經緯度查詢。例如:
-
geo_distance
-
geo_bounding_box
-
-
複合(compound)查詢:複合查詢可以將上述各種查詢條件組合起來,合併查詢條件。例如:
-
bool
-
function_score
-
查詢的語法基本一致:
GET/{索引名稱}/_search { "query":{ "查詢型別":{ "查詢條件":"條件值" } } }
我們以查詢所有為例,其中:
-
查詢型別為match_all
-
沒有查詢條件
// 查詢所有 GET/indexName/_search { "query":{ "match_all":{ } } }
使用場景
全文檢索查詢的基本流程如下:
-
對使用者搜尋的內容做分詞,得到詞條
-
根據詞條去倒排索引庫中匹配,得到文件id
-
根據文件id找到文件,返回給使用者
比較常用的場景包括:
-
商城的輸入框搜尋
-
百度輸入框搜尋
基本語法
常見的全文檢索查詢包括:
-
match查詢:單欄位查詢
-
multi_match查詢:多欄位查詢,任意一個欄位符合條件就算符合查詢條件
match查詢語法如下:
GET/indexName/_search { "query":{ "match":{ "FIELD":"TEXT" } } }
mulit_match語法如下:
GET/indexName/_search { "query":{ "multi_match":{ "query":"TEXT", "fields":["FIELD1"," FIELD12"] } } }
match查詢示例:
multi_match查詢示例:
可以看到,兩種查詢結果是一樣的,為什麼?
因為我們將brand、name、business值都利用copy_to複製到了all欄位中。因此你根據三個欄位搜尋,和根據all欄位搜尋效果當然一樣了。
但是,搜尋欄位越多,對查詢效能影響越大,因此建議採用copy_to,然後單欄位查詢的方式。
match和multi_match的區別是什麼?
-
match:根據一個欄位查詢
-
multi_match:根據多個欄位查詢,參與查詢欄位越多,查詢效能越差
精確查詢一般是查詢keyword、數值、日期、boolean等型別欄位。所以不會對搜尋條件分詞。常見的有:
-
term:根據詞條精確值查詢
-
range:根據值的範圍查詢
term查詢
因為精確查詢的欄位搜是不分詞的欄位,因此查詢的條件也必須是不分詞的詞條。查詢時,使用者輸入的內容跟自動值完全匹配時才認為符合條件。如果使用者輸入的內容過多,反而搜尋不到資料。
語法說明:
//term查詢 GET/indexName/_search { "query":{ "term":{ "FIELD":{ "value":"VALUE" } } } }
當我搜索的是精確詞條時,能正確查詢出結果:
但是,當我搜索的內容不是詞條,而是多個詞語形成的短語時,反而搜尋不到:
range查詢
範圍查詢,一般應用在對數值型別做範圍過濾的時候。比如做價格範圍過濾。
基本語法:
//range查詢 GET/indexName/_search { "query":{ "range":{ "FIELD":{ "gte":10, // 這裡的gte代表大於等於,gt則代表大於 "lte":20 // lte代表小於等於,lt則代表小於 } } } }
示例:
總結
精確查詢常見的有哪些?
-
term查詢:根據詞條精確匹配,一般搜尋keyword型別、數值型別、布林型別、日期型別欄位
-
range查詢:根據數值範圍查詢,可以是數值、日期的範圍
4.地理座標查詢
矩形範圍查詢,也就是geo_bounding_box查詢,查詢座標落在某個矩形範圍的所有文件:
查詢時,需要指定矩形的左上、右下兩個點的座標,然後畫出一個矩形,落在該矩形內的都是符合條件的點。
語法如下:
//geo_bounding_box查詢 GET/indexName/_search { "query":{ "geo_bounding_box":{ "FIELD":{ "top_left":{ // 左上點 "lat":31.1, "lon":121.5 }, "bottom_right":{ // 右下點 "lat":30.9, "lon":121.7 } } } } }
附近查詢
附近查詢,也叫做距離查詢(geo_distance):查詢到指定中心點小於某個距離值的所有文件。
換句話來說,在地圖上找一個點作為圓心,以指定距離為半徑,畫一個圓,落在圓內的座標都算符合條件:
語法說明:
//geo_distance 查詢 GET/indexName/_search { "query":{ "geo_distance":{ "distance":"15km", // 半徑 "FIELD":"31.21,121.5" // 圓心 } } }
示例:
我們先搜尋陸家嘴附近15km的酒店:
發現共有47家酒店。
然後把半徑縮短到3公里:
可以發現,搜尋到的酒店數量減少到了5家。
5.複合查詢
複合(compound)查詢:複合查詢可以將其它簡單查詢組合起來,實現更復雜的搜尋邏輯。常見的有兩種:
-
fuction score:算分函式查詢,可以控制文件相關性算分,控制文件排名
-
bool query:布林查詢,利用邏輯關係組合多個其它的查詢,實現複雜搜尋
根據相關度打分是比較合理的需求,但合理的不一定是產品經理需要的。
以百度為例,你搜索的結果中,並不是相關度越高排名越靠前,而是誰掏的錢多排名就越靠前。
要想認為控制相關性算分,就需要利用elasticsearch中的function score 查詢了。
1)語法說明
function score 查詢中包含四部分內容:
-
原始查詢條件:query部分,基於這個條件搜尋文件,並且基於BM25演算法給文件打分,原始算分(query score)
-
過濾條件:filter部分,符合該條件的文件才會重新算分
-
算分函式:符合filter條件的文件要根據這個函式做運算,得到的函式算分(function score),有四種函式
-
weight:函式結果是常量
-
field_value_factor:以文件中的某個欄位值作為函式結果
-
random_score:以隨機數作為函式結果
-
script_score:自定義算分函式演算法
-
-
運算模式:算分函式的結果、原始查詢的相關性算分,兩者之間的運算方式,包括:
-
multiply:相乘
-
replace:用function score替換query score
-
其它,例如:sum、avg、max、min
-
function score的執行流程如下:
-
1)根據原始條件查詢搜尋文件,並且計算相關性算分,稱為原始算分(query score)
-
2)根據過濾條件,過濾文件
-
3)符合過濾條件的文件,基於算分函式運算,得到函式算分(function score)
-
4)將原始算分(query score)和函式算分(function score)基於運算模式做運算,得到最終結果,作為相關性算分。
因此,其中的關鍵點是:
-
過濾條件:決定哪些文件的算分被修改
-
算分函式:決定函式算分的演算法
-
運算模式:決定最終算分結果
2)示例
需求:給“如家”這個品牌的酒店排名靠前一些
翻譯一下這個需求,轉換為之前說的四個要點:
-
原始條件:不確定,可以任意變化
-
過濾條件:brand = "如家"
-
算分函式:可以簡單粗暴,直接給固定的算分結果,weight
-
運算模式:比如求和
因此最終的DSL語句如下:
GET/hotel/_search { "query":{ "function_score":{ "query":{ .... }, // 原始查詢,可以是任意條件 "functions":[//算分函式 { "filter":{//滿足的條件,品牌必須是如家 "term":{ "brand":"如家" } }, "weight":2//算分權重為2 } ], "boost_mode": "sum" // 加權模式,求和 } } }
測試,在未新增算分函式時,如家得分如下:
添加了算分函式後,如家得分就提升了:
3)小結
function score query定義的三要素是什麼?
-
過濾條件:哪些文件要加分
-
算分函式:如何計算function score
-
加權方式:function score 與 query score如何運算