天天看點

elastic search中混合使用match實作召回率和精确率的平衡

召回率:比如你搜尋一個java spark,總共有100個doc,能傳回多少個doc作為結果,就是召回率,即recall;

精準度:比如你搜尋一個java spark,能不能盡可能讓包含短語 "java spark",或者是java和spark離的很近的doc,排在最前面,即precision;

在使用近似比對的時候,召回率比較低,精準度太高了,比如:

match phrase,proximity match,要求doc必須包含所有的term,才能作為結果傳回;如果某一個doc可能就是有某個term沒有包含,那麼就無法作為結果傳回

java spark --> hello world java --> 就不能傳回了
java spark --> hello world, java spark --> 才可以傳回
           

但是有時可能我們希望的是比對到幾個term中的部分,就可以作為結果出來,這樣可以提高召回率。同時我們也希望用上match_phrase根據距離提升分數的功能,讓幾個term距離越近分數就越高,優先傳回;

意思是:java spark,包含java的也傳回,包含spark的也傳回,包含java和spark的也傳回;同時兼顧精準度,就是包含java和spark,同時java和spark離的越近的doc排在最前面;

此時可以用bool組合match query和match_phrase query一起,來實作上述效果

GET /forum/article/_search
{
  "query": {
    "bool": {
      "must": {
        "match": { 
          "title": {
            "query": "java spark" ----->java或spark或java spark,java和spark靠前,但是沒法區分java和spark的距離,也許java和spark靠的很近,但是沒法排在最前面
          }
        }
      },
      "should": {
        "match_phrase": {------>在slop以内,如果java spark能比對上一個doc,那麼就會對doc貢獻自己的relevance score,如果java和spark靠的越近,那麼就分數越高
          "title": {
            "query": "java spark",
            "slop":  50
          }
        }
      }
    }
  }
}
           
  • match和phrase match(proximity match)差別:
  • match:隻要簡單的比對到了一個term,就可以了解将term對應的doc作為結果傳回,掃描反向索引,掃描到了就ok;

    phrase match :首先掃描到所有term的doc list; 找到包含所有term的doc list; 然後對每個doc都計算每個term的position,是否符合指定的範圍; slop,需要進行複雜的運算,來判斷能否通過slop移動,比對一個doc;

  • match query的性能比phrase match和proximity match(有slop)要高很多。因為後兩者都要計算position的距離。

    match query比phrase match的性能要高10倍,比proximity match的性能要高20倍。

如何優化proximity match的性能:

   一般就是減少要進行proximity match搜尋的document數量。主要思路:

   用match query先過濾出需要的資料,然後再用proximity match來根據term距離提高doc的分數,同時proximity match隻針對每個shard的分數排名前n個doc起作用,來重新調整它們的分數,這個過程稱之為rescoring,重計分。因為一般使用者會分頁查詢,隻會看到前幾頁的資料,是以不需要對所有結果進行proximity match操作。

   比如說:預設情況下,match也許比對了1000個doc,proximity match全都需要對每個doc進行一遍運算,判斷能否slop移動比對上,然後去貢獻自己的分數但是很多情況下,match出來也許1000個doc,其實使用者大部分情況下是分頁查詢的,是以可能最多隻會看前幾頁,比如一頁是10條,最多也許就看5頁,就是50條,proximity match隻要對前50個doc進行slop移動去比對,去貢獻自己的分數即可,不需要對全部1000個doc都去進行計算和貢獻分數

match:1000個doc,其實這時候每個doc都有一個分數了; proximity match,前50個doc,進行rescore,重打分,即可; 讓前50個doc,term舉例越近的,排在越前面

GET /forum/article/_search 
{
  "query": {
    "match": {
      "content": "java spark"
    }
  },
  "rescore": {
    "window_size": 50,
    "query": {
      "rescore_query": {
        "match_phrase": {
          "content": {
            "query": "java spark",
            "slop": 50
          }
        }
      }
    }
  }
}
           

繼續閱讀