搜索引擎對于檢索性能要求比較高,為此,系統開放了兩階段排序過程:基礎排序和業務排序,即粗排和精排。基礎排序即是海選,從檢索結果中快速找到質量高的文檔,取出TOP N個結果再按照精排進行精細算分,最終返回最優的結果給用戶。由此可見,基礎排序對性能影響比較大,業務排序對最終排序效果影響比較大。因此,基礎排序要求盡量簡單有效,只提取業務排序中的關鍵因子即可。其中,基礎排序與業務排序目前均通過排序表達式的方式進行配置。
排序表達式(Ranking Formula)允許用戶為應用自定義搜索結果排序方式,通過在查詢請求中指定表達式來對結果排序。排序表達式支持基本運算(算術運算、關系運算、邏輯運算、位運算、條件運算)、數學函數和排序特征(feature)等。Open Search對于幾種經典的應用(如論壇、資訊等)提供了表達式模板,用戶可根據自己數據的特點,選擇合適的表達式模板,并以此為基礎進行修改,生成自己的表達式。
在進行相關性排序(業務排序)之前,首先要了解下系統排序策略:通過query等子句找到符合條件的文檔后,會進入排序階段(具體參見sort子句),如果未指定sort子句或者sort子句中顯式指定了RANK,那么都將進入到相關性算分階段。
如何設計基礎排序和業務排序的表達式要取決于實際搜索場景的需求,最佳實踐-功能篇有個《相關性實戰》的文章,較詳細介紹了在幾個典型場景下如何來思考和設計排序因子,大家可以參考。
排序表達式中一律使用數值或數值字段類型參與基本運算操作,例如算數,關系,邏輯,條件等運算操作,大部分函數都不支持字符串類型進行運算。
基本運算
運算 | 運算符 | 說明 |
一元運算 | - | 負號,功能為對某個表達式的值取負值,如-1, -max(width)。 |
算數運算 | +, -, *, / | 如width / 10 |
關系運算 | ==,!= ,>, <, >=, <= | 如width>=400 |
邏輯運算 | and ,or,! | 如width>=400 and height >= 300, !(a > 1 and b < 2) |
位運算 | &, |,^ | 如 3 & (price ^ pubtime) + (price | pubtime) |
條件運算 | if(cond, thenValue, elseValue) | 如果cond的值非0,則該if表達式的實際值為thenValue,否則為elseValue。如if(2, 3, 5)的值為3,if(0, 3, 5)的值為5。(注意:不支持字符串字段類型,如literal或text類型都不支持;取值范圍為int32的取值范圍) |
in 運算 | i in [value1, value2, …, valuen] | 如果i的值在集合[value1, value2, …, valuen]中出現,則該表達式值為1,否則為0。例如: 2 in [2, 4, 6]的值為1,3 in [2, 4, 6]的值為0。 |
數學函數
函數 | 說明 |
max(a, b) | 取a和b的最大值。 |
min(a, b) | 取a和b的最小值。 |
ln(a) | 對a取自然對數。 |
log2(a) | 對a取以2為底的對數。 |
log10(a) | 對a取以10為底的對數。 |
sin(a) | 正弦函數。 |
cos(a) | 余弦函數。 |
tan(a) | 正切函數。 |
asin(a) | 反正弦函數 |
acos(a) | 反余弦函數 |
atan(a) | 反正切函數。 |
ceil(a) | 對a向上取整,如ceil(4.2)為5。 |
floor(a) | 對a向下取整,如floor(4.6)為4。 |
sqrt(a) | 對a開方,如sqrt(4)為2。 |
pow(a,b) | 返回a的b次冪,如pow(2, 3)為8。 |
now() | 返回當前時間,自Epoch (00:00:00 UTC, January 1, 1970)開始計算,單位是秒。 |
random() | 返回[0, 1]間的一個隨機值。 |
內置特征函數
OpenSearch提供了豐富的內置特征函數,如LBS類、文本類、時效類等,可以用在排序表達式中,相互組合實現強大的相關性排序效果。
Cava插件
Cava是OpenSearch引擎團隊基于llvm實現的一門高效的編程語言,它的語法和Java類似,性能與c++相當。Cava是一門面向對象的編程語言,支持即時編譯(jit),支持各種安全檢查保證程序更加健壯。使用cava和OpenSearch提供的cava庫,在OpenSearch中可以定制自己的排序插件,相比于OpenSearch支持的表達式,使用cava實現排序插件具有以下優點:
更強的定制能力:cava提供了較表達式更加豐富的語法功能,比如for循環,函數定義,類定義等,用戶可以實現自己的業務需求。
更易于維護:cava實現的排序插件比表達式更具有可讀性,更易于維護。
更易于接受:cava的語法和Java類似,熟悉Java的同學很容易使用cava進行開發,學習成本較低。
溫馨提示:Cava插件僅支持獨享型應用配置。
流程演示
這里以文本相關性排序函數配置為例,演示基礎排序和業務排序如何配置:
1.創建基礎排序策略,進入“開放搜索控制臺”,在排序配置—->策略管理,點擊“創建”: 填寫“策略名稱”,選擇應用范圍為“基礎排序”,選擇類型為“表達式”,點擊“下一步”:
選擇算分特征為“static_bm25”,設置權重為“10”(注:這里權重為10,就代表該得分在計算的時候*10):也可以選擇搜索字段(字段必須是屬性字段,并且只支持數值類型的字段,如:INT、DOUBLE、FLOAT類型),設置權重,則該字段*權重的得分也會加在排序分里:
配置完成,返回策略管理頁:
2.創建業務排序策略,進入“開放搜索控制臺”,在排序配置—->策略管理,點擊“創建”: 填寫“策略名稱”,選擇應用范圍為“業務排序”,選擇類型為“表達式”,點擊“下一步”:
在內置函數里選擇“text_relevance”,括號內填入待查詢索引里配置的字段名,點擊“完成”:配置完成,返回排序配置頁面:
3.查看排序效果,在搜索測試界面,配置基礎和業務排序參數,并打開顯示排序明細:查看各函數算分結果:
對于文檔得分的排序分為兩個階段:基礎排序和業務排序,通過query召回并通過filter過濾后的文檔,首先進入基礎排序,根據基礎排序表達式海選出文檔得分較高的文檔,然后取出TOP N個結果再按照業務排序表達式進行精細算分,最終返回最優的結果給用戶。算分邏輯如下:
若只配置了基礎排序,則文檔得分為(10000+基礎排序表達式計算的結果),總分最大為20000,超過20000結果仍為20000。
若只配置了業務排序,則文檔得分為(10000+業務排序表達式計算的結果),總分無上限。
若同時配置了基礎排序和業務排序,那么進入業務排序的文檔最終得分為(10000+業務排序表達式計算的結果),其余文檔最終得分為(10000+基礎排序表達式計算的結果,總分最大為20000,超過20000結果仍為20000)。
可以創建多個基礎排序和業務排序規則,但是查詢請求時僅支持同時使用1個基礎排序和一個業務排序規則。
first_rank_name僅支持填寫一個排序表達式名稱,不支持多個基礎排序表達式同時使用;
second_rank_name僅支持填寫一個排序表達式名稱,不支持多個業務排序表達式同時使用。
SDK 配置演示
Java SDK 演示:
// 設置粗精排表達式,此處設置為默認
Rank rank =newRank();
rank.setFirstRankName("default");//基礎排序策略名稱
rank.setSecondRankName("default");//業務排序策略名稱
rank.setReRankSize(5);//設置參與精排文檔個數
PHP SDK 演示:
//指定粗排表達式
$params->setFirstRankName('default');
//指定精排表達式
$params->setSecondRankName('default');
注意:
如果在控制臺中設置了默認的基礎排序和業務排序,而在代碼中又重新指定基礎排序和業務排序,那么在程序運行時,查詢接口以代碼中配置的基礎排序和業務排序為準。
代碼中查看排序明細:
方法:在config子句中添加參數:format:fulljson;
在返回結果中sortExprValues 就是文檔得分:
sortExprValues 是個數組,表示sort子句中排序字段的值,例:
sort=-price;-RANK
那么sortExprValues 就是[price,文檔得分]
如果不設置sort,默認就是文檔得分