1. 程式人生 > >Elasticsearch系列---深入全文搜尋

Elasticsearch系列---深入全文搜尋

概要

本篇介紹怎樣在全文欄位中搜索到最相關的文件,包含手動控制搜尋的精準度,搜尋條件權重控制。

手動控制搜尋的精準度

搜尋的兩個重要維度:相關性(Relevance)和分析(Analysis)。

相關性是評價查詢條件與結果的相關程度,並對相關程度進行排序,一般使用TF/IDF方法。

分析是指將索引文件與查詢條件規範化的一個過程,目的是建立倒排索引時,儘可能地提升召回率。

match查詢原理

匹配查詢match是核心查詢語法,它的主要應用場景就是全文搜尋,我們舉一個示例:

GET /music/children/_search
{
  "query": {
    "match": {
      "name": "wake"
    }
  }
}

Elasticsearch執行的步驟:

  1. 檢索欄位型別:match的欄位name為text型別,是一個analyzed的欄位,那麼查詢條件的字串也應該被analyzed。
  2. 分析查詢字串:將查詢字串"wake"傳入分詞器中(與mapping的分詞器一致),因為只有一個單詞,所以match最終執行的是單個底層的term查詢。
  3. 查詢匹配文件:用term倒排索引中查詢wake然後獲取一組包含該詞的文件。
  4. 為每個文件評分:用term查詢計算每個文件相關度評分,即TF、IDF、length norm演算法。

得到的結果如下:

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "music",
        "_type": "children",
        "_id": "2",
        "_score": 0.2876821,
        "_source": {
          "id": "a810fad4-54cb-59a1-9b7a-82adb46fa58d",
          "author": "John Smith",
          "name": "wake me, shark me",
          "content": "don't let me sleep too late, gonna get up brightly early in the morning",
          "language": "english",
          "tags": "enlighten",
          "length": 55,
          "isRelease": true,
          "releaseDate": "2019-12-21"
        }
      }
    ]
  }
}

因為樣本資料的問題,暫時只有一條文件匹配。

搜尋name中包含"you"或"sunshine"的文件

GET /music/children/_search
{
  "query": {
    "match": {
      "name": "you sunshine"
    }
  }
}

搜尋name中包含"you"和"sunshine"的文件

GET /music/children/_search
{
  "query": {
    "match": {
      "name": {
        "query": "you sunshine",
        "operator": "and"
      }
    }
  }
}

搜尋精準度控制的第一步:使用and關鍵字。如果希望所有搜尋關鍵字都要匹配,可以用and來實現。

搜尋"you"、"my"、"sunshine"、"teeth" 4個關鍵字中,至少包含3個的文件

GET /music/children/_search
{
  "query": {
    "match": {
      "name": {
        "query": "you my sunshine teeth",
        "minimum_should_match": "75%"
      }
    }
  }
}

搜尋精準度控制的第二步:指定至少匹配其中的多少個關鍵字,才能作為結果返回

bool組合多個搜尋條件

用bool組合,可以完成更加個性化的搜尋需求,例如我們查詢名稱包含"sunshine",但不包含"teeth",允許出現"you"、"my"關鍵字,示例如下:

GET /music/children/_search
{
  "query": {
    "bool": {
      "must":     { "match": { "name": "sunshine" }},
      "must_not": { "match": { "name": "teeth"  }},
      "should": [
                  { "match": { "name": "my" }},
                  { "match": { "name": "you"   }}
      ]
    }
  }
}

should對相關度評分計算的影響

以上面的bool為例子,我們只討論匹配的文件,按自己的理解,對文件進行粗略排名:

  1. 最符合搜尋條件的

文件中同時包含should中的"my"、"you"兩個關鍵字。

  1. 很符合搜尋條件的

文件中包含should中的"my"或"you"兩個關鍵字的其中一個。

  1. 符合搜尋條件的

文件中不包含should中的"my"和"you"。

像must not這種硬性條件,不匹配都不會出現在結果集裡,主要起到排除文件作用,不參與評分計算。但should也能影響相關度評分,匹配得越多,評分就越高。

bool查詢會為每個文件計算相關度評分_score ,再將所有匹配的 must 和 should 語句的分數 _score 求和,最後除以 must 和 should 語句的總數。

