天天看點

Lucene5學習之Directory了解

directory即lucene中對索引目錄的一個抽象,展現到api上,它被設計為一個抽象類,類裡面定義了一些抽象方法,如listall列出目錄下所有檔案,deletefile(string name) 根據檔案名稱删除索引檔案,這個都是檔案的基本操作,其中比較重要的一個接口方法是makelock,為什麼要為索引目錄加鎖?其實就跟你上廁所為什麼要鎖門是一樣一樣滴?我沒拉完你就給我乖乖等着。

 basedirectory是directory的一個子類,它預設實作了makelock方法,

Lucene5學習之Directory了解

@override  

  public final lock makelock(string name) {  

    return lockfactory.makelock(this, name);  

  }  

 這裡的lockfactory仍然是一個抽象類,由子類傳入傳入具體的lockfactory工廠實作來建立不同的lock執行個體fsdirectory是針對檔案系統的一個directory實作,即使用這個directory就可以把索引檔案存儲到我們的檔案系統裡了。fsdirectory下面又有3個子類,分别是simplefsdirectory,niofsdirectory,mmapdirectory,

simplefsdirectory:它是基于檔案系統的索引目錄的一個簡單實作,它在多線程環境下性能表現很差,不支援并發讀寫索引檔案。

niofsdirectory:顧名思義,它就是使用nio裡的filechannel檔案通道來解決并發讀寫索引檔案的,但它在windows平台下有個緻命的bug,官方建議在windows平台下使用rafdirectory來代替niofsdirectory。

mmapdirectory:即基于記憶體映射的方式把檔案load到記憶體來減少與io的互動次數,進而提高io性能,但這部分記憶體也存在隐患,因為jdk存在一個bug,就是當indexinput.close()時并不能有效的交還檔案系統裡索引檔案的檔案句柄,這就直接導緻索引lock無法釋放,一直直到gc回收這部分記憶體中潛在的對象時該句柄才會釋放。由于檔案句柄不能有效的立即釋放,可能會導緻你的硬碟空間得不到立即的釋放,是以如果你的應用對于硬碟狀況很敏感,這将是一個緻命的定時炸蛋(連個zha彈都不讓寫,iteye這是怎麼了?),放在心裡就行,反正暫時這個bug未解決。(現在硬碟這麼廉價,多浪費點硬碟空間也沒啥)不過在linux系統上,即使句柄沒有釋放,當你删除索引檔案時會提示是否在delete on last close,當你close時候還是會删除成功的,但索引檔案還是會檔案系統上占硬碟空間,而在windows平台上你隻會得到一個error,是以又是windows,你懂的。

上面簡單說了下各種fsdirectory的作用,下面簡單說下各個directory中比較重要的一些接口方法:

Lucene5學習之Directory了解

/** just like {@link #open(path)}, but allows you to 

   *  also specify a custom {@link lockfactory}. */  

  public static fsdirectory open(path path, lockfactory lockfactory) throws ioexception {  

    if (constants.jre_is_64bit && mmapdirectory.unmap_supported) {  

      return new mmapdirectory(path, lockfactory);  

    } else if (constants.windows) {  

      return new simplefsdirectory(path, lockfactory);  

    } else {  

      return new niofsdirectory(path, lockfactory);  

    }  

 fsdirectory類裡的open方法是使用比較頻繁的方法之一,其實内部就是根據使用者的作業系統環境和使用的jdk來選擇合适的directory,

constants.jre_is_64bit即表示是否是64位的jdk,

mmapdirectory.unmap_supported即表示是否支援direct buffer,什麼叫direct buffer?其實direct buffer并不是直接配置設定在堆上的,direct buffer不受gc管理,即direct buffer是有作業系統來銷毀的,但direct buffer上對象是由gc負責回收的,direct buffer讀寫之是以快,是因為減少資料拷貝到核心緩沖區的操作,但direct buffer是由作業系統負責銷毀,是以代價也是很高的。那我們看看lucene是如何判斷是否支援direct buffer的?

Lucene5學習之Directory了解

/** 

   * <code>true</code>, if this platform supports unmapping mmapped files. 

   */  

  public static final boolean unmap_supported;  

  static {  

    boolean v;  

    try {  

      class.forname("sun.misc.cleaner");  

      class.forname("java.nio.directbytebuffer")  

        .getmethod("cleaner");  

      v = true;  

    } catch (exception e) {  

      v = false;  

    unmap_supported = v;  

這兩個類都是用于direct buffer裡對象清理工作的。

oracle/sun jdk 6中的hotspot vm隻會在年老代gc(full gc/major gc或者concurrent gc都算)的時候才會做reference processing,而在young gc/minor gc時不做。 也就是說,做full gc的話會做reference processing,進而能觸發cleaner對已死的directbytebuffer對象做清理工作。而如果很長一段時間裡沒做過gc或者隻做了young gc的話則不會觸發cleaner的工作,那麼就可能讓本來已經死了的directbytebuffer關聯的native memory得不到及時釋放。 

之是以要保證有上述兩個類,就是確定directbytebuffer裡的記憶體能得到釋放以保證性能,這樣你使用mmapdirectory才能展現它的優勢又能避免它潛在的隐患。

另外一個比較重要的directory就是fileswitchdirectory,它就是集niodirectory與mmapdirectory優點與一身的directory,niodirectory是直接把檔案放入heap buffer中,而mmapdirectory是把檔案直接映射到direct buffer,由于heap buffer可使用量大而direct buffer雖然讀寫速度快,但它受作業系統排程,開辟和銷毀的代價太高,不宜過多使用,是以一般我們需要使用niodirectory來讀寫比較大的索引檔案,而用mmapdirectory來讀寫相對比較小的檔案,兩者結合互補你懂的。

同理lock也有對應的3種實作,就不贅述了。

一般我們使用fsdirectory.open由api自動幫我們來選擇合适的directory即可,特殊情況下可以使用fileswitchdirectory結合下兩種directory的優點。關于directory就說這麼多了,如果有哪裡說的不正确,還望你提出來,謝謝!

如果你還有什麼問題請加我Q-q:7-3-6-0-3-1-3-0-5,

或者加裙

Lucene5學習之Directory了解

一起交流學習!

轉載:http://iamyida.iteye.com/blog/2194394