elasticsearch——影響文檔評(píng)分

一般情況下,類似關(guān)系型數(shù)據(jù)庫中影響返回結(jié)果的方式袭异,在elasticsearch中也存在钳垮,包括sort惑淳、size等。但是這都是簡(jiǎn)單粗暴的對(duì)返回結(jié)果進(jìn)行直接處理饺窿,很大的可能會(huì)影響返回文檔的相關(guān)度歧焦。比如,通過sort操作對(duì)搜索結(jié)果按時(shí)間排序肚医,這時(shí)排在前面的文檔很可能相關(guān)度非常小绢馍,而相關(guān)度大的文檔則因?yàn)闀r(shí)間排序被放在了下面。這顯然不是我們想要的結(jié)果肠套。elasticsearch提供了方法舰涌,允許我們用除了搜索之外的其他因素影響返回文檔的順序,同時(shí)兼顧文檔的相關(guān)度你稚。

簡(jiǎn)單粗暴地評(píng)分

首先先說一下elasticsearch的搜索評(píng)分邏輯瓷耙。
查詢的權(quán)重基于三個(gè)因素:詞頻、逆向文檔頻率和字段長(zhǎng)度歸一值刁赖。

  • 詞頻:查詢?cè)~在該文檔中出現(xiàn)的頻率搁痛。頻率越高,權(quán)重越高宇弛。
  • 逆向文檔頻率:查詢?cè)~在所有文檔中出現(xiàn)的頻率鸡典。頻率越高,權(quán)重越低枪芒〕箍觯可以降低日常使用的高頻率詞的權(quán)重。
  • 字段長(zhǎng)度歸一值:查詢字段的長(zhǎng)度舅踪。字段長(zhǎng)度越長(zhǎng)纽甘,查詢?cè)~權(quán)重越高,反之越低抽碌。

不同詞對(duì)搜索結(jié)果的影響基本取決于以上三個(gè)因素贷腕,這里不列出詳細(xì)的計(jì)算公式。

如何影響文檔評(píng)分

首先,影響文檔評(píng)分的操作推薦是查詢的時(shí)候進(jìn)行泽裳,這樣靈活性更好瞒斩。這里不介紹簡(jiǎn)單的評(píng)分提升或者降低,直接介紹elasticsearch中控制文檔評(píng)分的終極武器:function_scor涮总。

function_score

function_score是query結(jié)構(gòu)的一個(gè)子集胸囱,它對(duì)每一個(gè)符合查詢的文檔應(yīng)用一個(gè)或一組函數(shù),達(dá)到影響甚至替換原始查詢?cè)u(píng)分的目的瀑梗。這個(gè)操作可以很方便的實(shí)現(xiàn)復(fù)雜的查詢邏輯烹笔。
Elasticsearch 預(yù)定義了一些函數(shù):

  • weight:為每個(gè)文檔應(yīng)用一個(gè)簡(jiǎn)單而不被規(guī)范化的權(quán)重提升值:當(dāng) weight 為 2 時(shí),最終結(jié)果為 2 * _score 抛丽。
  • field_value_factor:使用這個(gè)值來修改 _score 谤职,如將 popularity 或 votes (受歡迎或贊)作為考慮因素。
  • random_score:為每個(gè)用戶都使用一個(gè)不同的隨機(jī)評(píng)分對(duì)結(jié)果排序亿鲜,但對(duì)某一具體用戶來說允蜈,看到的順序始終是一致的。
  • 衰減函數(shù) —— linear 蒿柳、 exp 饶套、 gauss:將浮動(dòng)值結(jié)合到評(píng)分 _score 中,例如結(jié)合 publish_date 獲得最近發(fā)布的文檔垒探,結(jié)合 geo_location 獲得更接近某個(gè)具體經(jīng)緯度(lat/lon)地點(diǎn)的文檔妓蛮,結(jié)合 price 獲得更接近某個(gè)特定價(jià)格的文檔。
  • script_score:如果需求超出以上范圍時(shí)圾叼,用自定義腳本可以完全控制評(píng)分計(jì)算蛤克,實(shí)現(xiàn)所需邏輯。

以上函數(shù)開箱即用夷蚊,一般情況下咖耘,elasticsearch提供的函數(shù)就可以滿足需求,如果有特殊要求撬码,也可以使用最后一個(gè)script_score自己寫控制評(píng)分腳本。但是script_score對(duì)性能有較大影響版保,能不用就不用呜笑。
下面簡(jiǎn)單說明幾個(gè)需求,來看看elasticsearch是如何通過function_score實(shí)現(xiàn)的彻犁。

點(diǎn)擊數(shù)影響評(píng)分

如果想要在原來搜索的基礎(chǔ)上叫胁,加入點(diǎn)擊數(shù)的影響,即將點(diǎn)擊數(shù)高的文檔放到搜索結(jié)果靠上的位置汞幢,但是搜索的評(píng)分仍然是主要的依據(jù)驼鹅。

PUT /blogposts/post/1
{
  "title":   "About popularity",
  "content": "In this post we will talk about...",
  "votes":   6
}

