用Elasticsearch構建電商搜尋平臺

AskHarries發表於2018-08-03

電商資料系統主要型別

一箇中等的電商平臺,每天都要產生百萬條原始資料,上億條使用者行為資料。一般來說,電商資料一般有3種主要型別的資料系統:

  1. 關係型資料庫 ,大多數網際網路公司會選用mysql作為關資料庫的主選,用於儲存商品,使用者資訊等資料。 關係型資料庫對於事務性非常高的OLTP操作(比如訂單,結算等)支援良好。
  2. hadoop生態 ,hadoop是資料倉儲主要的載體,除了備份關係型資料庫的所有版本,還儲存使用者行為,點選,曝光,互動等海量日誌資料,hadoop對於資料分析,資料探勘等OLAP支援比關係型資料庫更加具有擴充套件性和穩定性。
  3. 搜尋引擎 ,以elasticsearch和solr為代表。搜尋引擎是獲取資訊最高效的途徑,幾乎成為各類網站,應用的基礎標配設施(地位僅次於資料庫)。

目前搜尋引擎技術已經有非常成熟的開源解決方案,最出名的ElasticSearch和Solr都是基於lucence的。很多中小型網際網路公司搜尋引擎都是基於這兩個開源系統搭建的,但是即便如此,一個搜尋引擎團隊想把搜尋引擎質量做到商用標準,從系統熟悉,服務搭建,功能定製,通常需要花費較長時間。

通用搜尋引擎應用在網際網路商用搜尋 通常會遇到如下幾個問題 :

  • 搜尋引擎與公司現有資料系統的整合。mysql 和 hadoop是電商的兩個主要資料載體,搜尋引擎在全量和增量建索引過程中必須和mysql或hadoop無縫整合,才能發揮搜尋引擎自身的實時性,水平擴充套件性(效能與容量和機器數量成正比)等優勢。
  • 商用搜尋高度定製化與通用搜尋引擎的矛盾。商用搜尋的問題有時候超越了搜尋引擎本身解決的範圍,比如商品的去重,店鋪的去重需要很專業的搜尋引擎使用技巧; 商品的權重,使用者意圖的識別需要演算法和模型的支援。
  • 在不瞭解搜尋引擎專業知識的前提下,很難建立對效能友好的索引。結果造成了通用搜尋效能很差的假象。

筆者是有贊大資料架構師,從自身的搜尋實踐出發,分享搜尋引擎實際的架構和解決的問題。

搜尋引擎架構

有贊搜尋引擎實踐,上半部分主要介紹搜尋引擎的架構和效能優化方面的經驗;下半部分是演算法篇,介紹有贊實際需要的搜尋演算法的問題和解決方案。文章僅僅介紹一箇中型電商公司實際的使用現狀和筆者個人的經驗,不代表搜尋引擎最佳實踐方法,也不代表可以適用所有的場景。

1.技術架構

有贊搜尋引擎基於分散式實時引擎elasticsearch(ES)。ES構建在開源社群最穩定成熟的索引庫lucence上,支援多使用者租用,高可用,可水平擴充套件;並有自動容錯和自動伸縮的機制。我們同事還實現了es與mysql和hadoop的無縫整合;我們自主開發了高階搜尋模組提供靈活的相關性計算框架等功能。

2.索引構建

網際網路索引的特點是實時性高,資料量大。時效性要求使用者和客戶的各種行為能夠第一時間進入索引;資料量大要求一個有效分散式方案可以在常數時間內建立不斷增長的TB數量級索引。

實時索引我們採用 面向佇列的架構 ,資料首先寫入DB(或檔案),然後通過資料庫同步機制將資料流寫入kafka佇列。這種同步機制和資料庫主從同步的原理相同,主要的開源產品有mypipe和阿里推出的canal。es通過訂閱相應的topic實現實時建立索引。

如果資料來源是檔案,則使用flume實時寫入Kafka。

