ElasticSearch 評分排序

来源:https://www.cnblogs.com/wangiqngpei557/archive/2019/02/23/10423875.html
-Advertisement-
Play Games

近期有一個需求,需要對優惠券可用商品列表加個排序,只針對面值類的券不包括折扣券。 需求是這樣的,假設有一張面值券 50 塊錢,可用商品列表 A 100、B 40、C 10,當用戶查詢當前券可用商品列表的時候優先將卡券可以直接抵扣且不需要用戶在額外支付的商品排在前面。 ...


  • 背景
  • 通過腳本改變評分

背景

近期有一個需求,需要對優惠券可用商品列表加個排序,只針對面值類的券不包括折扣券。

需求是這樣的,假設有一張面值券 50 塊錢,可用商品列表 A 100、B 40、C 10,當用戶查詢當前券可用商品列表的時候優先將卡券可以直接抵扣且不需要用戶在額外支付的商品排在前面。

C 10
B 40
A 100

其實排序有很多側重,比如:

1.根據用戶利益最大化原則,排序列表應該是 B、C、A
2.根據用戶購買習慣,有可能是 A、B、C
3.根據運營策略、第三方利益等有可能是C、B、A

這裡暫且先不擴展如何對商品列表進行智能排序,如果需要完整的個性化商品推薦,涉及很多東西,後面有經驗在拿來分享。

我們就這個簡單的 case,一開始最直接的想法就是加個排序列,建索引的時候將排序值計算好直接寫入。後來分析了下原來索引(index) 結構不是這種笛卡爾積的排列,所以在短時間內很難立馬上線,需要新建 index 結構。

後來通過討論用影響評分的方法來解決,可以節省時間快速上線。

通過腳本改變評分

ES query DSL 支持很多種類型的查詢,結果的排序如果沒有特殊聲明 sort field 則是根據es打分(score)來排序的,score 分值越高排序越靠前。

ES score 計算比較複雜,涉及到 TF(詞頻)/IDF(逆向文檔頻率)罕見詞匹配文檔長度權重 boost 向量空間模型 等,不過 ES 提供了幾種封裝好的評分插件供使用。

function_score 查詢來讓我們根據業務場景改變文檔評分方法,根據業務場景我們需要完全控制 score 生成的邏輯,所以我們選擇 script_score 方式。

script_score
如果需求超出以上範圍時,用自定義腳本可以完全控制評分計算,實現所需邏輯。
(參考:https://www.elastic.co/guide/cn/elasticsearch/guide/current/function-score-query.html

腳本預設是 groovy,當然也可以根據需要使用其他腳本語言,我們來看下實現。

script.inline: on
script.enfine.groovy.inline.aggs: on
script.indexed: on
script.file: on

首先在 es.yml 配置中打開腳本支持相關選項。

{
    "query": {
        "function_score": {
            "query": {
                "bool": {
                    "should": [
                        {
                            "match": {
                                "productName": "英語"
                            }
                        }
                    ]
                }
            },
            "score_mode": "first",
            "script_score": {
                "lang": "groovy",
                "params": {
                    "couponPrice": 100
                },
                "script": "def deduct = couponPrice - doc['unitCost'].value.toFloat(); if (deduct > 0) {return 10000 + deduct;}else if(deduct==0 || (deduct<1 && deduct>0)){return 20000;}else{return  doc['unitCost'].value.toFloat()-couponPrice;}"
            },
            "boost_mode": "replace"
        }
    },
    "from": 0,
    "size": 100
}

查詢條件可以任意,關鍵是 script_score 對象,script 是需要 ES 腳本引擎執行的腳本代碼。

一個比較重要的選項 boost_modeboost_mode 是控制整個 document 的評分方式,這裡我們選擇替代(replace)預設計算好的評分。

這裡面的排序有一個小技巧,如何將負數排序在前面,正數排序在後面,還有抵扣後是0的處理。

def deduct = couponPrice - doc['unitCost'].value.toFloat(); 
if (deduct > 0) {
    return 10000 + deduct; 
}else if(deduct==0 || (deduct<1 && deduct>0)){
    return 20000; 
}else{
    return  doc['unitCost'].value.toFloat()-couponPrice;
}

通過 couponPrice 變數表示優惠券面值金額,如果當前商品抵扣完是負數說明需要排序在前面,那麼如何和抵扣完正數分開尼,這裡可以取一個稍微大點的值加上抵扣後的負值,這樣把負值轉換成正數自然就排序在前面。

抵扣後等於0的或者小於1大於0的值也是可以優先安排在前面,當然這裡還是不夠靈活的,最好的方式是根據當前面值、商品價格動態計算才準確。

最後就是抵扣完需要用戶在額外支付的排在最後面,直接取需要額外支付的金額數值作為排序。

通過 ES 評分我們能做很多事情,這個case只是一個簡單的場景。

作者:王清培 (滬江集團資深架構師)

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、Flume概述 Flume是一種分散式、可靠且可用的服務,用於有效的收集、聚合和移動大量日誌文件數據。Flume具有基於流數據流的簡單靈活的框架,具有可靠的可靠性機制和許多故障轉移和恢復機制,具有強大的容錯能力。Flume使用簡單的的可擴展數據模型,迴圈線上分析應用程式。 二、Flume的作用 ...
  • 字體圖標生成 http://fluttericon.com/Flutter中文網 https://flutterchina.club Flutter官網 https://flutter.ioFlutter中文社區https://www.flutter123.netFlutter中文開發者論壇 htt ...
  • 前言 對於每一個程式員來說,空指針異常應該是基本都會遇到過的異常,而且這個異常出現的概率還比較大。 但是,空指針異常又是最容易解決的異常,因為只要加個非空判斷就可以避免了。 本篇通過對比一般非空判斷和 dart 特有的語法糖告訴你如何使用 dart 進行優雅的避空。 目錄 1. dart 線上編輯器 ...
  • 創建Comp組件<template> <div class="x-bar"> <div :id="id" :option="option"></div> </div></template><script> import HighCharts from 'highcharts' import high ...
  • 首先,不論是在Windows、Linux還是Mac上,Webassembly的編譯都是主要依賴於Emscripten SDK這個工具的。但是,在這裡必須要吐槽一下,不論是WebAssembly官網、WebAssembly中文網還是Emscriptem官網安裝文檔上給出的安裝方式基本都是這樣的(中文網 ...
  • 需要實現的功能有: 1、圖上點擊要素會出現自定義的信息視窗 2、將視圖內的要素顯示到右側的標簽中 3、點擊右側的標簽,定位到指定要素視圖 1、圖上點擊要素會出現自定義的信息視窗——註意書寫順序,不規範結果是出不來的 var map = new Map({ basemap:"dark-gray" }) ...
  • 設置預設值 這是被廣泛流傳的js技巧之一,這種編碼應該說是很壞的習慣。 ||的問題 js是一種弱類型的編程語言,代表著傳入的變數並不清楚作為何種類型使用。 這樣的定義在js是不存在的, 對js來說傳入的任意參數都應該考慮不同類型的結果 ,而不是單單考慮一種情況。若傳入0、false等,||所要實現默 ...
  • 上面是將有序數組轉為二叉樹的代碼~ 二分查找的速度為O(log n), 遍歷二叉樹的速度為O(n) ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...