有關(guān)Lucene的問題(8):用Lucene構(gòu)建實時索引的文檔更新問題_第1頁
有關(guān)Lucene的問題(8):用Lucene構(gòu)建實時索引的文檔更新問題_第2頁
有關(guān)Lucene的問題(8):用Lucene構(gòu)建實時索引的文檔更新問題_第3頁
有關(guān)Lucene的問題(8):用Lucene構(gòu)建實時索引的文檔更新問題_第4頁
有關(guān)Lucene的問題(8):用Lucene構(gòu)建實時索引的文檔更新問題_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

在有關(guān)Lucene的問題(7),討論了使用Lucene內(nèi)存索引和硬盤索引構(gòu)建實時索引的問題。然而有的讀者提到,如果涉及到文檔的刪除及更新,那么如何構(gòu)建實時的索引呢?本節(jié)來討論這個問題。1、Lucene刪除文檔的幾種方式IndexReader.deleteDocument(intdocID)是用IndexReader按文檔號刪除。IndexReader.deleteDocuments(Termterm)是用IndexReader刪除包含此詞(Term)的文檔。IndexWriter.deleteDocuments(Termterm)是用IndexWriter刪除包含此詞(Term)的文檔。IndexWriter.deleteDocuments(Term[]terms)是用IndexWriter刪除包含這些詞(Term)的文檔。IndexWriter.deleteDocuments(Queryquery)是