另外一個索引問題是全量索引。有如下幾個場景讓 全量索引是一個必要過程 :

  • 實時更新有可能會丟資料,每次很少的丟失時間長了降低搜尋引擎的質量。 週期性的全量更新是解決這個問題的最直接的方法;
  • 即使能夠保證實時更新,業務的發展有可能有重新建索引的需求(比如增加欄位,修改屬性,修改分詞演算法等)。
  • 很多搜尋引擎是在業務開始後很久才搭建的,冷啟動必須全量建立索引。

我們採用 Hadoop-es 利用hadoop分散式的特性來建立索引。hadoop-es讓分散式索引對使用者透明,就像單機更新索引一樣。一個是分散式的資料平臺,一個是分散式搜尋引擎,如果能把這兩個結合就能夠實現分散式的全量索引過程。Hadoop-es正式我們想要的工具。

我們給出一個通過Hive sql建立索引的栗子 :

  1. drop table search.goods_index;
  2. CREATE EXTERNAL TABLE search.goods_index (
  3. is_virtual int,
  4. created_time string,
  5. update_time string,
  6. title string,
  7. tag_ids array
  8. ) STORED BY ‘org.elasticsearch.hadoop.hive.EsStorageHandler’ TBLPROPERTIES (
  9. ‘es.batch.size.bytes’=’1mb’,
  10. ‘es.batch.size.entries’=’0’,
  11. ‘es.batch.write.refresh’=’false’,
  12. ‘es.batch.write.retry.count’=’3’,
  13. ‘es.mapping.id’=’id’,
  14. ‘es.write.operation’=’index’,
  15. ‘es.nodes’=’192.168.1.10:9200’,
  16. ‘es.resource’=’goods/goods’);

系統把es對映成hive的一個外部表,更新索引就像是寫入一個hive表一樣。實際上所有分散式問題都被系統透明瞭。

不建議從資料庫或檔案系統來全量索引。一方面這會對業務系統造成很大的壓力,另一方面因為資料庫和檔案系統都不是真正分散式系統,自己寫程式保證全量索引的水平擴充套件性很容易出問題,也沒有必要這麼做。

全量索引和增量索引的架構如下圖所示。另外一點是hadoop也是訂閱kafka備份資料庫和日誌的。我個人建議一個公司所有DB和檔案都儲存在hadoop上,這樣做起碼有二個 好處 :

  1. hadoop上使用hive或者spark建立的資料倉儲為大資料提供統一的操作介面。
  2. hadoop資料相對於線上更加穩定,可以作為資料恢復的最後一個防線。

資料倉儲的話題不在本篇文章的討論範圍,這裡只是簡單提一下。

為什麼我們選擇Kafka?Kafka 是一個以高吞吐著名的訊息系統。Kafka開啟了日誌合併(log compaction)功能後,可以永久儲存每條訊息。每一條訊息都有一個key,正好對應資料庫的主鍵,Kafka始終儲存一個key最新的一條訊息,歷史版本會被垃圾回收掉。有了這個特性,Kafka不僅可以儲存資料庫最新的快照,而且可以實現實時更新的訊息系統。

第一次同步的時候,資料表中每行記錄都轉化成以主鍵為key的訊息進入Kafka,並且可以被任意數量的broker消費。之後資料庫的每次更新(insert,updated,delete)都會被轉化成Kafka的訊息。如果一行記錄頻繁被更改,Kafka會識別這些重複的訊息,把舊的訊息回收掉。

Kafka既儲存資料庫最新的全量資料,又提供實時資料流的這個特性為架構的可維護性提供極大便捷。如果你想從零掃描整個資料庫,你只需要從開始消費這個Kafka的topic即可完成,當讀到topic末端,自動獲得實時更新的特性。

Kakfa的另一個特性是 支援從任意斷點讀取資料 ,比如我們全量索引是從HDFS中讀取,我們可以根據HDFS儲存的資料的最後一條的時間戳,直接切換到Kafka讀取之後的資料。

高階搜尋: 超越ES功能限制

高階搜尋模組(AS)在商業搜尋引擎起到至關重要的作用。在各大商業搜尋引擎公司裡面AS已經成為標配,也是變更最為頻繁的模組。

