简析Instgram的搜索架构
原文: Search Architecture
作者: Maxime Boucher, Thomas Dimson
翻譯: 孫薇
責編: 錢曙光,關注架構和算法領域,尋求報道或者投稿請發郵件qianshg@csdn.net,另有「CSDN 高級架構師群」,內有諸多知名互聯網公司的大牛架構師,歡迎架構師加微信qshuguang2008申請入群,備注姓名+公司+職位。
Instagram的優勢在于:雖然公司規模小,卻擁有相對大得多的基礎設施架構,在恰當的時候還能利用資源以借助Facebook十年來積累的經驗。Facebook的“Unicorn”搜索架構是一款以社交圖譜為基礎的搜索引擎,可擴展至包含上萬億個文檔的索引。2015年初,Instagram將所有的搜索架構從Elasticsearch轉到Unicorn。同一時期,Instagram的搜索流量增加了65%,這不僅是用戶群數量增加的結果,也是忠實用戶數(每次使用搜索引擎時都會使用Instagram)增長了12%的結果。
這樣的成果部分得益于Unicorn通過社交功能及二階連接執行查詢排序的能力。在7.0升級后,通過對圖譜的各個部分編制索引,Instagram的搜索能力更強,可以更迅速、更便捷地搜索任何想要查找的信息,包括人、地點、標簽與媒體。
什么是搜索?
Instagram的搜索架構包含了所有興趣實體,如:標簽、位置、用戶及媒體,這些內容以非規范化的形式儲存,通常被稱為文檔——它們被分組歸類到集合中,可通過高效的集合運算(如AND、OR與NOT)來查詢,在實際操作中Instagram對運算結果高效地排序篩選,只留下與指定查詢最相關的文檔。當用戶查詢時,服務器后端會將查詢轉換成編碼,進行集合運算后篩出最佳匹配結合的有序集合。
數據錄入
Instagram每秒可處理數百萬個搜索請求,其中很多如注冊、點贊和上傳在內的請求需要修改現有記錄,并向主PostSQL數據庫增加新行。為了確保可搜索文件的集合正確,我們需要將這些變更告知搜索架構。此外,在PostgreSQL數據庫中,搜索時一般需要不只一行的信息,例如在照片上傳后,該用戶帳號的歷史信息也會用在搜索中。
為了解決非規范化的問題,Instagram引入了Slipstream系統,該系統會對Instagram上的event進行編碼,再錄入包含更多信息的Thrift架構中。這些event以二進制序列化格式存儲,通過異步發送-訂閱頻道(Firehose)來發送。譬如“搜索”功能之類的消費者訂閱到Firehose,過濾掉不相干的event,再對其余event作出反應。Firehose在Facebook的Scribe頂端實現,讓消息傳輸可以異步實現。
下圖展示了該架構:
自系統化之后,Thrift中跨請求對象再次復用;同時無需自定義反序列化,消費者便可直接消費所傳遞的信息。Slipstream架構中與照片對應的子集如下所示:
struct User { 1: required i64 id; 2: string username; 3: string fullname; 4: bool is_private; ... } struct Media { 1: required i64 id; 2: required i64 owner_id; 3: required MediaContentType content_type; ... } struct LikeEvent { 1: required i64 liker_id; 2: required i64 media_id; 3: required i64 media_owner_id; 4: Media media; 5: User liker; 6: User media_owner; ... 8: bool is_following_media_owner; } union InstagramEvent { ... 2: LikeEvent like; ... } struct FirehoseEvent { 1: required i64 server_time_millis; 2: required InstagramEvent event;}Firehose頻道的信息作為best-effort delivery,在消息傳遞中預計只有很小比例的數據丟失。在搜索時,我們通過數據核對進程或base build建立起最終一致性:每天晚上都會對Instagram連接到Hive的所有PostgreSQL數據庫進行截圖存檔,并定期在這些Hive表格與結構中查詢每個垂直搜索的所有文檔;將base build與從Slipstream中獲取的數據相合并,以確保在數據丟失的情況下,系統也保持最終一致性。
數據輸出
處理查詢
如果數據正確接收,則搜索架構可在一定的約束下高效提取相關的文檔,我們稱之為“約束查詢(constraint a query)”,一般是根據用戶提供的文字(例如:用戶輸入“Justin”,實際想搜索Justin Bieber)所衍生。在Unicorn中,查詢被重寫為明確表達目的的S-Expressions,比如:
(and user:maxime (apply followed_by: followed_by:me))以上代碼翻譯過來就是:查找我關注、名叫maxime的人所關注的人。在搜索架構中,這個過程分兩步處理:
-
生成候選集:找出一組與給定查詢匹配的文檔,Instagram的服務器后端使用反向索引(reverse index)結構,即通過關鍵詞索引找到多組文檔。舉例來說,輸入關鍵詞“name:justin”就會出現包含“justin”的用戶名集合。
-
排序:從所有候選集中選出最佳文檔。獲取候選文檔后,從文檔的元數據編碼中找出特征,例如:用戶Justin Bieber的特征之一是關注者多達3.23千萬。系統會將這些特征用于計算“擬合度值(goodness)”,以便對候選子集進行排序。擬合度可通過機器學習或手動調整而生成——在機器學習案例中,針對特定候選者,我們可以設計點擊或關注有所差異的特征。
通過這兩個步驟,最終得出指定查詢的最佳文檔有序列表。
社交圖譜搜索
在優化搜索功能時,為了提供更具個性化的搜索結果,Instagram現在會將用戶關注的人以及他們所關注的人都納入搜索范圍。這樣一來,基于用戶所關注的人再來查找某人會更容易。
使用Unicorn后,我們能夠對Instagram上的所有帳號、媒體、標簽和地址,還有其間各類關系生成索引。舉例來說,通過對某個用戶的關注者編輯索引,Unicorn可以回答這類問題:
“用戶X與用戶Y同時關注的賬號有哪些?”
同樣的,通過對媒體中的位置進行索引,Unicorn能得出如下信息:
“我關注的帳號所發布的媒體是在紐約拍攝的”。
優化帳號搜索功能
單獨使用Instagram的圖譜的話體驗不佳,不足以找到想要查找的帳號,必須結合Unicorn的搜索排序架構使用才能奏效。
完成這一目標的方法之一是在Instagram上為現有連接建立模型。在Facebook上,賬號間的基本關系是非定向的(通常會互加好友),而在Instagram上卻不一定要回粉。我們的團隊必須對搜索排序算法進行修改,以存儲并檢索Instagram關注圖譜中的帳號信息。對Instagram來說,要使用Unicorn按照混合的方式來檢索帳號:“你關注的人所關注的人”和“關注你的人所關注的其他人”。
此外,Instagram的用戶關注彼此的原因各種各樣,某位用戶無需與他所關注的用戶保持完全一致的興趣點。我們的團隊構建了一個模型,針對每個用戶所關注的帳號進行排序,因此在搜索時,與搜索者關系更為密切的用戶所關注的對象會優先顯示。
統一搜索框
有時,搜索查詢的最佳匹配可能是標簽或地點。根據之前的經驗,Instagram的用戶必須明確選擇是搜索帳號還是搜索標簽。之前搜索標簽或地點時,必須要在不同類型的結果中進行選擇,而現在有了更簡單的替代方案——我們建立了一個排序框架,能夠預測正在搜索的用戶希望查到的結果類型。在測試時,我們發現將帳號與標簽融合可將標簽的點擊率提升20%以上,同時并未對帳號搜索性能有太大影響。
在用戶使用Instagram時,我們的分類器也對搜索日志進行了個性化,并啟用了機器學習功能。查詢日志按照國家來匯總,以確定針對給定搜索詞(如“#tbt”)的搜索更有可能是標簽搜索還是帳號搜索,再結合其他信息,比如給定用戶過去的搜索記錄,以及可展示的搜索結果質量,創建出搜索結果的最終混合列表。
媒體搜索
Instagram的搜索架構常用來加強與用戶輸入差距較大的搜索,而Instagram最大的垂直搜索便是媒體搜索,它包含了數以億計的日志,每個都收獲數萬億的點贊。與其他層面不同,媒體搜索是純粹的基礎架構,用戶從不在應用上輸入明確對媒體的搜索,我們使用它來加強其它顯示媒體的功能,如:瀏覽、標簽、地點以及最新推出的編輯集群(editorial cluster)。
候選集生成
由于沒有明確的查詢需求,我們在媒體反向索引關鍵詞上發揮了創造力,對關鍵字做了不同的切分。下面的表格列出了目前媒體索引所支持的一些索引詞類型:
在各個日志列表中,媒體按照時間逆序排列(靜態排名),將更近的搜索結果顯示在最上面。舉個例子,通過單一查詢(term owner: 181861901),我們便能查找到 @thomas 的個人主頁。擴展到標簽上,搜索(term 標簽: #hyperlapse),我們就能找到帶有#hyperlapse標簽的最新媒體。Unicorn還允許用戶發送(標簽:#hyperlapse,owner:181861901)找到用戶@thomas所發布的、帶有#Hyperlapses標簽的日志。
許多索引詞的存在就是為了鼓勵搜索結果多樣化,比如,我們可能對此感興趣:確保一些帶有#hyperlapse標簽的候選日志是來自認證賬號的。那么通過Unicorn的WEAK AND運算符,可以確保至少有30%的候選日志來自認證賬號:
wand (term hashtag:#hyperlapse) (term verified:1 :optional-weight 0.3))我們探索多樣性,以便在標簽與位置的“頂端”部分提供更符合的內容。
功能
盡管日志是按照時間順序來排列的,我們一般想要的是指定查詢(標簽、位置等)的熱門媒體。在生成候選集之后,我們會執行排名進程,通過對每份文檔進行評分來選出最佳媒體。評分功能包含一系列功能,最終輸出的分數代表與查詢指定文檔擬合度最高的結果。
-
視覺: 查看圖片本身可視內容的功能。具體來講,在嘗試對圖片內容分類時,Instagram會使用深層神經網絡(DNN)圖像分類器,然后采用人臉識別技術來確定圖片中人臉的數目與尺寸大小。
-
日志元數據: 查看指定日志非視覺內容的功能。Instagram的許多日志都包含標題、地理位置標記、標簽以及/或者提示信息,有助于確認搜索的相關性。比如FEATURE_IG_MEDIA_IS_LOCATION_TAGGED就是確定某個日志是否包含地理位置標記的標識功能。
-
發布者: 查看特定日志發布者的功能。某個日志的一些最為豐富的信息都是由發布者確定的,比如通過FEATURE_IG_MEDIA_AUTHOR_VERIFIED就可以鑒定該日志的發布者是否是認證用戶。
我們索引中的功能可以被大致分為三類,根據使用情況不同,其權重也不盡相同。在位置頁面的“頂端”部分,我們可能想要分辨這些圖片是該地理位置的照片,還是其附近的照片,并將包含大量面孔的照片排在后面。Instagram還使用per-query-type排序模型,針對特定的應用頁面對合適的選擇進行建模。
案例研究:發現
Instagram的媒體搜索架構還拓展出了發現功能,為那些沒有明確搜索目標的用戶推送有趣的內容。Instagram的瀏覽日志功能可以通過社交圖譜,為用戶推送附近的人感興趣的內容。具體來說,發現的來源就是“你點贊的圖片的作者,他所喜歡的照片”,我們可以在單個unicorn查詢中將此功能編碼:
(apply liker:(extract owner: liker:<userid>))這就是一個由內及外的過程:
- liker::你曾點贊的日志
- (extract owner:…):這些日志的發布者
- (apply liker:..):他們點贊的媒體
這一查詢的候選結果生成之后,我們就能利用現有的排序架構為用戶推送熱門日志。與帶有標簽及地理位置標記的熱門日志不同,發現功能的評分函數是通過機器學習演化的,而不是人工手動調整的。
總結
以上是生活随笔為你收集整理的简析Instgram的搜索架构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Google I/O大会,炫酷产品汇总
- 下一篇: H264 数据avi文件封装和拆解