基本概念
Elasticsearch是一個(gè)分布式全文檢索系統(tǒng)。很多人說(shuō)到它的特點(diǎn):查詢快,高吞吐量,可擴(kuò)展。我們首先來(lái)看看它的底層數(shù)據(jù)結(jié)構(gòu)。
底層數(shù)據(jù)
倒排索引(reverted index)
Elasticsearch依賴lucene來(lái)存儲(chǔ)和索引數(shù)據(jù)。我們首先來(lái)看看它是如何處理數(shù)據(jù)。
用例:
- Winter is coming
- Ours is the fory
- The choice is yours
我們有上面三句話。現(xiàn)在,我們要查詢那句話包含了comming。
方案一:傳統(tǒng)數(shù)據(jù)庫(kù)
有一個(gè)表t_content, 字段:id, content。所以我們查詢的方式是: select * from t_content where content like '%coming%'
因?yàn)閏ontent是一大段內(nèi)容,我們是不能為其建立有效索引的。數(shù)據(jù)庫(kù)查詢,會(huì)將該表所有的行都掃描一把,拿其中的content與查詢關(guān)鍵字來(lái)比較,這就是所謂的全表掃描。可以看到,這樣的效率是非常的低效的。方案二: Elasticsearch保存
我們建立一個(gè)content的index, fields: id, content(text 類型)。當(dāng)我們保存數(shù)據(jù)的時(shí)候,Elasticsearch首先會(huì)對(duì)content的內(nèi)容進(jìn)行詞的拆分,最終建立content的索引, 這就是思維的倒排索引(reverted index)。
Term | Freq | Document |
---|---|---|
choice | 1 | 3 |
coming | 1 | 1 |
fury | 1 | 2 |
is | 3 | 1, 2, 3 |
ours | 1 | 2 |
the | 2 | 2, 3 |
winter | 1 | 7 |
yours | 1 | 3 |
如上圖,我們可以看到lucene已經(jīng)將content的內(nèi)容拆分為詞(term), 并統(tǒng)計(jì)它的使用的個(gè)數(shù),在哪些document存在。
所以,當(dāng)我們查詢那句話包含了coming的時(shí)候,lucene首先在dictionary找到coming這個(gè)詞,然后找到使用了它的document。(注: term dictionary)
總結(jié):我們可以看到這兩種查詢方案,總結(jié)為兩種不同的提問(wèn)方式。
- 哪些文檔包含了coming呢?遍歷文檔,看看每個(gè)文檔是否包含了coming。
- coming在哪些文檔中? 事先為coming在哪些文檔中建立索引,查找時(shí)候先找到coming對(duì)應(yīng)的索引,再拿出對(duì)應(yīng)的文檔。
Lucene基本概念
Term and Term dictionary: Term是Lucene中的最小的index單元,在某些內(nèi)容的詞法分析中產(chǎn)生(Analyzer/tokenizer)。Term dictionary是用來(lái)查詢term的數(shù)據(jù)結(jié)構(gòu)。
Field: 一個(gè)document可能包含許多fields。列如:一個(gè)BLOG可能包括author, title, content, publish date。Lucene為不同的field提供了不同的類型, 比如:keyword, text, long, date等。
-
Segment:Lucene的索引是由一系列的segments組成。每個(gè)segment是獨(dú)立的且可以搜索。當(dāng)創(chuàng)建index的時(shí)候:
- 為新的document創(chuàng)建新的索引
- 合并老的segment.
查詢的時(shí)候可能會(huì)涉及到多個(gè)segments.
Document:類似數(shù)據(jù)庫(kù)表的一行。
Index:類似數(shù)據(jù)庫(kù)表。
特點(diǎn):
- Lucene在內(nèi)存中建立索引,然后歸集到segment, 寫(xiě)到磁盤(pán)
- segment是不可更改的,打一個(gè)刪除的標(biāo)記來(lái)刪除
- segment使用一定的機(jī)制來(lái)定期merge
- 查詢與搜索是基于segment
數(shù)據(jù)結(jié)構(gòu)
-
B+ 樹(shù)
B+.png -
Skip list
skiplist.png -
FST(Finite State Transducer)
- FST壓縮率一般在3倍~20倍之間
- O(len(str))的查詢時(shí)間復(fù)雜度
- Build FST
TF-IDF 關(guān)鍵詞權(quán)重的度量
-
TF 詞頻
我們來(lái)看一個(gè)短語(yǔ):美麗的燕子。它可以分為三個(gè)關(guān)鍵字:美麗,的,燕子。假如在兩篇文章中,第一篇文章中出現(xiàn)的次數(shù)是5, 100, 5;在第二篇文章中出現(xiàn)的次數(shù)是8,100,5。我們可以認(rèn)為搜索這個(gè)“美麗的燕子”時(shí),第二篇的相關(guān)度比第一篇高。但是這里有個(gè)漏洞,假如第一篇文章的總字?jǐn)?shù)為200,而第二篇的總字?jǐn)?shù)為2000,明顯文章長(zhǎng)的占道便宜。
TF(詞頻) = 關(guān)鍵字次數(shù)/總字?jǐn)?shù)
所以第一篇文章的詞頻分別為:0.025, 0.5, 0.025
第二篇的詞頻分別為:0.004, 0.05, 0.0025有個(gè)簡(jiǎn)單的辦法,就是直接使用關(guān)鍵字在文章中出現(xiàn)的總詞頻。對(duì)“美麗的燕子”,在第一篇總詞頻為:0.025 + 0.5 + 0.025 = 0.55, 在第二篇出現(xiàn)的總詞頻是:0.004 + 0.05 + 0.005 = 0.0475。
這里有個(gè)漏洞是:“的”,這個(gè)實(shí)際上是對(duì)相關(guān)性的區(qū)分是沒(méi)有任何用處的,在實(shí)際的度量性中Lucene也不會(huì)進(jìn)行處理。
-
IDF(Inversted Document Frequent) 逆分檔詞頻
對(duì)“美麗的燕子”搜索,很明顯“燕子”的關(guān)鍵性要大于“美麗”。“美麗”這個(gè)詞太普遍了,可用于很多的地方。所以識(shí)別分類的時(shí)候,“燕子”的識(shí)別性更高。
很容易發(fā)現(xiàn),一個(gè)詞在很少的文章中出現(xiàn),那么它的分類型更強(qiáng),可識(shí)別性更高,權(quán)重更大。相反,這個(gè)詞在大多數(shù)的文章中存在,那么它的識(shí)別性更低,權(quán)重反而更小。IDF (逆文檔詞頻) = log(D/Dw) D為出現(xiàn)的全部文檔個(gè)數(shù),Dw為改關(guān)鍵在在所有文檔出現(xiàn)的次數(shù)。
綜上所述,TD-IDF = TF(詞頻) * IDF(逆文檔詞頻)