這是一篇文章的文檔,其中保存了點(diǎn)擊數(shù)。這里可以通過field_value_factor實(shí)現(xiàn)相關(guān)需求输钩。

GET /blogposts/post/_search
{
  "query": {
    "function_score": { 
      "query": {
        "multi_match": {
          "query":    "popularity",
          "fields": [ "title", "content" ]
        }
      },
      "field_value_factor": { 
        "field": "votes" 
      }
    }
  }
}

function_score嵌入了一個(gè)query查詢中豺型,然后內(nèi)部又設(shè)定了一個(gè)query,內(nèi)部的query查詢是主查詢买乃。在function_score內(nèi)部還有一個(gè)field_value_factor函數(shù)姻氨,這個(gè)函數(shù)會(huì)對(duì)符合每一個(gè)主查詢的文檔使用。每個(gè)文檔的最終評(píng)分都會(huì)進(jìn)行如下的計(jì)算:new_score = old_score * number_of_votes
默認(rèn)的field_value_factor計(jì)算是線性的剪验,votes的原始值直接用來計(jì)算肴焊,這通常不會(huì)產(chǎn)生好的結(jié)果。一般情況下功戚,通過對(duì)數(shù)計(jì)算取代現(xiàn)行計(jì)算娶眷,可以取得更平滑的結(jié)果。

GET /blogposts/post/_search
{
  "query": {
    "function_score": {
      "query": {
        "multi_match": {
          "query":    "popularity",
          "fields": [ "title", "content" ]
        }
      },
      "field_value_factor": {
        "field":    "votes",
        "modifier": "log1p"
      }
    }
  }
}

將field_value_factor設(shè)為對(duì)數(shù)計(jì)算啸臀,計(jì)算公式:new_score = old_score * log(1 + number_of_votes)届宠。
field_value_factor提供了眾多參數(shù),設(shè)置相關(guān)計(jì)算的各種參數(shù)壳咕,這里不再一一列舉席揽。如果想要細(xì)致的調(diào)整搜索結(jié)果的話,參考官方文檔進(jìn)行谓厘。

對(duì)查詢結(jié)果進(jìn)行隨機(jī)評(píng)分

作為網(wǎng)站的所有者幌羞,總會(huì)希望讓廣告有更高的展現(xiàn)率。在當(dāng)前查詢下竟稳,有相同評(píng)分 _score 的文檔會(huì)每次都以相同次序出現(xiàn)属桦,為了提高展現(xiàn)率,在此引入一些隨機(jī)性可能會(huì)是個(gè)好主意他爸,這能保證有相同評(píng)分的文檔都能有均等相似的展現(xiàn)機(jī)率聂宾。
我們想讓每個(gè)用戶看到不同的隨機(jī)次序,但也同時(shí)希望如果是同一用戶翻頁瀏覽時(shí)诊笤,結(jié)果的相對(duì)次序能始終保持一致系谐。這種行為被稱為一致隨機(jī)。
random_score 函數(shù)會(huì)輸出一個(gè) 0 到 1 之間的數(shù)讨跟,當(dāng)種子 seed 值相同時(shí)纪他,生成的隨機(jī)結(jié)果是一致的。例如:

GET /blogposts/post/_search
{
  "query": {
    "function_score": {
      "query": {
        "multi_match": {
          "query":    "popularity",
          "fields": [ "title", "content" ]
        }
      },
      "random_score": {
        "seed":  "userID"
      }
    }
  }
}

使用每個(gè)用戶的id作為seed傳入晾匠,可以使每個(gè)用戶的隨機(jī)保持一致茶袒,同時(shí)在不同用戶之間保持不同的隨機(jī)性。

時(shí)間凉馆、空間上的“越近越好”

一般來說薪寓,搜索要求具有時(shí)間相關(guān)性亡资。也就是說,用戶只想看到時(shí)間較近的文檔向叉,而時(shí)間較遠(yuǎn)的文檔锥腻,就算相關(guān)度較高,用戶也不想看到植康】跆空間上也有相關(guān)的性質(zhì),比如以某個(gè)點(diǎn)為中心销睁,周圍一定距離以內(nèi)的文檔排在返回結(jié)果的前面供璧,而超過一定距離的文檔就算相關(guān)度較高也排在后面。elasticsearch提供了衰減函數(shù)冻记,可以對(duì)文檔的相關(guān)性按某個(gè)維度進(jìn)行衰減睡毒。

這里不能直接使用sort。因?yàn)槿绻苯邮褂胹ort冗栗,會(huì)讓相關(guān)度較低的文檔排在前面演顾,維度近了但是相關(guān)度很差,達(dá)不到相關(guān)度較高隅居、同時(shí)某個(gè)維度較 近 的需求钠至。

