本文首發於 vivo 網際網路技術微信公眾號 mp.weixin.qq.com/s/wLMvJPXXa…
作者:Eike Dehling
翻譯:楊振濤
本文由來自 Textkernel 的軟體與資料工程師 Eike Dehling 於2018年10月23日釋出與其Linkedin 的 pulse 上,已獲得翻譯授權。
目錄:
一、Fast Nearest Neighbours
二、Elasticsearch 外掛
三、整合工作
四、結論
最近我在幫一個資料科學家同事工程化一個基於深度學習模型的搜尋系統。他們的專案是關於在文件嵌入應用深度學習模型,然後使用嵌入向量到我們的搜尋系統中來查詢相似文件。
一個文件嵌入本質上其實是一個(長的)數值陣列,查詢相似文件就相當於查詢其他與其較相近的(長的)數值陣列;可以採用諸如歐氏距離等來衡量相似性。
可以藉此來查詢相似文件,但是因為不是直接基於關鍵詞而是基於“嵌入”,所以可以自動獲得與同義詞擴充套件相媲美的效果。它會查詢相關文件,即使它們使用不同的關鍵詞,因此能比關鍵詞檢索表現更好。
已經有解決這種問題的工具了,比如 facebook 的 FAISS 庫(github.com/facebookres…)。這個類庫速度非常快,並且支援多種智慧方法使用嵌入向量實現快速檢索。不過它不能友好地整合到類似 Elasticsearch 這樣的搜尋引擎中。
對於 Elasticsearch 來說,也有一些外掛(github.com/muhleder/el…)提供了相似度計算功能,但是它們的速度並不怎麼樣,因為它們只計算了向量相似度而沒有做過濾。
所以我們自己動手實現了更好的解決方案。
一、Fast Nearest Neighbours
為了更快速檢索通常會使用各種“索引”,這種資料結構支援高效地過濾出相關的匹配,而無需單獨評估每一個匹配。基於關鍵詞的檢索一般使用“倒排索引”;基於地理位置的檢索,一般使用一種叫做 KD樹 的資料結構。我們也需要諸如此類的機制來快速過濾出最相關的匹配,因此我們只需要在這個較小的集合上計算精確得分。這一點非常重要,因為在一個高維向量的超大集合上計算距離,是代價非常高昂(慢)的操作。
上文提到的 FAISS 庫提供了多種方式來解決這個問題:
- PCA 降維
- K 均值聚類
- 區域性敏感雜湊
- 可能還有其他我不知道方法
這些方法中的每一種都能實現高效的索引方法,因此可以快速地篩選出較近鄰的文件,然後通過計算精確的距離來查詢最近鄰文件。在降維以後就可以使用 KD樹,聚類或者區域性敏感雜湊後也可以使用倒排索引。
上圖揭示瞭如何通過過濾資料集來加速計算,需要計算精確距離的文件數與計算時間之間是線性關係;同時也說明了高效地過濾掉不相似文件多麼重要。
當然所有這些方法都是有可能在 Elasticsearch 裡得到實現的,其優點是便於和其他檢索系統整合。屆時就可以組合使用關鍵詞查詢或其他基於深度學習的查詢結果了。
實驗表明在我們的資料集上,結合了 PCA 降維後再使用 KD 樹索引,能帶給我們速度和精度的最佳y組合。
上圖揭示了縮小資料集是如何影響結果精確度的。能夠看到,過濾得太狠意味著我們會丟失一些最近鄰文件;而如果過濾掉 50k 到 75k 的文件,就可以找到所有的最近鄰文件,同時計算時間只佔暴力計算所有距離的很小一部分。
二、Elasticsearch 外掛
在 Lucene 即 Elasticsearch的底層類庫中,KD樹的資料結構已經實現了,但還沒有通過 Elasticsearch 的 API 暴露出來。已經有外掛可以計算精確的向量距離,所以我們只需要開發一個小外掛來支援使用這種索引結構即可。參見這裡:github.com/EikeDehling…
三、整合工作
現在整合工作只是相當於把拼圖圖片按照正確的順序拼到一起:
- 安裝 Elasticsearch 外掛
- PCA降維(Python/sklearn 或者 Java/Smile)
- 索引降維後的完整向量到 Elasticsearch 中(以及其他必要屬性)
- 整裝待發!
安裝外掛、建立索引以及新增文件請參考這裡(github.com/EikeDehling…)。完成這些步驟後,現在就可以使用我們的嵌入向量了!請注意 pca_reduced_vector 上的範圍查詢,這才是我們新外掛起到的作用。
四、結論
我們展示瞭如何應用深度學習向量來實現高效的搜尋。這一方法適用於想要尋找相似文件而普通關鍵詞查詢不夠好的任何應用場景。其中的嵌入向量,可以使用諸如 doc2vec 等來實現。
更多內容敬請關注 vivo 網際網路技術 微信公眾號
注:轉載文章請先與微訊號:labs2020 聯絡。