資料二三事 搜尋

資料二三事 搜尋

提到搜尋,我們先講一個和搜尋相類似的名詞“查詢”。當然在不同領域內,他們的定義不盡相同,在我們的業務領域他們有什麼區別呢,我們來想一下我們整個業務的發展,資訊化建設一開始主要提供的是查詢的服務。在沒有資訊整合的時期,我們實現的是對單類資訊的查詢,而且在查詢時我們也是明確資料項的。大家最常見的是系統介面會有多個表單,比如你要查的是人口資訊,那麼有姓名的表單,性別的表單、民族的表單,你提供查詢請求後,系統會按照系統介面中的對應關係去後臺數據庫中去查詢相應的結果,在這裡查詢後端的資料庫大多也是關係型資料庫。大家知道關係型資料庫儲存的是結構化資料,所以我大致理解查詢就是基於結構化資料的查詢。而且大多數查詢是知道查詢項的,比如查“張三”,一般明確的就是查姓名這個資料項。

在這裡提一下“索引”這個術語,索引在一般場景裡指將書刊中的內容分類摘錄,表明頁數,按一定次序排列的一種工具。而在資料庫場景中索引是一種單獨的、物理的對資料庫中一列或多列的值進行排序的一種儲存結構。舉例來說,書刊的例子如字典裡的按漢字筆畫查字這個工具,它就是筆畫索引。我們數出“二”這個字有兩筆,然後就可以去筆畫索引那裡去找兩筆的字,然後找到“二”後就可以找到“二”所在的字典頁碼了。

資料二三事 搜尋

同樣的在資料庫中索引實現的原理也是一樣的。比如我們有年齡這麼一個欄位,我們就可以按照年齡大小進行排序,然後構造年齡這個欄位的索引。當我們查詢一個年齡為45歲的人時,資料庫會先去查年齡的索引,然後找到45歲所對應的的資料位置。可以看出索引的引入會大大加快資料查詢的速度,如果沒有索引,原則上你查一個年齡為45歲的人,後臺資料庫會進行全表掃描,逐條匹配,這樣的話不僅速度慢而且浪費了大量的資料庫效能。

簡單加上索引的關係資料庫查詢在業務前期滿足了我們基本的資訊查詢需求,但隨著業務的發展、資料的融合、需求的深入,只是簡單的查詢已經遠遠不能滿足我們的實戰需求,比如我們要查“張某三”、或者我們不確定“張三”就是姓名還是別的什麼資訊,更有甚者,我們想查“張三盜竊”這事有沒有。

這些需求我們原有的關係資料庫查詢就很難響應了,儘管可以做相關的改造和適配,但代價太大。其實在這裡我們的需求就不僅僅是查詢了,而是搜尋的需求。我認為搜尋與查詢最大的區別就是查詢非結構化資料的能力,搜尋是能對非結構化資料進行處理的,就例如搜尋“張三盜竊”這個資訊。

這種能夠對非結構化資料(主要是文字資料)進行搜尋的技術業界叫做全文檢索、全文檢索可以實現對非結構化資料的全文檢索功能。目前市面的百度、谷歌也是採用的這種技術。那麼全文檢索是怎麼實現這樣的功能的呢?

還是引入一個術語“倒排索引”,為啥叫倒排索引?倒排索引和我們上文所提到的關係資料庫中的索引是不同的,因為它索引的方式和普通索引相比是轉置的,所以叫倒排索引。

還是舉例說明吧,不知道大家玩沒玩過詩詞的“飛花令”,也就是前段時間大火的中國詩詞大會節目的一個專案。

資料二三事 搜尋

比如出一個字“前”,讓你背出所有帶“前”的詩句。這個其實有些難度,即使你會背很多詩詞,很多詩詞裡面有“前”這個詞,但你一時卻很難想起。這是為什麼呢,原因就在於你的大腦中沒有建立“倒排索引”。你大腦中建立的都是正向的索引,比如我提示你說“靜夜思,李白”,你立即就能說出來“床前明月光”了。你的大腦中存有這個詩句,它的記憶方式如下圖:

