[Elasticsearch] 鄰近匹配 (二) - 多值字段,鄰近程度與相關度

多值字段(Multivalue Fields)

在多值字段上使用短語匹配會產生古怪的行爲:html

PUT /my_index/groups/1
{
    "names": [ "John Abraham", "Lincoln Smith"] }

運行一個針對Abraham Lincoln的短語查詢:json

GET /my_index/groups/_search
{
    "query": { "match_phrase": { "names": "Abraham Lincoln" } } }

使人詫異的是,以上的這份文檔匹配了查詢。即便Abraham以及Lincoln分屬於name數組的兩我的名中。發生這個現象的緣由在於數組在ES中的索引方式。數組

當John Abraham被解析時,它產生以下信息:app

  • 位置1:john
  • 位置2:abraham

而後當Lincoln Smith被解析時,它產生了:elasticsearch

  • 位置3:lincoln
  • 位置4:smith

換言之,ES對以上數組分析產生的詞條列表和解析單一字符串John Abraham Lincoln Smith時產生的結果是同樣的。在咱們的查詢中,咱們查詢鄰接的abraham和lincoln,而這兩個詞條在索引中確實存在而且鄰接,所以查詢匹配了。ide

幸運的是,有一個簡單的方法來避免這種狀況,經過position_offset_gap參數,它在字段映射中進行配置:ui

DELETE /my_index/groups/ 

PUT /my_index/_mapping/groups 
{
    "properties": { "names": { "type": "string", "position_offset_gap": 100 } } }

position_offset_gap設置告訴ES須要爲數組中的每一個新元素設置一個誤差值。所以,當咱們再索引以上的人名數組時,會產生以下的結果:spa

  • 位置1:john
  • 位置2:abraham
  • 位置103:lincoln
  • 位置104:smith

如今咱們的短語匹配就沒法匹配該文檔了,由於abraham和lincoln之間的距離爲100。你必需要添加一個值爲100的slop的值才能匹配。htm



 

越近越好(Closer is better)

短語查詢(Phrase Query)只是簡單地將不含有精確查詢短語的文檔排除在外,而鄰近查詢(Proximity Query) - 一個slop值大於0的短語查詢 - 會將查詢詞條的鄰近度也考慮到最終的相關度_score中。經過設置一個像50或100這樣的高slop值,你能夠排除那些單詞過遠的文檔,可是也給予了那些單詞鄰近的文檔一個更高的分值。索引

下面針對quick dog的鄰近查詢匹配了含有quick和dog的兩份文檔,可是給與了quick和dog更加鄰近的文檔一個更高的分值:

POST /my_index/my_type/_search
{
   "query": { "match_phrase": { "title": { "query": "quick dog", "slop": 50 } } } }
{
  "hits": [ { "_id": "3", "_score": 0.75, "_source": { "title": "The quick brown fox jumps over the quick dog" } }, { "_id": "2", "_score": 0.28347334, "_source": { "title": "The quick brown fox jumps over the lazy dog" } } ] }

 


 

使用鄰近度來提升相關度

儘管鄰近度查詢(Proximity Query)管用,可是全部的詞條都必須出如今文檔的這一要求顯的過於嚴格了。這個問題和咱們在全文搜索(Full-Text Search)一章的精度控制(Controlling Precision)一節中討論過的相似:若是7個詞條中有6個匹配了,那麼該文檔也許對於用戶而言已經足夠相關了,可是match_phrase查詢會將它排除在外。

相比將鄰近度匹配做爲一個絕對的要求,咱們能夠將它當作一個信號(Signal) - 做爲衆多潛在匹配中的一員,會對每份文檔的最終分值做出貢獻(參考多數字段(Most Fields))。

咱們須要將多個查詢的分值累加這一事實表示咱們應該使用bool查詢將它們合併。

咱們可使用一個簡單的match查詢做爲一個must子句。該查詢用於決定哪些文檔須要被包含到結果集中。能夠經過minimum_should_match參數來去除長尾(Long tail)。而後咱們以should子句的形式添加更多特定查詢。每一個匹配了should子句的文檔都會增長其相關度。

GET /my_index/my_type/_search
{
  "query": { "bool": { "must": { "match": { "title": { "query": "quick brown fox", "minimum_should_match": "30%" } } }, "should": { "match_phrase": { "title": { "query": "quick brown fox", "slop": 50 } } } } } }

毫無疑問咱們能夠向should子句中添加其它的查詢,每一個查詢都用來增長特定類型的相關度。

相關文章
相關標籤/搜索