搜索工程搭建
文章目錄
- 搜索工程的三大模塊
- 1. 數(shù)據(jù)工程
- 1. 全量同步的實現(xiàn)
- 2. 增量同步實現(xiàn)
- 2. 檢索端
??做了三年多的搜索相關的工程建設,從現(xiàn)在網(wǎng)上能夠看到的資料來說,搜索工程這一塊兒的資料還是相對較少,有的資料也都是比較的泛化,很難依據(jù)之進行一個初步的搜索工程的建設。這里結合自己的工作經(jīng)驗嘗試對垂直類搜索工程做一些介紹,方便沒有做過搜索工程的同學來了解搜索工程的概貌。
??所謂垂直類的搜索,一般是指站內搜索,一般不涉及從站外爬取數(shù)據(jù),比如你在淘寶里面搜索,搜的都是淘寶里面的東西,想搜索門戶,百度,google則是屬于大搜,要聚合網(wǎng)絡平臺的數(shù)據(jù)來進行搜索,他們的數(shù)據(jù)源需要通過爬蟲從各個網(wǎng)站爬取才能夠得到。
搜索工程的三大模塊
在搜索工程中,主要有三個部分,搜索引擎,檢索服務,數(shù)據(jù)工程。
整個系統(tǒng)的架構大概是這個樣子,針對不同的數(shù)據(jù)情況可能又會有一些優(yōu)化。
1. 數(shù)據(jù)工程
??首先聊一下數(shù)據(jù)工程,搜索使用的數(shù)據(jù)是存儲在es當中的,因為es屬于文檔型數(shù)據(jù)庫,而且搜索大部分是按照主題進行搜索,比如搜用戶,搜帖子,搜評論等在實現(xiàn)中是有多個索引,對不同的索引進行搜索。
??每一個索引包含的數(shù)據(jù)有哪些呢?一般情況下存儲在搜索引擎當中的數(shù)據(jù)都是搜索或者排序的時候需要使用的數(shù)據(jù)。這里展開說一下,現(xiàn)在高級一些的系統(tǒng),把召回和排序分開來做,召回一般是通過es來進行文本命中,排序的話則是通過模型來進行排序,來讓排序達到更好的效果。如果開發(fā)人力資源不夠的話可能es會承擔召回和排序的兩部分的功能。
??在es中一般存儲的有這樣三類數(shù)據(jù),我們可以拿用戶索引來進行舉例:
??這些數(shù)據(jù)在數(shù)據(jù)庫中可能散落在多個庫和表中,那么就需要將這些數(shù)據(jù)形成一個個以user_id為標識的文檔,索引入es當中。這就需要一個單獨的項目來對數(shù)據(jù)進行組裝了,比如同庫的可以使用join查詢,不同庫的可以在程序里面進行組裝。
??一般情況下,數(shù)據(jù)的同步還需要滿足兩個需求,一個是全量的同步,一個是增量的同步。
1. 全量同步的實現(xiàn)
??一般是直接掃表,比如從mysql中讀取數(shù)據(jù),可以使用多線程的方式來加快速度(mysql如果直接使用limit進行翻頁的話也會有很大的性能問題,一定要增加過濾項)。
??還有一點需要強調的是,在生產(chǎn)環(huán)境中一般都是使用alias對索引進行操作,比如user相關的查詢,使用的別名是user,但是實際指向的索引是user_one, 然后在全量的時候直接新建一個user_two,等user_two創(chuàng)建完成后,直接把alias切換到user_two上面
2. 增量同步實現(xiàn)
??使用binlog來實現(xiàn),這一塊兒為了達到實時性,一般都是通過mysql,mongo的binlog,oplog來作為觸發(fā)事件來進行索引的增量更新。架構實現(xiàn)一般是mysql的binlog通過canal發(fā)送到kafka,mongo的oplog通過mongo-shake發(fā)送到kafka,然后java應用通過消費kafka的數(shù)據(jù),解析binlog的數(shù)據(jù),然后再從mysql中查出doc的整個數(shù)據(jù)index到es當中。
增量的時候有時候可能會出現(xiàn)寫放大的情況,只能增加寫入速度,比如采用批處理,采用多線程等。
同時,還會有這樣一個問題,我們在做全量同步的時候一直也會有增量的數(shù)據(jù)產(chǎn)生,那么我們如何控制在做全量的時候產(chǎn)生的新的增量也能夠進入到新的索引中呢。有兩種實現(xiàn)方式
第一種是增量的話只根據(jù)別名寫索引,在全量新建的時候增量的數(shù)據(jù)不會進去,這個時候在全量結束的時候根據(jù)全量開始的時間節(jié)點去kafka中回放對應的數(shù)據(jù),回放完成后進行索引別名的切換。這種其實在索引別名切換之前可能也會有少許的數(shù)據(jù)誤差,因為這個回放的完成很難定義,數(shù)據(jù)還是在源源不斷的產(chǎn)生。
第二種比較好的方式則是,在全量開始的時候,增量使用雙寫的方式,這樣的話,在增量寫入沒有大的延遲的情況下,數(shù)據(jù)的一致性還是比較ok的
2. 檢索端
搜索端使用的話,主要通過es檢索出來一定排序的文檔,然后根據(jù)其中的user_id去請求完整的用戶信息,組裝后返回給client端。
這里比較重要的一塊兒是設計mapping,主要是text類型的字段的設計,舉例用戶的昵稱字段
一般會使用四種分詞設計(結合es的fields功能)
1.使用ik中文分詞(實際上用戶名使用中文分詞意義一般不大,可能用戶描述更合適)
2.使用拼音分詞,做拼音匹配
3.使用standard分詞,主要是為了打散,比如使用的單字檢索也能檢索出來結果,為了能夠提升召回率吧
4.keyword不分詞,做完全匹配
類似下面這種
"analysis" : {"analyzer" : {"pinyin_analyzer" : {"tokenizer" : "_pinyin"}},"tokenizer" : {"_pinyin" : {"keep_joined_full_pinyin" : "true","lowercase" : "true","keep_original" : "true","remove_duplicated_term" : "true","keep_separate_first_letter" : "false","type" : "pinyin","limit_first_letter_length" : "16","keep_full_pinyin" : "true"}}}"name" : {"type" : "text","analyzer" : "ik_max_word","fields" : {"keyword" : {"type" : "keyword"},"pinyin" : {"type" : "text","analyzer" : "pinyin_analyzer"},"single" : {"type" : "text","analyzer" : "standard" }}}總結
- 上一篇: 系统设计
- 下一篇: golang学习笔记01