十年網(wǎng)站開發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊
量身定制 + 運(yùn)營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
這篇文章主要介紹“Lucene的Directory怎么實(shí)現(xiàn)”,在日常操作中,相信很多人在Lucene的Directory怎么實(shí)現(xiàn)問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Lucene的Directory怎么實(shí)現(xiàn)”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
創(chuàng)新互聯(lián)專注于涇縣企業(yè)網(wǎng)站建設(shè),自適應(yīng)網(wǎng)站建設(shè),商城建設(shè)。涇縣網(wǎng)站建設(shè)公司,為涇縣等地區(qū)提供建站服務(wù)。全流程按需定制,專業(yè)設(shè)計,全程項目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)
在此之前,我們先來看下Directory家族的層級分布圖。
從上圖中,我們可以看出Directory共有11個直接或者間接的子類,不同的子類的作用和功能不一樣,那么Directory作為此繼承圖的頂級父類,在Lucene中確實(shí)發(fā)揮重要的根基作用,就像Hadoop的根基是HDFS一樣,Directory肩負(fù)著索引存儲的重任,如果沒有存儲,那么檢索就無從談起了,雖然我們經(jīng)常稱全文檢索,搜索引擎什么的,其實(shí)它們的背后,Directory才是默默無聞的”雷鋒“。
下面就來詳細(xì)的剖析下Directory的核心實(shí)現(xiàn)。
Directory是由lucene中的一些列索引文件組成的目錄,一個典型索引文件結(jié)構(gòu)圖的截圖如下:
而Directory的作用,就是負(fù)責(zé)管理這些索引文件,包括數(shù)據(jù)的讀取和寫入,以及索引文件的添加,刪除和合并。從這樣的角度來分析,Directory更像一個系統(tǒng)的管理員,下面,散仙再具體的分析下一些核心方法的作用。
我們都知道Lucene的索引體系,支持讀共享,寫?yīng)氄嫉姆绞絹碓L問索引目錄,也就是說,它允許多個線程實(shí)例同時并發(fā)的讀取,而不允許多個線程同時寫入,大家可能會有疑問,為什么不支持多線程寫入呢?這其實(shí)是因?yàn)樗饕夸浻凶约旱哪骋粫r刻的內(nèi)部狀態(tài),比如說文件指針,而多線程寫入時,會造成指針混亂,從而引起索引結(jié)構(gòu)損壞或某些數(shù)據(jù)丟失,所以lucene任何時候都禁止有多個線程并發(fā)的寫入索引,即使是多線程寫,每次也只能通過隊列的方式,一次只允許一個線程操作索引,按這樣的情況分析,多線程寫入與單線程寫入,在性能上的提升,并不是明顯的,那么lucene又是怎么控制一次只能有一個線程寫入呢,打開Directory的源碼,我們就會發(fā)現(xiàn),它其實(shí)是在內(nèi)部維護(hù)了一個鎖的實(shí)例,通過加鎖方式,來禁止后來線程的寫入操作,當(dāng)然鎖的作用不僅僅是防止并發(fā)寫入,它還可以通過鎖名字來判斷,這兩份索引是否為同一份索引,那么如果我們想使用多線程來提升寫入速度,一個折中的辦法就是,每個線程寫一份目錄,最后在對這些目錄,進(jìn)行合并,下面給出了一些源碼中鎖的實(shí)現(xiàn)方法
protected LockFactory lockFactory;//鎖實(shí)現(xiàn),只能由子類覆蓋 //設(shè)置鎖名 public Lock makeLock(String name) { return lockFactory.makeLock(name); } //清除鎖 public void clearLock(String name) throws IOException { if (lockFactory != null) { lockFactory.clearLock(name); } }
下面我們來分析下Directory源碼中另外一個變量isOpen的作用
//注意,使用的是volatile關(guān)鍵字修飾 volatile protected boolean isOpen = true;
isOpen是用來判斷當(dāng)前的Directory實(shí)例,在內(nèi)存中的狀態(tài),它使用的是volatile 關(guān)鍵字修飾的,被此變量修飾的內(nèi)容,JVM虛擬機(jī)讀取的時候會直接在主存中讀取該變量的值,而不會在各個線程的本地內(nèi)存中讀,這樣一來,當(dāng)并發(fā)讀的時候,如果Directory實(shí)例關(guān)閉了,那么各個讀的線程會立即獲取最新的狀態(tài),如果不做處理的話,將會拋出一個目錄實(shí)例關(guān)閉的異常。isOpen 確保了索引在并發(fā)讀的時候,各個線程實(shí)例獲取Directory狀態(tài)的一致性。
private static final class SlicedIndexInput extends BufferedIndexInput { IndexInput base; long fileOffset; long length; SlicedIndexInput(final String sliceDescription, final IndexInput base, final long fileOffset, final long length) { this(sliceDescription, base, fileOffset, length, BufferedIndexInput.BUFFER_SIZE); } SlicedIndexInput(final String sliceDescription, final IndexInput base, final long fileOffset, final long length, int readBufferSize) { super("SlicedIndexInput(" + sliceDescription + " in " + base + " slice=" + fileOffset + ":" + (fileOffset+length) + ")", readBufferSize); this.base = base.clone(); this.fileOffset = fileOffset; this.length = length; }
接下來,來分析Directory的靜態(tài)常量內(nèi)部類SlicedIndexInput的作用,Lucene的索引文件是非常松散的,不同類型的數(shù)據(jù)存儲在不同的文件里,我們可以通過文件名,來單獨(dú)讀取指定索引文件的內(nèi)容,同樣道理我們也可以,在寫入信息時候,單獨(dú)寫入某部分?jǐn)?shù)據(jù)的信息,這樣一來,就避免了操作整個目錄的可能,按需所用,從一定程度上來說,這樣的設(shè)計提升了性能,保證了數(shù)據(jù)的穩(wěn)定與可靠性,雖然也從某種程度上加大了Directory目錄管理的復(fù)雜度,但這些都是微不足道的。
SlicedIndexInput這個類的作用保證了Lucene可以單獨(dú)讀取部分索引文件的內(nèi)容,注意這些內(nèi)容都不是最原始的數(shù)據(jù),而是SlicedIndexInput克隆的一份副本,這樣一來在并發(fā)讀的環(huán)境下是非常有利的,每個線程都會從主存中l(wèi)oad一份副本出來。在我們的源碼中,我們并沒有發(fā)現(xiàn)它具有深度克隆的功能,但是通過一系列繼承的追蹤,我們發(fā)現(xiàn),SlicedIndexInput==》BufferedIndexInput==》IndexInput==》DataInput,在最后的這個父類中實(shí)現(xiàn)了Cloneable和Closeable接口,從而確保保證了SlicedIndexInput可以正常的工作,以及釋放一些占用的IO資源。
到此,關(guān)于“Lucene的Directory怎么實(shí)現(xiàn)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!