用IndexWriter刪除能滿足此查詢(Query)的文檔。IndexWriter.deleteDocuments(Query[]queries)是用IndexWriter刪除能滿足這些查詢(Query)的文檔。刪除文檔既可以用reader進行刪除,也可以用writer進行刪除,不同的是,reader進行刪除后,此reader馬上能夠生效,而用writer刪除后,會被緩存,只有寫入到索引文件中,當(dāng)reader再次打開的時候,才能夠看到。2、Lucene文檔更新的幾個問題2?1、使用IndexReader還是IndexWriter進行刪除既然IndexReader和IndexWriter都能夠進行文檔刪除,那么到底是應(yīng)該用哪個來進行刪除呢?本文的建議是,用IndexWriter來進行刪除。因為用IndexReader可能存在以下的問題:當(dāng)有一個IndexWriter打開的時候,IndexReader的刪除操作是不能夠進行的,否則會報LockObtainFailedException當(dāng)IndexReader被多個線程使用的時候,一個線程用其進行刪除,會使得另一個線程看到的索引有所改變,使得另一個線程的結(jié)果帶有不確定性。對于更新操作,在Lucene中是先刪除,再添加的,然而刪除的被立刻看到的,而添加卻不能夠立刻看到,造成了數(shù)據(jù)的不一致性。即便以上問題可以通過鎖來解決,然而背后的操作影響到了搜索的速度,是我們不想看到的。2?2、如何在內(nèi)存中緩存文檔的刪除在上一節(jié)中,為了能夠做到實時性,我們使用內(nèi)存中的索引,而硬盤上的索引則不經(jīng)常打開,即便打開也在背后線程中打開。而要刪除的文檔如果在硬盤索引中,如果不重新打開則看不到新的刪除,則需要將刪除的文檔緩存到內(nèi)存中。那如何將緩存在內(nèi)存中的文檔刪除在不重新打開IndexReader的情況下應(yīng)用于硬盤上的索引呢?在Lucene中,有一種IndexReader為FilterlndexReader,可以對一個IndexReader進行封裝,我們可以實現(xiàn)一個自己的FilterlndexReader來過濾掉刪除的文檔。一個例子如下:publicclassMyFilterIndexReaderextendsFilterIndexReader{OpenBitSetdels;publicMyFilterIndexReader(IndexReaderin){super(in);dels=newOpenBitSet(in.maxDoc());}publicMyFilterIndexReader(IndexReaderin,ListvString>idToDelete)throwsIOException{super(in);dels=newOpenBitSet(in.maxDoc());for(Stringid:idToDelete){TermDocstd=in.termDocs(newTerm("id",id));//如果能在內(nèi)存中Cache從Lucene的ID到應(yīng)用的ID的映射,Reader的生成將快得多。if(td.next()){dels.set(td.doc());}}}@OverridepublicintnumDocs(){returnin.numDocs()-(int)dels.cardinality();}@OverridepublicTermDocstermDocs(Termterm)throwsIOException{returnnewFilterTermDocs(in.termDocs(term)){@Overridepublicbooleannext()throwsIOException{booleanres;while((res=super.next())){if(!dels.get(doc())){break;}}returnres;}};}@OverridepublicTermDocstermDocs()throwsIOException{returnnewFilterTermDocs(in.termDocs()){@Overridepublicbooleannext()throwsIOException{booleanres;while((res=super.next())){if(!dels.get(doc())){break;}}returnres;}};}}2?3、文檔更新的順序性問題Lucene的文檔更新其實是刪除舊的文檔,然后添加新的文檔。如上所述,刪除的文檔是緩存在內(nèi)存中的,并通過FilterIndexReader應(yīng)用于硬盤上的索引,然而新的文檔也是以相同的id加入到索引中去的,這就需要保證緩存的刪除不會將新的文檔也過濾掉,將緩存的刪除合并到索引中的時候不會將新的文檔也刪除掉。Lucene的兩次更新一定要后一次覆蓋前一次,而不能讓前一次覆蓋后一次。所以內(nèi)存中已經(jīng)硬盤中的多個索引是要被保持一個順序的,哪個是老的索引,哪個是新的索引,緩存的刪除自然是應(yīng)該應(yīng)用于所有比他老的索引的,而不應(yīng)該應(yīng)用于他自己以及比他新的索引。3、具有更新功能的Lucene實時索引方案3?1、初始化首先假設(shè)我們硬盤上已經(jīng)有一個索引FileSystemIndex,被事先打開的,其中包含文檔1,2,3,4,5,6。我們在內(nèi)存中有一個索引MemoryIndex,新來的文檔全部索引到內(nèi)存索引中,并且是索引完IndexWriter就commit,IndexReader就重新打開,其中包含文檔7,8。3?2、更新文檔5這時候來一個新的更新文檔5,需要首先將文檔5刪除,然后加入新的文檔5。需要做的事情是:首先在內(nèi)存索引中刪除文檔5,當(dāng)然沒有文檔5,刪除無效。其次將對文檔5的刪除放入內(nèi)存文檔刪除列表,并與硬

盤的IndexReader組成FilterlndexReader最后,將新的文檔5加入內(nèi)存索引,這時候,用戶可以看到的就是新的文檔5了。將文檔5放入刪除列表以及將文檔5提交到內(nèi)存索引

兩者應(yīng)該是一個原子操作,好在這兩者都是比較塊的。注:此處對硬盤上的索引,也可以進行對文檔5的刪除,由于IndexReader沒有重新打開,此刪除是刪不掉的,我們之所以沒有這樣做,是想保持此次更新要么全部在內(nèi)存中,要么全部在硬盤中,而非刪除部分已經(jīng)應(yīng)用到硬盤中,而新文檔卻在內(nèi)存中,此時,如果系統(tǒng)crash,則新的文檔5丟失了,而舊的文檔5也已經(jīng)在硬盤上被刪除。我們將硬盤上對文檔5的刪除放到從內(nèi)存索引向硬盤索引的合并過程。ZxZxMulliReaderFiiterInd<;xReaderIrtdexReader—LW?吋打幵FiiterInd<;xReaderIrtdexReader—LW?吋打幵如果再有一次對文檔5的更新,則首先將內(nèi)存索引中的文檔5刪除,添加新的文檔5,然后將文檔5加入刪除列表,發(fā)現(xiàn)已經(jīng)存在,則不必刪除。3?3、合并索引然而經(jīng)過一段時間,內(nèi)存中的索引需要合并到硬盤上。在合并的過程中,需要重新建立一個空的內(nèi)存索引,用于合并階段索引新的文檔,而合并中的索引的IndexReader以及硬盤索引和刪除列表所組成的FilterlndexReader仍然保持打開,對外提供服務(wù),而合并階段從后臺進行。后臺的合并包括以下幾步:將刪除列表應(yīng)用到硬盤索引中。將內(nèi)存索引合并到硬盤索引中。IndexWriter提交。

弁Fifterhidexkeader弁Fifterhidexkeader3?4、合并的過程中更新文檔5在合并的過程中,如果還有更新那怎么辦呢?首先將合并中索引的文檔5刪除,此刪除不會影響合并,因為合并之前,合并中索引的IndexReader已經(jīng)打開,索引合并中索引的文檔5還是會合并到硬盤中去的。此刪除影響的是此后的查詢在合并中索引是看不到文檔5的。然后將文檔5的刪除放入刪除列表,并同合并中索引的刪除列表,已經(jīng)硬盤索引一起構(gòu)成FilterIndexReader。將新的文檔5添加到內(nèi)存中索引。提交在合并中索引對文檔5的刪除,將文檔5添加到刪除列表,提交在內(nèi)存索引中對文檔5的添加三者應(yīng)該是一個原子操作,好在三者也是很快的。MultiReaderFilterIndexReaderFilterIndexReader3?5、重新打開硬盤索引的IndexReader當(dāng)合并中索引合并到硬盤中的時候,是時候重新打開硬盤上的索引了,新打開的IndexReader是可以看到文檔5的刪除的。如果這個時候有新的更新,也是添加到內(nèi)存索引和刪除列表的

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論