搜尋PM:有贊搜尋引擎實踐(演算法篇)
導讀:原文是有贊搜尋大牛的分享。我對內容進行整合,剔除一些產品不需要過多關注的程式碼和技術細節,增添點評更多產品上的策略和想法。
1. 搜尋演算法總體架構
商業電商搜尋由於搜尋的特殊性, 獨立的ElasticSearch叢集是無法滿足多樣的演算法需求的, 我們在搜尋的各個部件上都有相應的演算法外掛, 用於構建商業電商搜尋引擎的演算法體系。
1.1 索引過程
建立索引過程從原始資料建立倒排索引的過程。 這個過程中我們對商品(doc)進行分析, 計算商品靜態分, 並對商品進行相似度計算。 商品的靜態分對於提升搜尋引擎質量起到至關重要的作用 , 相當於網頁搜尋的pagerank, 想象一下如果沒有pagerank演算法, 網頁搜尋的質量會有多麼差。。
在電商搜尋中, 最常見的問題是相似商品太多, 必須在建立索引過程中就對商品間的相似度進行預計算 , 以便在檢索過程中進行有效去重。
建立索引的過程如下:(doc是商品)
step 1. 計算每個doc的靜態分
step 2. 計算兩兩doc的相似度
step 3. 根據相似度和其他資訊對資料進行分庫
step 4. 建立ES索引
1.2 檢索過程
檢索過程是搜尋引擎接收使用者的query進行一系列處理並返回相關結果的過程。
商業搜尋引擎在 檢索過程中需要考慮2個因素:
1) 相關性 (召回的有哪些,是池子)
2) 重要性(那些權重高,優先靠前排)
其實本質和個性化推薦差不多,都是要先召回再篩選排序。
相關性是指返回結果和輸入query是否相關, 這是搜尋引擎基本問題之一 , 目前常用的演算法有BM25和空間向量模型。 這個兩個演算法ElasticSearch都支援, 一般商業搜尋引擎都用BM25演算法。 BM25演算法會計算每個doc和query的相關性分, 我們使用Dscore表示。
重要性是指商品被信賴的程度, 我們應該吧最被消費之信賴的商品返回給消費者, 而不是讓消費之自己鑑別。 尤其是在商品充分競爭的電商搜尋, 我們必須賦予商品合理的重要性分數, 才能保證搜尋結果的優質。 重要性分, 又叫做靜態分, 使用Tscore表示。
搜尋引擎最終的排序依據是:
Score = Dscore * Tscore
(這部分很經典很重要,不管做搜尋、推薦、排序、精準投放等,都是這個原理。權重分值)
即綜合考慮靜態分和動態分, 給使用者相關且重要的商品。(PM瞭解過程即可)
檢索的過程大致抽象為如下幾個步驟:
step 1. 對原始query進行query分析
step 2. 在as中根據query分析結果進行query重寫
step 3. 在as中使用重寫後的query檢索es
step 4. 在es查詢過程中根據靜態分和動態分綜合排序
step 5. 在as中吧es返回的結果進行重排
step 6. 返回結果
以下細節,PM不需太糾結,關注是流程、模組原理

2. 商品靜態分計算技術
在電商搜尋引擎裡面商品的靜態分,是有網頁搜尋裡面的pagerank同等的價值和重要性, 他們都是doc固有的和查詢query無關的價值度量。
(每個商品的靜態分,是排序、過濾等的基礎)
pagerank通過doc之間的投票關係進行運算, 相對而言商品的靜態分的因素會更多一些。 商品靜態計算過程和pagerank一樣需要解決如下2個問題:
1、 穩定性。 pagerank可以保證一個網站不會因為簡單鏈接堆砌可以線性提升網站的排名。 同樣, 商品靜態分的計算不可以讓商品可以通過增加單一指標線性增加分值(比如刷單對搜尋引擎的質量的影響)。
2、 區分度。 在保證穩定性的基礎上商品靜態分要有足夠的區分度可以保證同樣搜尋的條件下, 排在前面的商品的質量比排在後面的商品的質量高。
我們假設商品的靜態分有3個決定性因素, 1.下單數, 2. 好評率 3. 發貨速度
靜態分我們使用Tsocre表示, Tscore可以寫成如下形式:
Tscore = a * f(下單數) + b * g(好評率) + c * h(發貨速度)
a,b,c是權重引數, 用於平衡各個指標的影響程度。 f,g,h是代表函式用於把原始的指標轉化成合理的度量。
首先, 我們需要尋找合理的代表函式。
1、對各個指標取log。 log的導數是一個減函式, 表示為了獲得更好的分數需要花費越來越多的代價。
2、標準化。 標準化的目的讓各個度量可以在同一區間內進行比較。
比如下單數的取值是0~10000, 而好評率的取值為0~1。 這種情況會影響到資料分析的結果和方便性, 為了消除指標之間的量綱的影響, 需要進行資料標準化處理, 以解決資料指標之間的可比性。最常用的標準化方法是z-score標準化方法。
z-score 標準化方法
"概率論"告訴我們對於滿足正態分佈的資料來說, 均值前後3個z-score的範圍可以覆蓋99%的資料。 經驗地, 我們把>5個zscore 或者小於 -5個zscore的分數設定成5*zscore或者-5zscore。 特別說明的是, 我們不建議使用min-max標準化方法。 這種方法又叫離差標準化, 是對原始資料的線性變換, 使結果值對映到[0-1]之間, 轉化函式如下:這種方法非常不穩定, 假設一個奇異點是第二大的值的1000倍, 會讓大部分的值都集中在0~0。01, 同樣失去了歸一化的目的。