AS在商業搜尋引擎中主要起到如下作用:

  1. 反向代理,實現基於分片的分散式搜尋(實際上es有這個功能); 提供必要的容災支援
  2. 提供外掛化的相關性計算框架
  3. 提供豐富的相關性庫,比如query分析庫,query改寫庫,排序庫,過濾庫等。
  4. 管理不同的搜尋業務

AS 一個主要的功 能 是通過一個個業務外掛來代表相應的搜尋。一個最簡單的外掛只需要包含對應的ES search API,它實際上就是一個配置項,說明es的地址。 這樣AS就是一個純代理。但是商業搜尋的需求都是不是ES本身能夠支援的,所以就需要根據需求寫相應的Query rewriter,rerank等演算法外掛。這樣就實現了框架和業務分離,AS具有極強的擴充套件性和複用性。

AS 另一個功能 是提供通用演算法庫,實際上它只為每種演算法提供程式設計框架。 演算法也是通過外掛的方式加入演算法庫的。這種方法可以讓演算法工程師抽象公共演算法庫供業務方使用,避免重新造輪子。一個具體業務要麼使用已經存在的演算法(並修改引數),要麼自己實現演算法。

上圖是一個 例項 。商品搜尋和分銷搜尋各自實現一個rerank的的演算法,同時都呼叫了系統提供的rerank1的演算法庫,並加入了自己特有的邏輯。

AS除了基本proxy功能外,還提供基於query的cache功能用於應用級別的快取。內部有一個緩衝佇列,防止出現雪崩現象。下一節效能優化中會詳細說明。

ES效能優化

下面幾個小結,我們寫了幾個我們遇到的效能優化場景。

1.使用應用級佇列防止雪崩

ES一個問題是在高峰期時候極容易發生雪崩。ES有健全的執行緒池系統來保證併發與穩定性問題。 但是在流量突變的情況下(比如雙十一秒殺)還是很容易發生癱瘓的現象,主要的原因如下:

  • ES幾乎為每類操作配置一個執行緒池; 只能保證每個執行緒池的資源使用時合理的,當2個以上的執行緒池競爭資源時容易造成資源響應不過來。
  • ES沒有考慮網路負載導致穩定的問題。

在AS裡我們實現了面向請求的全域性佇列來保證穩定性。 它主要做了3件事情。

  1. 根據業務把請求分成一個個slide,每個slide對應一個佇列。 預設一個應用就是一個slide,一個應用也可以區分不同的slide,這樣可以保護一個應用內重要的查詢。
  2. 每個佇列配置一個佇列長度,預設為50。
  3. 每個佇列計算這個佇列的平均響應時間。 當佇列平均響應時間超過200ms,停止工作1s,如果請求溢位就寫入溢位日誌留資料恢復使用。 如果連續10次佇列平均響應時間超過500ms就報警,以便工程師第一時間處理。

2.自動降級

應用級佇列解決雪崩問題有點粗暴,如果一個應用本身查詢就非常慢,很容易讓一個應用持續超時很久。我們根據搜尋引擎的特點編寫了自動降級功能。

比如商品搜尋的例子,商品搜尋最基本的功能是布林查詢,但是還需要按照相關性分數和質量度排序等功能,甚至還有個性化需求。完成簡單的布林查詢,ES使用bitsets操作就可以做到,但是如果如果需要相關性分,就必須使用倒排索引,並有大量CPU消耗來計算分數。ES的bitsets比倒排索引快50倍左右。

對於有降級方案的slide,AS在佇列響應過慢時候直接使用降級query代替正常query。這種方法讓我們在不擴容的情況下成功度過了雙十一的流量陡增。

3.善用filtered query

