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