elasticsearch提供了三個(gè)衰減函數(shù),分別是linear胎源、exp和gauss(線性棉钧、指數(shù)和高斯函數(shù)),它們可以操作數(shù)值涕蚤、時(shí)間以及經(jīng)緯度地理坐標(biāo)點(diǎn)這樣的字段(一般衰減也沒有用字符串做衰減的)宪卿。所有三個(gè)函數(shù)都能接受以下參數(shù):

  • origin:中心點(diǎn) 或字段可能的最佳值,落在原點(diǎn) origin 上的文檔評(píng)分 _score 為滿分 1.0 万栅。
  • scale:衰減率佑钾,即一個(gè)文檔從原點(diǎn) origin 下落時(shí),評(píng)分 _score 改變的速度烦粒。(例如休溶,每 £10 歐元或每 100 米)。
  • decay:從原點(diǎn) origin 衰減到 scale 所得的評(píng)分 _score 扰她,默認(rèn)值為 0.5 兽掰。
  • offset:以原點(diǎn) origin 為中心點(diǎn),為其設(shè)置一個(gè)非零的偏移量 offset 覆蓋一個(gè)范圍义黎,而不只是單個(gè)原點(diǎn)。在范圍 -offset <= origin <= +offset 內(nèi)的所有評(píng)分 _score 都是 1.0 豁跑。
    衰減曲線

比如廉涕,想要搜索某條博客泻云,同時(shí)發(fā)表時(shí)間近的排在前面,引入基于時(shí)間的衰減函數(shù)狐蜕。

GET /blogposts/post/_search
{
  "query": {
    "function_score": {
      "query": {
        "multi_match": {
          "query":    "popularity",
          "fields": [ "title", "content" ]
        }
      },
      "gauss" :{
          "timestamp": {
            "origin": "now timestamp",
            "offset": "5d",
            "scale": "10d"
          }
       }
    }
  }
}

按時(shí)間和地理空間做衰減宠纯,offset 和 scale 必須加上單位。
這里我們確定以當(dāng)前的時(shí)間為衰減函數(shù)的中心层释, 5 天以內(nèi)的文檔婆瓜,相關(guān)度不做處理;5 天到 15 天贡羔,衰減系數(shù)逐漸降低到0.5廉白;15 天之外,系數(shù)繼降低乖寒。

比如猴蹂,想將地理空間和價(jià)格的影響引入搜索,可以這樣實(shí)現(xiàn):

GET /_search
{
  "query": {
    "function_score": {
      "functions": [
        {
          "gauss": {
            "location": {
              "origin": { "lat": 51.5, "lon": 0.12 },
              "offset": "2km",
              "scale":  "3km"
            }
          }
        },
        {
          "gauss": {
            "price": { 
              "origin": "50", 
              "offset": "50",
              "scale":  "20"
            }
          },
          "weight": 2
        }
      ]
    }
  }
}

這里地理空間類型楣嘁,在衰減函數(shù)的參數(shù)里要加上單位磅轻,而普通的數(shù)值類型不用加單位。

通過衰減函數(shù)逐虚,可以在相關(guān)度為主的前提下聋溜,引入時(shí)間、空間叭爱、數(shù)值等其他因素撮躁,從而影響搜索的返回結(jié)果。比起簡(jiǎn)單粗暴的sort涤伐,衰減函數(shù)可以保證相關(guān)度高的依然排在靠前的位置馒胆。

終極武器script_score

elasticsearch支持用戶自己寫groovy腳本,來自定義復(fù)雜的評(píng)分影響邏輯凝果。因?yàn)槿粘V胁惶珜?shí)用祝迂,同時(shí)腳本對(duì)性能影響較大,所以這里不做介紹器净。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末型雳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子山害,更是在濱河造成了極大的恐慌纠俭,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浪慌,死亡現(xiàn)場(chǎng)離奇詭異冤荆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)权纤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門钓简,熙熙樓的掌柜王于貴愁眉苦臉地迎上來会宪,“玉大人伴澄,你說我怎么就攤上這事预皇∞榷蹋” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵损话,是天一觀的道長(zhǎng)侦啸。 經(jīng)常有香客問我,道長(zhǎng)丧枪,這世上最難降的妖魔是什么光涂? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮豪诲,結(jié)果婚禮上顶捷,老公的妹妹穿的比我還像新娘。我一直安慰自己屎篱,他們只是感情好服赎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著交播,像睡著了一般重虑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秦士,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天缺厉,我揣著相機(jī)與錄音,去河邊找鬼隧土。 笑死提针,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的曹傀。 我是一名探鬼主播辐脖,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼皆愉!你這毒婦竟也來了嗜价?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤幕庐,失蹤者是張志新(化名)和其女友劉穎久锥,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體异剥,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瑟由,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冤寿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歹苦。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绿鸣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出暂氯,到底是詐尸還是另有隱情,我是刑警寧澤亮蛔,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布痴施,位于F島的核電站,受9級(jí)特大地震影響究流,放射性物質(zhì)發(fā)生泄漏辣吃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一芬探、第九天 我趴在偏房一處隱蔽的房頂上張望神得。 院中可真熱鬧,春花似錦偷仿、人聲如沸哩簿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽节榜。三九已至,卻和暖如春别智,著一層夾襖步出監(jiān)牢的瞬間宗苍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工薄榛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留讳窟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓敞恋,卻偏偏與公主長(zhǎng)得像丽啡,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耳舅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354