理解lucence filter工作原理對於寫出高效能查詢語句至關重要。許多搜尋效能優化都和filter的使用有關。filter使用bitsets進行布林運算,quey使用倒排索引進行計算,這是filter比query快的原因。 bitsets的優勢 主要體現在:

  • bitsetcache在記憶體裡面,永不消失(除非被LRU)。
  • bitsets利用CPU原生支援的位運算操作,比倒排索引快個數量級
  • 多個bitsets的與運算也是非常的快(一個64位CPU可以同時計算64個DOC的與運算)
  • bitsets 在記憶體的儲存是獨立於query的,有很強的複用性
  • 如果一個bitset片段全是0,計算會自動跳過這些片段,讓bitsets在資料稀疏情況下同樣表現優於倒排索引。

舉個例子:

  1. query:bool:
  2. tag:'mac'
  3. region:'beijing'
  4. title: "apple"

lucence處理這個query的方式是在倒排索引中尋找這三個term的倒排鏈,並使用跳指標技術求交,在運算過程中需要對每個doc進行算分。實際上tag和region對於算分並沒有作用,他們充當是過濾器的作用。

這就是過濾器使用場景,它只儲存存在和不存在兩種狀態。 如果我們把tag和region使用bitsets進行儲存,這樣這兩個過濾器可以一直都被快取在記憶體裡面,這樣會快很多。 另外tag和region之間的求交非常迅速,因為64位機器可以時間一個CPU週期同時處理64個doc的位運算。

一個lucence金科玉律是: 能用filter就用filter,除非必須使用query(當且僅當你需要算分的時候)。

  1. query:
  2. filtered:
  3. query:
  4. title: "apple"
  5. filter:
  6. tag:"mac"
  7. region:"beijing"

lucence的filtered query會智慧的先計算filter語句,然後才計算query語句,儘可能在進行復雜的倒排演算法前減少計算空間。

4.其他效能優化

線上叢集關閉分片自動均衡。分片的自動均衡主要目的防止更新造成各個分片資料分佈不均勻。但是如果線上一個節點掛掉後,很容易觸發自動均衡,一時間叢集內部的資料移動佔用所有頻寬。建議採用閒時定時均衡策略來保證資料的均勻。

儘可能延長refresh時間間隔。為了確保實時索引es索引重新整理時間間隔預設為1秒,索引重新整理會導致查詢效能受影響,在確保業務時效性保證的基礎上可以適當延長refresh時間間隔保證查詢的效能。

除非有必要把all欄位去掉。索引預設除了索引每個欄位外,還有額外建立一個all的欄位,儲存所有文字,去掉這個欄位可以把索引大小降低50%。

建立索引時候,儘可能把查詢比較 慢 的索引和 快 的 索引物理分離 。

本文對es本身的優化寫的不多,因為es官網和其他的部落格有很多es優化的意見,就不在一一列舉。本文的主要目的是能夠對搭建商用電商搜尋引擎給讀者一個一般性的建議,另外,困擾商用搜尋引擎的最常見的問題是排序和演算法問題。

演算法體系架構

在上半部分中,我們介紹了有贊搜尋引擎的基本框架。搜尋引擎主要3個部件構成。第一,hadoop叢集,用於生成大規模搜尋和實時索引; 第二,ElasticSearch叢集,提供分散式搜尋方案; 第三,高階搜尋叢集,用於提供商業搜尋的特殊功能。

1.索引過程

建立索引過程從原始資料建立倒排索引的過程。這個過程中我們對商品(doc)進行分析,計算商品靜態分,並對商品進行相似度計算。商品的靜態分對於提升搜尋引擎質量起到至關重要的作用,相當於網頁搜尋的pagerank,想象一下如果沒有pagerank演算法,網頁搜尋的質量會有多麼差。在電商搜尋中,最常見的問題是相似商品太多,必須在建立索引過程中就對商品間的相似度進行預計算,以便在檢索過程中進行有效去重。

建立索引的過程如下:

step 1,計算每個doc的靜態分;

step 2,計算兩兩doc的相似度;

step 3,根據相似度和其他資訊對資料進行分庫;

step 4,建立ES索引。

2.檢索過程

檢索過程是搜尋引擎接收使用者的query進行一系列處理並返回相關結果的過程。商業搜尋引擎在檢索過程中需要考慮2個因素:1) 相關性,2) 重要性。