圖一是使用min-max歸一化後的資料分佈, 顯然大部分資料被"壓扁"在很小的範圍; 圖二使用log歸一化後的資料分佈, 由於log緩解了增長速度, 可以看出來已經有一個不錯的結果了, 圖三是在log的基礎上進行z-score歸一化, 可以看出來, z-score讓資料變得非常平滑。(圖一: min-max歸一化)(圖二: log歸一化)(圖三: log-zscore歸一化)



最後, 選擇合適的權重 經過log-zscore歸一化以後, 我們基本上吧f,g,h的表示的代表函式說明清楚。 Tscore = a f(下單數) + b g(好評率) + c*h(發貨速度), 下一步就是確定a,b,c的引數。 一般有兩個方法:
a) 專家法。 根據我們的日常經驗動態調整權重引數;
b) 實驗法。 首先在專家的幫助下賦一個初始值, 然後改變單一變數的方法根據abtest的結果來動態調整引數。
3. 商品標題去重
商品標題去重在電商搜尋中起到重要作用, 根據資料, 使用者通過搜尋頁購買商品80%選擇搜尋的前4頁。 商品標題的重複會導致重要的頁面沒有含金量, 極大降低了搜尋的購買率。
舉個例子:
Title1:美味/香蕉/包郵/廣東/高州/香蕉/banana//無/催熟劑/
Title2:美味/香蕉/廣東/高州/香蕉//非/粉蕉/包郵/
首先, 進行特徵向量化
這裡用到 "bag of word" 技術, 將詞彙表作為空間向量的維度, 標題的每個term的詞頻作為這個feature的值。 以這個例子來說。 這個詞彙的維度為: 美味(0), 香蕉(1), 包郵(2), 廣東(3), 高州(4), banana(5),無(6), 催熟劑(7),非(8),粉蕉(9) 位置: 0,1,2,3,4,5,6,7,8,9
Title1: 1,2,1,1,1,1,1,1,0,0
Title2: 1,2,1,1,1,0,0,0,1,1
這個每個title都用一個固定長度的向量表示。
再次, 計算兩兩相似度
相似度一般是通過計算兩個向量的距離實現的, 不失一般性, 在這裡我們使用1-cosine(x,y)來表示兩個向量的距離。 這是一個"All Pair Similarity"的問題, 即需要兩兩比較, 複雜度在O(n^2)。 在商品量巨大的時候單機很難處理。 我們給出兩種方法用於實現"All Pair Similarity"。
方法一: spark的矩陣運算。
rddRows = sc。parallelize(["1 0 2 0 0 1","0 0 4 2 0 0"])
rddRows。map(lambda x: Vectors。dense([float(each) for each in str(x)。split(" ")]))
mat = RowMatrix(rddRows)
simsPerfect = mat。columnSimilarities()
1
2
3
4
5
6
方法二: map-reduce 線性方法。 這個方法參考論文"Pairwise Document Similarity in Large Collections with MapReduce"。 可以實現幾乎線性的時間複雜度。 相對於矩陣運算在大規模(10億以上)pair similarity 運算上面有優勢。 這個方法簡單的描述如下: 首先, 按照倒排索引的計算方式計算每個term到doc的對映。 比如3個doc:
doc1 = 我 愛 北京
doc2 = 我 北京 天安門
doc3 = 我 天安門
1
2
3
轉化為倒排格式, 這個需要一次mapper reduce
我 ->doc1,doc2,doc3
愛 ->doc1
北京 ->doc1,doc2
天安門 ->doc2,doc3
1
2
3
4
然後, 對於value只有一個元素的過濾掉, 對於value大於2個doc的兩兩組合:
doc1,doc2<---- from: 我 ->doc1,doc2,doc3
doc1,doc3<---- from: 我 ->doc1,doc2,doc3
doc2,doc3<---- form: 我 ->doc1,doc2,doc3
doc1,doc2<---- from: 北京 ->doc1,doc2
doc2,doc3<---- from: 天安門 ->doc2,doc3
1
2
3
4
5
最後, 對於輸出進行聚合,value為重複次數和兩個doc乘積開根號的比。
doc1,doc2 ->2/(len(doc1)*len(doc2))^1/2=0。7
doc1,doc3 ->1/(len(doc1)*len(doc3))^1/2=0。3
doc2,doc3 ->2/(len(doc2)*len(doc3))^1/2=0。3
1
2
3
對於2個title1, title2, 如果X(title1, title2) > 0。7 則認為title1和title2相似, 對於相似的兩個doc, 靜態分大的定義為主doc, 靜態分小的定義為輔doc。 主doc和輔doc分別建庫。

