看Lucene原始碼必須知道的基本規則和演算法

程式設計一生發表於2017-04-09

  上中學的時候寫作文,最喜歡的季節我都是寫冬天。雖然是因為寫冬天的人比較少,那時確實也是對其他季節沒有什麼特殊的偏好,反而一到冬天,自己皮膚會變得特別白。但是冬天啊,看到的只有四季常青盆栽:瓜慄(就是發財樹,好吧,算我矯情,反正我不喜歡這個名字),綠蘿,永遠看不到它開花的巴西鐵,富貴竹,散尾葵……過年的時候家裡的杜鵑就開花了,零星的幾朵小花兒更突顯了這個季節的淒涼。紅掌,蝴蝶蘭總是美美的在那裡,開不敗卻看不到生機。插到水裡的勿忘我,洋桔梗,看到他們也只會聯想到過幾天他們會枯萎的命運。春天來了,先是迎春花,然後是桃花,玉蘭。到了四月,紅葉碧桃,紫荊,櫻花,紫葉李,垂絲海棠……最喜歡丁香花的味道~~再過幾日,鬱金香和牡丹也該開了。桃之夭夭,灼灼其華。果然,陽光下這些花兒是流光溢彩的。人生的悲哀不是短暫的快樂過後無盡的痛苦,而是從來沒讓自己快樂過。想想小鮮肉看的《熊出沒-雪嶺熊風》電影,熊二沒有再次遇到糰子之前的魂兒不守舍,與糰子經歷過精彩之後,雖然別人什麼都不記得了,所有的場景回到了最初,熊二心裡卻是滿足和平靜。就像這些花兒,雖然是花開不多時,但怒放過的青春總好過冬青一日和一生毫無區別(中學作文裡還總是在讚揚它冬天還是綠的呢[此處有表情])。大概現在和中學的時候最大的區別,就是那時候的人生觀更多的是受父母的影響。父母都是醫生,鐵飯碗,穩定是一成不變的追求。離父母越來越遠,活得越來越像自己,才發現自己的人生需要冬天的期待與思考,春天花的妖嬈,夏天葉的茂盛,秋天果實的沉重。誰規定的第一個季節是春天?我的人生第一個季節就不是

  下面介紹一些Lucene使用基本規則和演算法。這些規則和演算法的選擇,都和Lucene和支援TB級的倒排索引有關。

  字首字尾規則(Prefix+Suffix):在Lucene的反向索引中,要儲存詞典的資訊,所有的詞再詞典中是按照字典順序進行排列的,然後詞典中包含了文件中的幾乎所有的詞,並且有的詞還是很長的,這樣索引檔案會非常的大,所謂字首字尾規則,就是某個詞和前一個詞有共同的字首的時候,後面的詞僅僅儲存字首在詞中的偏移(offset),和剩下的部分(字尾)。

  比如:北京天安門  這個詞詞典裡通常都會包含北京  天安門  北京天安門  這三個詞。北京和北京天安門由於字首相同,在字典表裡會相鄰儲存,兩個詞存成  北京2天安門   ,這樣存比北京北京天安門   省空間。

  差值規則(Delta):在lucene的反向索引中,需要儲存很多整形數字的資訊,比如文件ID號,比如詞在文件中的位置等等。整形數字是以可變長整型的格式儲存的。隨著數值的增大,每個數字佔用的位元位增多。所謂差值規則就是先後儲存兩個整數的時候,後面的整數僅僅儲存和前面整數的差即可。多嘮叨兩句:因為看到有的哥哥們定義資料庫欄位的時候總是想都不想就用varchar,MD5的結果也用varchar[汗]。MD5的結果長度是固定的,沒有必要用varchar來節省空間。定長的char效率會高些。

  LZ4演算法(Realtime Compression Algorithm):在作業系統(linux/freeBSD),檔案系統(OpenZFS),大資料(Hadoop),搜尋引擎(Lucene/solr),資料庫(Hbase)等中都可以看到它的身影,很通用。壓縮/解壓速度快。

  跳躍表規則(Skip list):跳躍表是一種資料結構。額~~,要不能用幾句話把它介紹明白,真不好意思說自己有那麼多演算法專利。首先使用跳躍表的前提是因為搜尋引擎的索引資料是高度有序的。打個比方:我從北京回老家青州市可以做北京南到青島的動車或者高鐵。它們的路線是一樣的,後者貴100塊錢。貴在哪裡呢?後者停的站少,就是跳站了。有的高鐵到青州市不停。我只能在前一站淄博或者後一站濰坊下車,然後坐慢車去青州市。跳躍表就是這個原理。所有的搜尋資料存在一個連結串列裡,這就是慢車(最傳統的綠皮車)。然後新加一個連結串列,存的資料中間有間隔(K字頭車)。這時候我不得不說一個原則:所有原來的時間複雜度是delta(找這個符號比較費勁,我就直接用英文了,記住它是很有好處的,去米國總免不了和這個航空公司打交道~~) n的演算法,期待的終極優化後的結果基本都是 delta  log n。所以只有兩層的話,時間複雜度是達不到要求的。怎樣達到要求呢?最終要形成一棵樹。怎麼形成一棵樹呢?加層唄。加大跳站的間隔,T字頭車,D字頭車,G字頭車。一直到中間是所有的站,形成了一個root。樹形結構就形成了。時間複雜度變成了delta log n[耶][耶] Lucene3.0之前很多地方使用這種資料結構來提高查詢速度。但是因為它對模糊查詢的支援不太好,現在Lucene改用FST了。

  關於delta再多嘮叨兩句:它是希臘語的第四個字母,大寫是△。我這麼懶,不願意去拷貝一個小寫字母到這裡,大寫字母打出來也是因為我直接改用日語輸入法,打個[三角形]出來的~~。上面提到差值規則和時間複雜度都用到了delta。因為在數學或者物理中大寫的Δ用來表示增量符號。而小寫通常在高等數學中用於表示變數或者符號。所以差值規則裡用到了它大寫的含義,時間複雜度裡用到了它小寫的含義。

  有限自動機演算法(FST,Finite State Transducer):通過輸入有序字串構建最小有向無環圖。通過共享字首來節省空間,記憶體存放字首索引,磁碟存放字尾詞塊。Lucene的原始碼中可以看到它的具體實現。

  Lucene之所以有那麼頻繁的版本升級,我以前還專門追劇似的關心這個升級,是因為這裡面有一個問題的發生與解決的過程,舉個簡單的例子:在Windows系統中一個資料夾只能存放2W多個檔案,在1W多個檔案以後寫入速度會急劇下降,Lucene這樣處理TB級資料的系統更要考慮資料量和效能的關係和權衡。

  有限自動機是Lucene的核心查詢演算法,理解需要一定的時間。下面介紹Lucene的打分相關規則,這部分很容易理解。

  文件權重(Document boost):在索引時給某個文件設定的權重值。

  域權重(Field boost):在查詢的時候給某個域設定的權重值。

  調整因子(Coord):基於文件中包含查詢關鍵詞個數計算出來的調整因子。一般而言,如果一個文件中相比其它的文件出現了更多的查詢關鍵詞,那麼其值越大。

  逆文件頻率(Inerse document frequency):基於Term的一個因子,存在的意義是告訴打分公式一個詞的稀有程度。其值越低,詞越稀有(這裡的值是指單純的頻率,即多少個文件中出現了該詞;而非指Lucene中idf的計算公式)。打分公式利用這個因子提升包含稀有詞文件的權重。

  長度歸一化(Length norm):基於域的一個歸一化因子。其值由給定域中Term的個數決定(在索引文件的時候已經計算出來了,並且儲存到了索引中)。域越的文字越長,因子的權重越低。這表明Lucene打分公式偏向於域包含Term少的文件。

  詞頻(Term frequency):基於Term的一個因子。用來描述給定Term在一個文件中出現的次數,詞頻越大,文件的得分越大。

  查詢歸一化因子(Query norm):基於查詢語句的歸一化因子。其值為查詢語句中每一個查詢詞權重的平方和。查詢歸一化因子使得比較不同查詢語句的得分變得可行,當然比較不同查詢語句得分並不總是那麼易於實現和可行的。

  如需轉載,請註上我的原文連結: http://www.cnblogs.com/xiexj/p/6683439.html  謝謝哦~~

相關文章