這裡不詳細講解評分計算的具體細節和分數,瞭解should對其有影響即可。

should匹配原則

如果查詢條件中有must存在,那麼should匹配的數量不作要求;如果沒有must,則should必須要匹配一個,要不然全是should條件的,所有文件都能匹配,就失去了搜尋的意義。

如果帶上minimum_should_match,那麼就能做更精細的控制,可以指定必須要匹配幾個should,才能返回結果集,如下兩個示例是等同的:

GET /music/children/_search
{
  "query": {
    "match": {
      "name": {
        "query": "you my sunshine teeth",
        "minimum_should_match": "75%"
      }
    }
  }
}
GET /music/children/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "name": "you" }},
        { "match": { "name": "my"   }},
        { "match": { "name": "sunshine"   }},
        { "match": { "name": "teeth"   }}
      ],
      "minimum_should_match": 3 
    }
  }
}

多詞查詢的底層原理

上一節當中我們提到的多詞match的查詢,Elasticsearch會將多詞的term查詢轉換為bool查詢,or查詢使用should替代, and查詢使用must,我們回顧一下上一節的示例:

or查詢

下面兩個查詢是等價的

GET /music/children/_search
{
  "query": {
    "match": {
      "name": "you sunshine"
    }
  }
}

GET /music/children/_search
{
  "query": {
    "bool": {
      "should": [
        {"term": {"name": "you"}},
        {"term": {"name": "sunshine"}}
      ]
    }
  }
}

and查詢

下面兩個查詢也是等價的

GET /music/children/_search
{
  "query": {
    "match": {
      "name": {
        "query": "you sunshine",
        "operator": "and"
      }
    }
  }
}

GET /music/children/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {"name": "you"}},
        {"term": {"name": "sunshine"}}
      ]
    }
  }
}

minimum_should_match語法

下面兩個查詢仍然是等價的

GET /music/children/_search
{
  "query": {
    "match": {
      "name": {
        "query": "you my sunshine teeth",
        "minimum_should_match": "75%"
      }
    }
  }
}

GET /music/children/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "name": "you" }},
        { "match": { "name": "my"   }},
        { "match": { "name": "sunshine"   }},
        { "match": { "name": "teeth"   }}
      ],
      "minimum_should_match": 3 
    }
  }
}

minimum_should_match的值可以改,也會根據實際的條件來換算,比如我寫個75%,但實際的搜尋詞條就只有3個,那麼minimum_should_match的值就會變成66.6%,即至少需要匹配2條。

查詢語句權重控制

bool查詢裡的多條件並列,預設權重是一樣的,但實際的搜尋當中,我們可能會特別某一些關鍵詞給予特殊的關注,希望匹配關注度高的文件排序能靠前一些,boost語法可以幫助我們實現這一需求。

boost預設是1,可以在查詢語句中自行設定,如下示例,我希望sunshine的權重要大一些:

GET /music/children/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "name": {
            "query": "sunshine",
            "boost": 2
          }
        }
      },
      "should": [
        {
          "match": {
            "name": "my"
          }
        },
        {
          "match": {
            "name": "you"
          }
        }
      ]
    }
  }
}

在查詢結果裡可以看到,符合條件的文件的_score值變得更高一些。boost值的設定不是簡單的線性增長,boost設定為2不表示_score也會簡單的翻一倍,boost值在計算時有歸一化處理,但具體的計算數值及過程不在此篇作詳細的解釋。

評分計算的小問題

我們的演示環境是單node多shard模式的,有些示例發現評分會出現特別高的現象,給人感覺不是很準確,這是為什麼呢?

不準確的原因

我們簡單回顧一下評分計算的幾個演算法:TF、IDF、Length Norm,其中IDF本意上是在所有的document中,搜尋關鍵詞的出現次數,實際上IDF預設在本地shard執行的次數統計,一個shard只包含部分資料,不能代表所有資料,這樣做比較高效,但會帶來誤差,也是造成結果不準確的原因。

演示環境中出現較大偏差,還有一個原因是演示資料相對較少,如果只有一個document,並且該document符合查詢條件,那麼IDF的分數就會變得很高。