區別於網頁搜尋(網頁搜尋直接將輔doc刪除), 我們將主doc和輔doc分別建庫。 每一次搜尋按比例分別搜主庫和輔庫, 並將結果融合返回。 這樣可以保證結果的多樣性。
店鋪去重
店鋪去重和商品標題去重有點不同。
由於電商特定場景的需要, 不希望搜尋結果一家獨大, 這樣會引發強烈的馬太效應。 店鋪去重不能使用如上的方法進行。 因為上面的方法的主要依據是文字相似, 在結果都相關的前提下, 進行適當的取捨。 但是店鋪去重不是這樣的特性。
設想一下, 如果我們根據店鋪是否相同, 把同一店鋪的商品分到主庫和從庫中, 如下圖所示。

A和B代表不同的店鋪。
在搜尋香蕉的時候, 的確可以控制A店鋪結果的數量, 但是在搜尋"梨"的時候就錯誤的吧B店鋪的梨排在前面了(假設A:梨比B:梨靜態分高)。
實際上想達到店鋪去重的效果通過分桶搜尋是很容易做的事情。 我們假設每頁搜尋20個結果, 我們把索引庫分成4個桶, 每個商品對桶數取模得到所在桶的編號。 這樣可以保證同一店鋪的商品僅在一個桶裡面。

搜尋的過程每個桶平均分攤搜尋任務的25%, 並根據靜態分合併成一頁的結果。 這樣同一保證結果的相對順序, 又達到了店鋪去重的目的。
如上圖所示, 搜尋"香蕉", 雖然A店鋪有10個滿足需求的結果, 但是每頁搜尋醉倒只有5個結果可以展示。
Query分析與Query改寫技術
上面介紹了幾個建立索引過程中幾項技術, 檢索過程中的關鍵技術有很多。
其中最著名的是query分析技術。 我們使用的query分析技術主要包括核心詞識別, 同義詞拓展, 品牌詞識別等等。
query分析技術大部分都是NLP研究範圍, 本文就不詳細闡述很多理論知識。
我們重點介紹同義詞拓展技術。 這個技術一般都需要根據自己的商品和和使用者日誌特定訓練, 無法像分詞技術和品牌詞識別一樣有標準的庫可以適用。
同義詞拓展一般是通過分析使用者session日誌獲取。 如果一個使用者輸入"蘋果手機"沒有得到想要的結果, 他接著輸入"iphone", 我們在"蘋果手機"和"iphone"之間建立一個轉移關係。 基於統計, 我們可以把使用者query建立一個相互聯絡的權重圖。
使用者輸入query "蘋果手機", 根據query分析, "蘋果手機"有 "iphone" 0。8, "iphone 6" 0。5 兩個同義詞。 0。8和0。5分別表示同義的程度。 我們想要"蘋果手機", "iphone", "iphone 6" 3個query同時輸入, 並且按照同義的程度對不同的query賦予不同的權重。 ElasticSearch提供的BoostingQuery可以支援這個需求。 參考: ofollow,noindex">https://www。elastic。co/guide/en/elasticsearch/guide/current/ boosting query_clauses。html

其他比如核心詞識別, 歧義詞糾正等方法差不多, 本文不做詳細闡述。
其他
商業電商搜尋演算法另外兩個重要技術, 一個是類目體系建立和應用,另一個是個性化技術。 這個兩項技術我們還處在探索階段。 類目體系我們主要使用機器學習的方法進行訓練, 個性化主要通過使用者畫像進行Query改寫來實現。 等我們上線有效果在與大家分享。
小結
搜尋演算法是一個非常值得一個電商產品持續投入的技術。 一方面我們技術人員要有良好的技術背景, 可以借鑑很多成熟的技術, 避免重複造輪子;
另一方面, 每個產品的搜尋都有自身的特點, 需要深入研究產品的特性給出合理的解決方案。 本文給出的案例都具有代表性, 靈活的運用搜索的各方面的技術。
另外, 商業搜尋非常看重投入產出比, 我們也需要在眾多方案中尋找捷徑。 比如我們在做類目體系時候, 沒有投入大量的人力資源用於標註資料, 而是通過爬蟲爬取其他電商的資料進行參考, 從而節省了80%的人力資源。
後續詳細內容,請加入小組再閱讀(限時免費)
以上內容,原文來自整理自飯糰“策略產品經理研習社”,點選這裡可關注:https://fantuan.guokr.net/groups/149349010586624?utm_source=kuahao
更多幹貨可關注微信公眾號:鳳城狂客(chanpin007)
想學習更多關於產品策略、工作、認知和乾貨,可關注公眾號進入知識社群(免費)。

同時,也歡迎小夥伴加我的微信: mllianai 交流。
