<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)  編輯  收藏 所屬分類: 搜索引擎技術

    主站蜘蛛池模板: 亚洲午夜视频在线观看| 青青草国产免费久久久下载| 亚洲日韩国产一区二区三区| 精品无码专区亚洲| 免费观看a级毛片| 亚洲国产精品网站在线播放 | h视频免费高清在线观看| 日韩毛片免费在线观看| 亚洲欧美乱色情图片| 国产免费私拍一区二区三区| 久久亚洲AV成人无码国产电影| 日本19禁啪啪无遮挡免费动图| 亚洲丶国产丶欧美一区二区三区| 免费毛片网站在线观看| 青娱乐在线免费观看视频| 亚洲成网777777国产精品| 久久久受www免费人成| 亚洲色成人中文字幕网站| 无码免费一区二区三区免费播放| 亚洲三级电影网址| 美女视频黄的全免费视频| 亚洲人AV在线无码影院观看| 国产一区二区三区无码免费| 2022国内精品免费福利视频| 久久噜噜噜久久亚洲va久| 97碰公开在线观看免费视频| 亚洲av无一区二区三区| 亚洲一区日韩高清中文字幕亚洲 | 亚洲一区二区在线免费观看| 亚洲大尺码专区影院| 最新69国产成人精品免费视频动漫 | a级精品九九九大片免费看| 亚洲日韩图片专区第1页| 在线观看av永久免费| 青青久久精品国产免费看| 亚洲AV无码码潮喷在线观看| 性做久久久久久久免费看| 一级看片免费视频| 亚洲视频在线观看免费视频| 四虎www免费人成| 成人无码精品1区2区3区免费看|