相關性是指返回結果和輸入query是否相關,這是搜尋引擎基本問題之一,目前常用的演算法有BM25和空間向量模型。這個兩個演算法ElasticSearch都支援,一般商業搜尋引擎都用BM25演算法。BM25演算法會計算每個doc和query的相關性分,我們使用Dscore表示。

重要性是指商品被信賴的程度,我們應該吧最被消費之信賴的商品返回給消費者,而不是讓消費之自己鑑別。尤其是在商品充分競爭的電商搜尋,我們必須賦予商品合理的重要性分數,才能保證搜尋結果的優質。重要性分,又叫做靜態分,使用Tscore表示。

搜尋引擎最終的排序依據是:

Score = Dscore * Tscore

即綜合考慮靜態分和動態分,給使用者相關且重要的商品。

檢索的過程大致抽象為如下幾個步驟。

step 1,對原始query進行query分析;

step 2,在as中根據query分析結果進行query重寫;

step 3,在as中使用重寫後的query檢索es;

step 4,在es查詢過程中根據靜態分和動態分綜合排序;

step 5,在as中吧es返回的結果進行重排;

step 6,返回結果。

商品靜態分計算技術

在電商搜尋引擎裡面商品的靜態分是有網頁搜尋裡面的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 = af(下單數) + bg(好評率) + c*h(發貨速度),下一步就是確定a,b,c的引數。一般有兩個方法:

  1. 專家法。根據我們的日常經驗動態調整權重引數;
  2. 實驗法。首先在專家的幫助下賦一個初始值,然後改變單一變數的方法根據abtest的結果來動態調整引數。

商品標題去重

商品標題去重在電商搜尋中起到重要作用,根據資料,使用者通過搜尋頁購買商品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()

方法二:map-reduce 線性方法。

這個方法參考論文”Pairwise Document Similarity in Large Collections with MapReduce”。可以實現幾乎線性的時間複雜度。相對於矩陣運算在大規模(10億以上)pair similarity 運算上面有優勢。這個方法簡單的描述如下: 首先,按照倒排索引的計算方式計算每個term到doc的對映。比如3個doc:

doc1 = 我 愛 北京

doc2 = 我 北京 天安門

doc3 = 我 天安門

轉化為倒排格式,這個需要一次mapper reduce

我 -> doc1, doc2, doc3

愛 -> doc1

北京 -> doc1, doc2

天安門 -> doc2, doc3

然後,對於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

最後,對於輸出進行聚合,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

對於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可以支援這個需求。

原始的query:

  1. {
  2. “query”{
  3. “match”: {
  4. “query”: ”蘋果手機”
  5. }
  6. }
  7. }

優化後的query:

  1. {
  2. "query": {
  3. "should": [
  4. {
  5. "match": {
  6. "content": {
  7. "query": "蘋果手機",
  8. "boost": 10
  9. }
  10. }
  11. },
  12. {
  13. "match": {
  14. "content": {
  15. "query": "iphone",
  16. "boost": 8
  17. }
  18. }
  19. },
  20. {
  21. "match": {
  22. "content": {
  23. "query": "iphone6",
  24. "boost": 5
  25. }
  26. }
  27. }
  28. ]
  29. }
  30. }

其他比如核心詞識別,歧義詞糾正等方法差不多,本文不做詳細闡述。

小結

商業電商搜尋演算法另外兩個重要技術,一個是類目體系建立和應用,另一個是個性化技術。這個兩項技術我們還處在探索階段。類目體系我們主要使用機器學習的方法進行訓練,個性化主要通過使用者畫像進行Query改寫來實現。等我們上線有效果在與大家分享。

搜尋演算法是一個非常值得一個電商產品持續投入的技術。一方面如果技術人員要有良好的技術背景,可以借鑑很多成熟的技術,避免重複造輪子; 另一方面,每個產品的搜尋都有自身的特點,需要深入研究產品的特性給出合理的解決方案。

用Elasticsearch構建電商搜尋平臺


相關文章