解決辦法

  1. 生產環境資料量相對較大,預設使用_id進行路由,在概率分佈下,其實每個shard的資料基本上比較均勻,不用太擔心演示環境的這種情況。
  2. 演示環境可以將primary shard設定為1,只有一個shard,那IDF的值肯定是對的。
  3. 演示環境進行搜尋時,帶上search_type=dfs_query_then_fetch引數,會將local IDF取出來計算global IDF。注意效能問題,生產上禁用。

小結

本篇主要介紹了全文搜尋幾種手動控制精度的方式:邏輯操作符變換、should命中率設定、權重調整等手段,最後對評分計算的小問題進行的簡單描述,謝謝。

專注Java高併發、分散式架構,更多技術乾貨分享與心得,請關注公眾號:Java架構社群
可以掃左邊二維碼新增好友,邀請你加入Java架構社群微信群共同探討技術

相關推薦

Elasticsearch系列---深入全文搜尋

概要 本篇介紹怎樣在全文欄位中搜索到最相關的文件,包含手動控制搜尋的精準度,搜尋條件權重控制。 手動控制搜尋的精準度 搜尋的兩個重要維度:相關性(Relevance)和分析(Analysis)。 相關性是評價查詢條件與結果的相關程度,並對相關程度進行排序,一般使用TF/IDF方法。 分析是指將索引文件與查詢條

elasticsearch筆記_全文搜尋_query(五)

全文搜尋(Query) 全文搜尋最重要的兩個方面就是”相關性(Relevance)”和”分析(Analysis)” . 相關性(Relevance) 每個文件都有相關性評分,用一個正浮點數字段 _score 來表示 。_score 評分越高 ,

elasticsearch系列四:搜尋詳解(搜尋API、Query DSL)

