1. 程式人生 > 程式設計 >探索ElasticSearch-深入搜尋之全文搜尋(八)

探索ElasticSearch-深入搜尋之全文搜尋(八)

前言

學習需要先打好基礎,最後才能逐步深入。今天來重新探索下ElasticSearch的全文搜尋。

搜尋

ElasticSearch中存在兩種搜尋方式。一種是Request Body SearchRequest 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查詢存在matchterm子查詢。因為termfilter物件內,所以不會對最後的排序分數產生影響。而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_nonematch_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會被分析為eddieweber兩個單詞。之後在檔案中的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_nameEddie Webber的人。但是,我們不想搜尋出來只叫做Eddie,也不想搜尋出來叫做Eddie xxx Webber的人。這個時候可以使用match Phrase,因為match Phrase不僅會要求欄位內容中均包含eddiewebber也要求這兩個單詞的順序是一致的,中間不能有其他單詞插入。

比如我們再插入一條資料,一個叫做Eddie fake Weber的人。

POST /kibana_sample_data_ecommerce/_doc/1
{
  "customer_full_name":"Eddie fake Weber"
}
複製程式碼

這個時候,使用matchand來進行匹配會發現有三條資料。

 "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中的EddieWeber沒有間隔任何的單詞,所以間隔為0。而新插入的資料Eddie fake Weber中的EddieWeber間隔為1,因為間隔了fake這個單詞。 預設的match phraseslop的值為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 prefixmatch 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。