<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    huangfox

    韜光隱晦
    隨筆 - 1, 文章 - 8, 評論 - 1, 引用 - 0
    數據加載中……

    有關Lucene的問題(7):用Lucene構建實時的索引【轉】

      由于前一章所述的Lucene的事務性,使得Lucene可以增量的添加一個段,我們知道,倒排索引是有一定的格式的,而這個格式一旦寫入是非常難以改變 的,那么如何能夠增量建索引呢?Lucene使用段這個概念解決了這個問題,對于每個已經生成的段,其倒排索引結構不會再改變,而增量添加的文檔添加到新 的段中,段之間在一定的時刻進行合并,從而形成新的倒排索引結構。

      然而也正因為Lucene的事務性,使得Lucene的索引不夠實時,如果想Lucene實時,則必須新添加的文檔后IndexWriter需要 commit,在搜索的時候IndexReader需要重新的打開,然而當索引在硬盤上的時候,尤其是索引非常大的時候,IndexWriter的 commit操作和IndexReader的open操作都是非常慢的,根本達不到實時性的需要。

      好在Lucene提供了RAMDirectory,也即內存中的索引,能夠很快的commit和open,然而又存在如果索引很大,內存中不能夠放下的問題。

      所以要構建實時的索引,就需要內存中的索引RAMDirectory和硬盤上的索引FSDirectory相互配合來解決問題。

      1、初始化階段

      首先假設我們硬盤上已經有一個索引FileSystemIndex,由于IndexReader打開此索引非常的慢,因而其是需要事先打開的,并且不會時常的重新打開。

      我們在內存中有一個索引MemoryIndex,新來的文檔全部索引到內存索引中,并且是索引完IndexWriter就commit,IndexReader就重新打開,這兩個操作時非常快的。

      如下圖,則此時新索引的文檔全部能被用戶看到,達到實時的目的。

      有關Lucene的問題(7):用Lucene構建實時的索引

      2、合并索引階段

      然而經過一段時間,內存中的索引會比較大了,如果不合并到硬盤上,則可能造成內存不夠用,則需要進行合并的過程。

      當然在合并的過程中,我們依然想讓我們的搜索是實時的,這是就需要一個過渡的索引,我們稱為MergingIndex。

      一旦內存索引達到一定的程度,則我們重新建立一個空的內存索引,用于合并階段索引新的文檔,然后將原來的內存索引稱為合并中索引,并啟動一個后臺線程進行合并的操作。

      在合并的過程中,如果有查詢過來,則需要三個IndexReader,一個是內存索引的IndexReader打開,這個過程是很快的,一個是合并中索引 的 IndexReader打開,這個過程也是很快的,一個是已經打開的硬盤索引的IndexReader,無需重新打開。這三個IndexReader可以 覆蓋所有的文檔,唯一有可能重復的是,硬盤索引中已經有一些從合并中索引合并過去的文檔了,然而不用擔心,根據Lucene的事務性,在硬盤索引的 IndexReader沒有重新打開的情況下,背后的合并操作它是看不到的,因而這三個IndexReader所看到的文檔應該是既不少也不多。合并使用 IndexWriter(硬盤索引).addIndexes(IndexReader(合并中索引)),合并結束后Commit。

      如下圖:

      有關Lucene的問題(7):用Lucene構建實時的索引

      查看原圖(大圖)

      3、重新打開硬盤索引的IndexReader

      當合并結束后,是應該重新打開硬盤索引的時候了,然而這是一個可能比較慢的過程,在此過程中,我們仍然想保持實時性,因而在此過程中,合并中的索引不能丟 棄,硬盤索引的IndexReader也不要動,而是為硬盤索引打開一個臨時的IndexReader,在打開的過程中,如果有搜索進來,返回的仍然是上 述的三個IndexReader,仍能夠不多不少的看到所有的文檔,而將要打開的臨時的IndexReader將能看到合并中索引和原來的硬盤索引所有的 文檔,此IndexReader并不返回給客戶。如下圖:

      有關Lucene的問題(7):用Lucene構建實時的索引

      查看原圖(大圖)

      4、替代IndexReader

      當臨時的IndexReader被打開的時候,其看到的是合并中索引的IndexReader和硬盤索引原來的IndexReader之和,下面要做的是:

      (1) 關閉合并中索引的IndexReader

      (2) 拋棄合并中索引

      (3) 用臨時的IndexReader替換硬盤索引原來的IndexReader

      (4) 關閉硬盤索引原來的IndexReader。

      上面說的這幾個操作必須是原子性的,如果做了(2)但沒有做(3),如果來一個搜索,則將少看到一部分數據,如果做了(3)沒有做(2)則,多看到一部分數據。

      所以在進行上述四步操作的時候,需要加一個鎖,如果這個時候有搜索進來的時候,或者在完全沒有做的時候得到所有的IndexReader,或者在完全做好 的時候得到所有的IndexReader,這時此搜索可能被block,但是沒有關系,這四步是非常快的,絲毫不影響替代性。

      如下圖:

      有關Lucene的問題(7):用Lucene構建實時的索引

      查看原圖(大圖)

      經過這幾個過程,又達到了第一步的狀態,則進行下一個合并的過程。

      5、多個索引

      有一點需要注意的是,在上述的合并過程中,新添加的文檔是始終添加到內存索引中的,如果存在如下的情況,索引速度實在太快,在合并過程沒有完成的時候,內 存索引又滿了,或者硬盤上的索引實在太大,合并和重新打開要花費太長的時間,使得內存索引以及滿的情況下,還沒有合并完成。

      為了處理這種情況,我們可以擁有多個合并中的索引,多個硬盤上的索引,如下圖:

      有關Lucene的問題(7):用Lucene構建實時的索引

      查看原圖(大圖)

      新添加的文檔永遠是進入內存索引

      當內存索引到達一定的大小的時候,將其加入合并中索引鏈表

      有一個后臺線程,每隔一定的時刻,將合并中索引寫入一個新的硬盤索引中取。這樣可以避免由于硬盤索引過大而合并較慢的情況。硬盤索引的 IndexReader也是寫完并重新打開后才替換合并中索引的IndexReader,新的硬盤索引也可保證打開的過程不會花費太長時間。

      這樣會造成硬盤索引很多,所以,每隔一定的時刻,將硬盤索引合并成一個大的索引。也是合并完成后方才替換IndexReader

      大家可能會發現,此合并的過程和Lucene的段的合并很相似。然而Lucene的一個函數IndexReader.reopen一直是沒有實現的,也即 我們不能選擇哪個段是在內存中的,可以被打開,哪些是硬盤中的,需要在后臺打開然后進行替換,而IndexReader.open是會打開所有的內存中的 和硬盤上的索引,因而會很慢,從而降低了實時性。

    posted on 2010-09-25 16:15 fox009 閱讀(183) 評論(0)  編輯  收藏 所屬分類: 搜索引擎技術

    主站蜘蛛池模板: 久久精品国产这里是免费| 九九免费久久这里有精品23| 国产免费无码AV片在线观看不卡| 免费a级毛片在线观看| 国产亚洲精彩视频| 国产免费拔擦拔擦8x| 免费在线人人电影网| 免费播放春色aⅴ视频| 无码AV动漫精品一区二区免费| 亚洲国产精品第一区二区三区| 日韩在线观看免费| 亚洲乱码日产一区三区| 日本免费一区二区久久人人澡| 久久亚洲精精品中文字幕| 一级做a爰全过程免费视频| 久久久亚洲欧洲日产国码二区 | 国产视频精品免费| 美女被免费网站在线视频免费| 亚洲AV中文无码乱人伦在线视色 | 午夜精品射精入后重之免费观看| 亚洲一区影音先锋色资源| 野花高清在线观看免费3中文| 在线观看亚洲视频| 亚洲日韩小电影在线观看| 7x7x7x免费在线观看| 国产精品亚洲午夜一区二区三区| 欧美a级在线现免费观看| 女人裸身j部免费视频无遮挡| 国产V亚洲V天堂无码久久久| 久久精品国产免费观看三人同眠| 亚洲国产精品无码观看久久| 亚洲一区二区三区乱码A| 99re6热视频精品免费观看| 亚洲国产无线乱码在线观看 | 在线毛片片免费观看| 亚洲人成高清在线播放| 亚洲A∨精品一区二区三区| 野花香在线视频免费观看大全| 456亚洲人成影院在线观| 久久伊人亚洲AV无码网站| 国产精品1024永久免费视频|