{  "took": 60,  "timed_out": false,  "_shards": {    "total": 5,    "successful": 5,    "skipped": 0,    "failed": 0  },  "hits": {    "total": 1000,    "m

Elasticsearch系列---結構化搜尋

概要 結構化搜尋針對日期、時間、數字等結構化資料的搜尋,它們有自己的格式,我們可以對它們進行範圍,比較大小等邏輯操作,這些邏輯操作得到的結果非黑即白,要麼符合條件在結果集裡,要麼不符合條件在結果集之外,沒有那種相似的概念。 前言 結構化搜尋將會有大量的搜尋例項,我們將"音樂APP"作為主要的案例背景,去開發一

瞭解學習 Elasticsearch 及其與 Python 實現全文搜尋

Elasticsearch簡介 ElasticSearch是一個基於Lucene的搜尋伺服器.它提供了一個分散式多使用者能力的全文搜尋引擎,基於RESTful web介面。Elasticsearch是用Java開發的,並作為Apache許可條款下的開放原始碼釋出,是當前流行的企業級搜尋引擎。設計

ElasticSearch最佳入門實踐(三十八)精確匹配與全文搜尋的對比分析

1、ES中的兩種搜尋模式 1、exact value 2、full text 2、exact value 2017-01-01,exact value,搜尋的時候,必須輸入2017-01-01,才能搜尋出來。如果你輸入一個01,是搜尋不

使用haystack實現Django的全文搜尋 -- Elasticsearch搜尋引擎

全文搜尋: 在使用python進行web開發的時候,免不了需要使用到全文搜尋;全文搜尋和我們平常使用的資料庫的模糊搜尋查詢不一樣,例如在mysql資料庫中,如果進行模糊查詢,比如 name like '%wang%'這一類的,效率是非常低的;而我們需求的全文搜尋,在效率方面要求是很高

全文搜尋儲存引擎 Elasticsearch 一點點

開始請大家想一個問題,如何統計一個Web站點的有效PV? 針對使用者請求的URL,統計時做模式匹配-------->即使用者真正去開啟一個站點的有效頁面並對每個頁面的入口的訪問做一個統計瀏覽量; 簡要搜尋引擎 搜尋引擎在網際網路上特別多有專業(Startpage,Google,Yah

Elasticsearch全文搜尋控制精準度

前言 本文主要是關於全文搜尋控制精準度的操作 其他搜尋請參考: 一、使用operator 搜尋結果中必須至少包括run、jump兩種愛好 GET people/_search {

ASP.NET Web API + Elasticsearch 6.x 快速做個全文搜尋

最近想做個全文搜尋,設想用 ASP.NET Web API + Elasticsearch 6.x 來實現。 網上搜了下 Elasticsearch 的資料,大部分是講 linux 平臺下如何用 java 來開發,有少量講在 windows 平臺下用 c# 開發的,且版本是 Elasti

[Elasticsearch] 全文搜尋 (二)

多詞查詢(Multi-word Queries) 如果我們一次只能搜尋一個詞,那麼全文搜尋就會顯得相當不靈活。幸運的是,通過match查詢來實現多詞查詢也同樣簡單: GET /my_index/my_type/_search { "query": {

laravel-elasticsearch 全文搜尋設定

1、首先安裝 jave環境 jdk 下載地址 ,我用的是最新版本的,有時版本要跟elasticsearch對應 2、安裝elasticsearch 下載地址 3、安裝Laravel scout 全文搜尋包,這裡我用的是5.0.3版本,tamayo/laravel-scout-elastic .這

[Elasticsearch] 全文搜尋 (三)

match查詢是如何使用bool查詢的 現在,你也許意識到了使用了match查詢的多詞查詢只是簡單地將生成的term查詢包含在了一個bool查詢中。通過預設的or操作符,每個term查詢都以一個語句被新增,所以至少一個should語句需要被匹配。以下兩個查詢是等價的:

Elasticsearch:一個方便易用的全文搜尋

注:本文內容均來自《Elasticsearch權威指南》,是做讀書筆記,同時做一個總結。 Elasticsearch是使用基於http的RestFul來實現和使用的,因此使用curl來測試。如果不使用curl,使用各種語言的對應http請求即可使用。 Ela

elasticsearch全文搜尋

1.場景還原    近期,筆者專案中需要通過關鍵字來搜尋與之相關的資料,es的全文搜尋終於派上用場了! 2.準備步驟 ②在es的plugins目錄下建立ik,然後解壓縮ik ③在elasticsearch.yml配置ik屬性 index.analysis.ana

elasticsearch 精確匹配與全文搜尋

elasticsearch的兩種搜尋模式:exact value、full text。 一、exact value(精確匹配) 介紹: 比如搜尋2017-01-01,使用exact value搜尋的時候,必須輸入2017-01-01,才能搜尋出來;如果輸

Elasticsearch(六)瞭解全文搜尋

遇到的問題 通過前面的學習,我們已經可以使用elasticsearch來進行資料的搜尋了,但此時我們發現了一個問題,這個問題如果沒有解決好就很影響我們後續的使用,那麼該問題是什麼呢?我們來看一下: 上面的截圖是我搜索“在”關鍵字出來的結果,按照正常情況下,我們是不是不應該搜

Elasticsearch系列---初識搜尋

概要 本篇主要介紹搜尋的報文結構含義、搜尋超時時間的處理過程,提及了一下多索引搜尋和輕量搜尋,最後將精確搜尋與全文搜尋做了簡單的對比。 空搜尋 搜尋API最簡單的形式是不指定索引和型別的空搜尋,它將返回叢集下所有索引的所有文件(預設顯示10條): GET /_search 響應的結果示例(有篩選,只取了一條d

Elasticsearch系列---實戰搜尋語法

概要 本篇介紹Query DSL的語法案例,查詢語句的除錯,以及排序的相關內容。 基本語法 空查詢 最簡單的搜尋命令,不指定索引和型別的空搜尋,它將返回叢集下所有索引的所有文件(預設顯示10條): GET /_search {} 搜尋多個索引 GET /index1,index2/_doc/_search {

Elasticsearch系列---搜尋執行過程及scroll遊標查詢

概要 本篇主要介紹一下分散式環境中搜索的兩階段執行過程。 兩階段搜尋過程 回顧我們之前的CRUD操作,因為只對單個文件進行處理,文件的唯一性很容易確定,並且很容易知道是此文件在哪個node,哪個shard中。 但搜尋比CRUD複雜,符合搜尋條件的文件,可能散落在各個node、各個shard中,我們需要找到匹配