資料二三事 搜尋

可以看出,這是一個正向的索引,也就是從文件到細化的資訊,但你正向的索引是無法完成“飛花令”這個任務的。

那麼倒排索引是怎樣的呢,倒排索引就是拿細化的資訊去索引整個文件,在這裡就是拿具體的字詞去索引詩句了,也就是如下圖:

資料二三事 搜尋

這樣的話我們就能輕鬆的由“前”這個索引找到對應的詩句了。

我們可以繼續維護這個索引,比如“日照香爐生紫煙,遙看瀑布掛前川”裡面就有“前”字,我們就把這個詩句也加到這個索引上去。這樣的詩句會越來越多,我們就建立了一個從文件中字詞“前”到整個文件《靜夜思》、《望廬山瀑布》的索引,這就叫倒排索引,好理解了吧。

當然如果你想揹帶有“月”字的詩句,那麼也要建立“月”字的倒排索引。在往上,如果你想揹帶有“明月”的詩句,那麼建立“明月”的倒排索引。這裡就有個問題,怎麼建立“明月”這個索引呢,我們知道“明月”是個有意義的詞語,所以我們得把“明月”看做一個整體,把“明月”從原詩句中提取出來,那麼我們就需要對原來的文件做分詞處理。

分詞就是將連續的字序列按照一定的規範重新組合成詞序列的過程。我們知道,在英文的行文中,單詞之間是以空格作為自然分界符的,而中文只是字、句和段能透過明顯的分界符來簡單劃界,唯獨詞沒有一個形式上的分界符,雖然英文也同樣存在短語的劃分問題,不過在詞這一層上,中文比之英文要複雜得多、困難得多。分詞細研究下去知識很多在這裡不談。

我們繼續。

如果要求背既帶“前”字又帶“月”字的詩句呢。如果我們分別建立了“前”字和“月”字的倒排索引,

資料二三事 搜尋

資料二三事 搜尋

從圖中看,“前”字索引到了三個文件詩句,“月”字也索引到了三個文件詩句。如果我們要背既帶“前”字又帶“月”字的詩句,那麼只需要將上面的值做一下交集,就能找出來“床前明月光”這句詩了。

到這裡基本的原理就可以用“飛花令”簡單的描述清楚了。我們回過來看我們的業務需求,像搜尋“張三”,我們就可以將後臺資料項都進行倒排索引,這樣當前臺輸入“張三”時,後臺進行索引匹配,不管索引到那條資料的那個欄位,都可以給你搜索出來,哪怕是一段案情描述中出現了“張三”這個詞。

再如搜尋“張三盜竊”,前端在收到“張三盜竊”這個搜尋詞後,會先進行分詞操作,也就是把“張三盜竊”分成“張三”和“盜竊”兩個詞,然後分別去倒排索引中去尋找對應的資料。然後把“張三”匹配到的所有資料記錄和“盜竊”匹配到的資料記錄做交集,最終找到包含“張三盜竊”資訊的資料。當然在這裡,“張三盜竊”可以是不連續的詞語。這樣就牽扯到匹配精確度的問題,比如“張三”和“盜竊”兩詞挨在一起的我們認為匹配最精確,“張三”和“盜竊”兩詞不挨在一起的稍弱一些,這些我們都可以設定。所以我們能看出,處理非結構化資料的全文檢索(搜尋)的結果也和結構化資料的查詢是不一樣,搜尋的結果是精確度匹配,是按照資料對請求匹配程度來響應的,而查詢一般就是精確匹配,是就是,不是就是不是。

現在流行的提供全文檢索能力的工具有elasticsearch,它提供了倒排索引、分詞等等的能力,現在許多的搜尋類系統都在採用elasticsearch。有機會再跟大家詳細聊一聊elasticsearch,但現在還沒怎麼學習。

資料二三事 搜尋