1. 程式人生 > >[Elasticsearch] 控制相關度 (四) - 忽略TF/IDF

[Elasticsearch] 控制相關度 (四) - 忽略TF/IDF

current list 得到 全文搜索 term 字段長度 options n) sco

本章翻譯自Elasticsearch官方指南的Controlling Relevance一章。


忽略TF/IDF

有時我們不需要TF/IDF。我們想知道的只是一個特定的單詞是否出現在了字段中。比如我們正在搜索度假酒店,希望它擁有的賣點越多越好:

  • WiFi
  • 花園(Garden)
  • 泳池(Pool)

而關於度假酒店的文檔類似下面這樣:

{ "description": "A delightful four-bedroomed house with ... " }

可以使用一個簡單的match查詢:

GET /_search
{
  "query": {
    "match": {
      "description": "wifi garden pool"
    }
  }
}

然而,我們需要的並不是真正的全文搜索。此時TF/IDF只會礙手礙腳。我們不在意wifi是否是一個常見的詞條,也不在意它在文檔中出現的是否頻繁。我們在意的只是它是否出現了。實際上,我們只是想通過賣點來對這些度假酒店進行排序 - 越多越好。如果擁有一個賣點,那麽它的分值就是1,如果沒有它的分值就是0。

constant_score查詢

首先介紹constant_score查詢。該查詢能夠包含一個查詢或者一個過濾器,所有匹配文檔的相關度分值都為1,不考慮TF/IDF:

GET /_search
{
  "query": {
    "bool": {
      "should": [
        { "constant_score": {
          "query": { "match": { "description": "wifi" }}
        }},
        { "constant_score": {
          "query": { "match": { "description": "garden" }}
        }},
        { "constant_score": {
          "query": { "match": { "description": "pool" }}
        }}
      ]
    }
  }
}

大概並不是所有的賣點都同等重要 - 其中的某些更有價值。如果最看中的賣點是泳池,那麽我們可以對它進行相應提升:

GET /_search
{
  "query": {
    "bool": {
      "should": [
        { "constant_score": {
          "query": { "match": { "description": "wifi" }}
        }},
        { "constant_score": {
          "query": { "match": { "description": "garden" }}
        }},
        { "constant_score": {
          "boost":   2 
          "query": { "match": { "description": "pool" }}
        }}
      ]
    }
  }
}

NOTE

每個結果的最終分值並不是將所有匹配子句的分值累加而得到。Coordination因子和查詢歸約因子(Query Normalization Factor)仍然會被考慮在內。

我們可以在度假酒店的文檔中添加一個not_analyzed類型的features字段:

{ "features": [ "wifi", "pool", "garden" ] }

默認情況下,一個not_analyzed字段的字段長度歸約(Field-length Norm)是被禁用的,同時其index_options也會被設置為docs,從而禁用詞條頻度(Term Frequencies),但是問題還是存在:每個詞條的倒排文檔頻度(Inverse Document Frequency)仍然會被考慮。

仍然使用constant_score查詢:

GET /_search
{
  "query": {
    "bool": {
      "should": [
        { "constant_score": {
          "query": { "match": { "features": "wifi" }}
        }},
        { "constant_score": {
          "query": { "match": { "features": "garden" }}
        }},
        { "constant_score": {
          "boost":   2
          "query": { "match": { "features": "pool" }}
        }}
      ]
    }
  }
}

實際上,每個賣點都應該被視為一個過濾器。度假酒店要麽有該賣點,要麽沒有 - 使用過濾器似乎是更自然的選擇。並且如果我們使用了過濾器,還可以得益於過濾器緩存這一功能。

不使用過濾器的根源在於:過濾器不會計算相關度分值。我們需要的是一座用來連接過濾器和查詢的橋梁。而function_score查詢就能夠做到這一點,並且它也提供了更多的功能。

[Elasticsearch] 控制相關度 (四) - 忽略TF/IDF