事务性Lucene
許多用戶不喜歡Lucene API的事務性語義,以及這在搜索應用程序中如何有用。 首先,Lucene實現(xiàn)了ACID屬性:
- 一個 tomicity:當您在更改(添加,刪除文件) IndexWriter會話,然后提交,要么全部(如果提交成功)或無的更改(如果提交失敗)將是可見的,從來沒有的東西在兩者之間。 某些方法具有其自己的原子行為:如果調(diào)用updateDocument ,該方法實現(xiàn)為在刪除之后添加的實現(xiàn),即使打開了近實時(NRT)閱讀器或從單獨的線程提交。 同樣,如果使用相對較新的 addDocuments方法添加文檔塊,則在獲得的任何閱讀器中都不會看到任何文檔或全部文檔。
- ?onsistency:如果計算機或操作系統(tǒng)崩潰,或JVM崩潰或被殺,或斷電,你的指數(shù)將保持不變(即,未破壞)。 請注意,其他問題(例如RAM損壞,CPU翻轉(zhuǎn)或文件系統(tǒng)損壞)仍然很容易損壞索引!
- 我這樣想 :在IndexWriter進行更改時,任何搜索索引的IndexReader都不可見,直到您提交或打開新的NRT閱讀器。 一次僅一個IndexWriter實例可以更改索引。
- d urability:一旦commit的回報,所有的改變都被寫入持久性存儲器(假設(shè)你的I / O系統(tǒng)正確實現(xiàn)fsync )。 如果計算機或操作系統(tǒng)崩潰,或者JVM崩潰或被殺死,或者計算機斷電,則所有更改仍將存在于索引中。
Lucene提供了兩階段的提交 API:調(diào)用prepareCommit方法來完成所有艱苦的工作(應用緩沖的刪除,編寫緩沖的文檔,fsync文件)。 如果出現(xiàn)問題(例如磁盤已滿),幾乎肯定會在第一階段發(fā)生。 然后,調(diào)用commit完成事務。
當您關(guān)閉IndexWriter ,它commit在IndexWriter調(diào)用commit 。 相反,如果您想放棄自上次提交以來的所有更改,請調(diào)用rollback方法,該方法也將關(guān)閉編寫器。 您甚至可以回滾CREATE :如果您已有索引,并使用OpenMode.CREATE在其上打開IndexWriter ,然后回滾,則索引將保持不變。 同樣,如果調(diào)用deleteAll然后回滾。
注意,僅在新目錄上打開IndexWriter并不會創(chuàng)建空提交。 也就是說,您必須先調(diào)用commit才能在目錄上打開IndexReader 。
Lucene本身并沒有實現(xiàn)事務日志 ,但是很容易在頂層構(gòu)建該層。 例如,流行的搜索服務器(例如Solr和ElasticSearch )就是這樣做的。
在一個索引中多次提交
一個Lucene索引可以自由包含多個提交; 這是一個功能強大但經(jīng)常被忽略的功能。 每個提交都擁有創(chuàng)建提交時所存在的索引的時間點視圖。
這類似于ZFS和新興的Btrfs等現(xiàn)代文件系統(tǒng)中可用的快照和可寫克隆。 實際上,Lucene能夠基于相同的根本原因有效地公開多個提交:所有索引段和文件都是一次寫入的,就像ZFS和Btrfs中的文件塊一樣。
要在索引中保存多個提交,只需實現(xiàn)自己的IndexDeletionPolicy并將其傳遞給IndexWriter 。 這是Lucene用來了解應刪除哪些提交的類: IndexWriter在打開索引時以及每次提交成功時都會調(diào)用它。 默認策略KeepOnlyLastCommitDeletionPolicy刪除除最后一次提交以外的所有內(nèi)容。 如果您使用NoDeletionPolicy則將保留每次提交!
您可以將userData ( Map<String,String> )傳遞給commit ,以記錄有關(guān)該提交的自定義信息(對Lucene不透明),然后使用IndexReader.listCommits在索引中查找所有提交。 找到提交后,您可以在其上打開IndexReader來搜索該提交時的索引。
您還可以在先前的提交上打開IndexWriter ,以有效地回滾之后的所有更改:這與rollback方法一樣,不同之處在于它使您可以跨提交進行回滾,而不僅僅是在當前IndexWriter會話中進行的更改。
即使使用OpenMode.CREATE打開索引,舊提交仍將保留。 當IndexReader仍在搜索舊提交時,也可以通過OpenMode.CREATE 。 這可以實現(xiàn)有趣的用例,例如在每次提交之間完全重新索引您的內(nèi)容,而不會影響任何開放的讀者。
結(jié)合所有這些有趣的事務功能,您可以做一些很酷的事情:
- 使用SnapshotDeletionPolicy或PersistentSnapshotDeletionPolicy 熱備份 :這些刪除策略使“實時”備份索引變得很簡單,而不會阻止使用IndexWriter進行的更改。 備份可以輕松進行增量備份(只需復制新文件,然后刪除已刪除的文件),就可以自由限制IO,以最大程度地減少對搜索的干擾。
- 搜索不同的目錄版本:也許您運行了一個電子商務網(wǎng)站,但是卻發(fā)布了多個版本的目錄。 在這種情況下,您可以保留較舊的提交,每次提交都搜索目錄的特定版本,從而使用戶可以選擇要搜索的目錄。
- 來自相同初始索引的可重復索引測試:也許您想運行一堆性能測試,也許從一個大的初始索引開始嘗試不同的RAM緩沖區(qū)大小或合并因子。 為此,只需運行每個測試,但是最后,不要關(guān)閉IndexWriter ,而使用rollback方法將索引快速返回其初始狀態(tài),以準備進行下一個測試。
- 強制將所有索引段合并到單個段,但也保留先前的多段提交。 然后,您可以進行測試以比較多段性能與單段性能。
- 在NFS文件系統(tǒng)上建立索引并進行搜索:由于NFS不能保護仍處于打開狀態(tài)的文件不被刪除,因此必須使用IndexDeletionPolicy保留每個提交,直到所有打開的閱讀器都完成了提交(即,重新打開為新的提交)。 簡單的方法是基于時間的,例如:不要刪除提交,直到提交時間為15分鐘,然后始終每5分鐘重新打開閱讀器一次。 沒有這個,在NFS上進行搜索時,您將遇到各種可怕的異常。
- 分布式提交:如果您還有其他資源必須隨同Lucene索引的更改一起自動提交,則可以使用兩階段提交API。 這很簡單,但是很容易在第二階段失敗。 為了從這種情況下恢復過來,例如,如果Lucene完成了其第二階段提交,但是數(shù)據(jù)庫的第二階段遇到了一些錯誤,崩潰或斷電,則可以通過在先前提交時打開IndexWriter輕松回滾Lucene的提交。
- 實驗性索引更改:也許您想嘗試以新的方式重新索引索引的某些子集,但是您不確定該索引是否會奏效。 在這種情況下,只需保留舊的提交,然后在不成功的情況下回滾,或者如果舊的刪除則刪除。
- 基于時間的快照:也許您希望自由地回滾到1天,1周前,1個月前等索引的索引,因此可以根據(jù)提交的年齡來保留提交。
請記住,保持多個提交活動必定會占用額外的磁盤空間,但是,開銷通常很小,因為多個提交通常會共享公共段,尤其是較大的舊段。
翻譯自: https://www.javacodegeeks.com/2013/06/transactional-lucene.html
總結(jié)
- 上一篇: 科大讯飞宣布讯飞星火即日起向全民开放,能
- 下一篇: 任天堂和 Niantic 发布基于浏览器