探索ElasticSearch-深入搜尋之全文搜尋(八)
前言
學習需要先打好基礎,最後才能逐步深入。今天來重新探索下ElasticSearch
的全文搜尋。
搜尋
ElasticSearch中存在兩種搜尋方式。一種是Request Body Search
和Request URL Search
方式。Request URL Search
是通過將引數放在URL
之後來達到傳遞查詢語句的目的,比如
GET /GET /kibana_sample_data_ecommerce/_search?q=customer_first_name:Eddie
複製程式碼
另外一種是Request Body Search
是通過將引數以json
串的方式傳遞,相對於Request URL Search
Request Body Search
會使用的多一些。下面主要講一講Request Body Search
的方式來查詢ElasticSearch
。
Query and filter context
本文使用的資料均為kibana
中的kibana_sample_data_ecommerce
資料。
在ElasticSearch
的查詢API中存在兩種主要的過濾方式。一種是Query
,由query
引導。另外一種是filter
,由filter
來引導。兩者之間的區別是在query
之後的查詢子句,會對檔案的分數產生影響。而filter
之後的查詢子句不會對檔案的分數產生影響。
舉個例子。
GET /kibana_sample_data_ecommerce/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"customer_first_name": "Eddie"
}
}
],"filter": {
"term": {
"customer_full_name.keyword": "Eddie Underwood"
}
}
}
}
}
複製程式碼
可以看到該bool
查詢存在match
和term
子查詢。因為term
在filter
物件內,所以不會對最後的排序分數產生影響。而match
子查詢中的customer_first_name
會對最後的排序分數產生影響。
Match All Query
match_all
match_all
作為最簡單的查詢。一般不會在生產環境中使用,在測試環境中使用的會較多。match_all
會查詢出所有的檔案。
舉個例子。
GET /kibana_sample_data_ecommerce/_search
{
"query": {
"match_all": {}
}
}
複製程式碼
match_none
今天才發現居然存在這麼個搜尋。match_none
是match_all
的反面,不會搜尋到任何的檔案。
GET /kibana_sample_data_ecommerce/_search
{
"query": {
"match_none": {}
}
}
複製程式碼
Full text queries
作為一個全文搜尋引擎的意義,對於text
欄位使用全文搜尋。最典型的應用是可以用來搜尋文章(比如各大部落格網站),用來搜尋程式碼(比如Github)。
match Query
match
查詢是最典型的全文搜尋的查詢子句。match
查詢子句會將查詢語句根據欄位的分析器分析為多個單詞。然後逐個查詢檔案中該欄位是否存在。
舉個例子。
GET /kibana_sample_data_ecommerce/_search
{
"query": {
"match": {
"customer_full_name": "Eddie Weber"
}
}
}
複製程式碼
可以得到
"hits" : {
"total" : 115,"hits" : [
{
"customer_full_name" : "Eddie Weber"
}
]
複製程式碼
customer_full_name
會被分析為eddie
和weber
兩個單詞。之後在檔案中的customer_full_name
中查詢是否包含這兩個欄位。如果包含了這兩個單詞其中一個,那麼就算是匹配成功。如果一個都沒有包含,那麼就表示匹配不成功。在示例資料中eddie
或者weber
匹配到了115個檔案。
預設情況下匹配的演演算法的確跟上面一樣,只要包含了一個單詞就可以匹配上檔案。但是,也可以通過引數operator
來修改這個演演算法。比如下面指定and
操作符。
GET /kibana_sample_data_ecommerce/_search
{
"query": {
"match": {
"customer_full_name": {
"query": "Eddie Weber","operator": "and"
}
}
}
}
複製程式碼
只能匹配上兩個檔案。從原來的匹配115個檔案降到了2個檔案。
"hits" : {
"total" : 2,"hits" : [
"_source" : {
"customer_full_name" : "Eddie Weber",複製程式碼
這裡表示必須customer_full_name
必須既包含eddie
也要包含weber
才可以匹配上。
match Phrase Query
match Phrase
表示短語搜尋。當我們想要搜尋一個短語的時候,可以使用match Phrase Query
,比如我們還是想要搜尋customer_full_name
為Eddie Webber
的人。但是,我們不想搜尋出來只叫做Eddie
,也不想搜尋出來叫做Eddie xxx Webber
的人。這個時候可以使用match Phrase
,因為match Phrase
不僅會要求欄位內容中均包含eddie
和webber
也要求這兩個單詞的順序是一致的,中間不能有其他單詞插入。
比如我們再插入一條資料,一個叫做Eddie fake Weber
的人。
POST /kibana_sample_data_ecommerce/_doc/1
{
"customer_full_name":"Eddie fake Weber"
}
複製程式碼
這個時候,使用match
和and
來進行匹配會發現有三條資料。
"hits" : {
"total" : 3,"max_score" : 9.586426,"hits" : [
{
"customer_full_name" : "Eddie Weber"
},{
"customer_full_name":"Eddie Weber"
},{
"customer_full_name":"Eddie fake Weber"
}
複製程式碼
我們使用match Phrase Query
來進行搜尋。
GET /kibana_sample_data_ecommerce/_search
{
"query": {
"match_phrase": {
"customer_full_name": "Eddie Weber"
}
}
}
複製程式碼
就只會得到只有名字叫做Eddie Weber
的人。
"hits" : {
"total" : 2,{
"customer_full_name" : "Eddie Weber"
}
複製程式碼
ElasticSearch
中還提供了一個叫做slop
的引數。使用slop
引數可以指定單詞之間的最大間隔是多少。間隔指短語中單詞與單詞之間間隔了多少單詞。比如上面的Eddie Weber
中的Eddie
和Weber
沒有間隔任何的單詞,所以間隔為0。而新插入的資料Eddie fake Weber
中的Eddie
和Weber
間隔為1,因為間隔了fake
這個單詞。
預設的match phrase
的slop
的值為0。可以設定slop
值為1來匹配上Eddie fake Weber
GET /kibana_sample_data_ecommerce/_search
{
"query": {
"match_phrase": {
"customer_full_name": {
"query": "Eddie Weber","slop": 1
}
}
}
}
複製程式碼
可以匹配上三個檔案。
"hits" : {
"total" : 3,{
"customer_full_name":"Eddie fake Weber"
}
複製程式碼
和match
搜尋比較下可以發現match phrase
類似於match
加上and
條件再加上順序和間隔為0的條件。
match Phrase Prefix Query
match phrase prefix
跟match phrase
之間的區別是match phrase prefix
可以讓你在短語的最後一個單詞上進行字首匹配。比如還是想要搜尋customer_full_name
,這個時候我可能已經忘記了Eddie Weber
的最後一個單詞Weber
的全部內容了。那麼我可以使用match phrase prefix
來搜尋Eddie We
,因為最後一個單詞We
會進行字首匹配。所以,我還是能夠搜尋到Eddie Weber
這個人。
比如
GET /kibana_sample_data_ecommerce/_search
{
"query": {
"match_phrase_prefix": {
"customer_full_name": "Eddie We"
}
}
}
複製程式碼
可以匹配上
"hits" : {
"total" : 2,{
"customer_full_name" : "Eddie Weber"
}
複製程式碼
那麼不是最後一個單詞而是在之前的單詞會進行字首匹配嗎?
比如我搜索Edd We
GET /kibana_sample_data_ecommerce/_search
{
"query": {
"match_phrase_prefix": {
"customer_full_name": "Edd We"
}
}
}
複製程式碼
匹配不上任何的檔案。因為只會對最後一個單詞進行字首匹配。
"hits" : {
"total" : 0,"max_score" : null,"hits" : [ ]
}
複製程式碼
另外ElasticSearch
還提供了max_expansions
來控制最後一個字首單詞和需要匹配的單詞之間的距離。什麼意思?比如上面使用We
來字首匹配Weber
。那麼這兩個單詞之間的距離是ber
,也就是3個字母的距離。
加入我們使用max_expansions
來控制匹配的距離為2,看一下會不會匹配上Weber
?
關於寫作
"百天"寫作計劃下半部。
每週更新一篇碎碎念。
每週三、週六更新一篇儘量全面,詳細的文章。
可能時長突破了百天,但是又有什麼關係呢?提高寫作水平,形成寫作的習慣才是最終的目的。
如果這篇文章給你帶來了一些幫助,可以動動手指點個贊,順便關注一波就更好了。
如果上面都沒有,那麼寫下讀完之後最想說的話?有效的反饋和你的鼓勵是對我最大的幫助。
另外打算把部落格給重新撿起來了。歡迎大家來訪問吃西瓜。
我是shane。今天是2019年9月18日。"百天"寫作計劃下半部,52/100。