Lucene.net 系列四 --- index 下

本文將介紹有關索引併發控制的問題,以結束對Lucene.net建立索引問題的討論.
1. 允許任意多的讀操作併發.即可以有任意多的用戶在同一時間對同一份索引做查詢工作.
2. 允許任意多的讀操作在索引被正在被修改的時候進行.即哪怕索引正在被優化,添加刪除文檔,這時也是允許用戶對索引進行查詢工作. (it’s so cool.)
3. 同一時間只允許一個對索引修改的操作.即同一時間只允許IndexWriter或IndexReader打開同一份索引.不能允許兩個同時打開一份索引.
Lucene提供了幾種對索引進行讀寫的操作.添加文檔到索引,從索引中刪除文檔,優化索引,合併Segments.這些都是對索引進行寫操作的方法. 查詢的時候就會讀取索引的內容.
有關索引併發的問題是一個比較重要的問題,而且是Lucene的初學者容易忽略的問題,當索引被破壞,或者程序突然出現異常的時候初學者往往不知道是自己的誤操作造成的.
下面讓我們看看Lucene是如何處理索引文件的併發控制的.
首先記住一下三點準則:
1. 允許任意多的讀操作併發.即可以有任意多的用戶在同一時間對同一份索引做查詢工作.
2. 允許任意多的讀操作在索引被正在被修改的時候進行.即哪怕索引正在被優化,添加刪除文檔,這時也是允許用戶對索引進行查詢工作. (it’s so cool.)
3. 同一時間只允許一個對索引修改的操作.即同一時間只允許IndexWriter或IndexReader打開同一份索引.不能允許兩個同時打開一份索引.
第一個準則很容易理解,第二個準則說明Lucene對併發的操作支持還是不錯的.第三個準則也很正常,不過需要注意的是第三個準則只是表明IndexWriter和IndexReader不能並存,而沒有反對在多線程中利用同一個IndexWriter對索引進行修改.這個功能可是經常用到的,所以不要以爲它是不允許的.不過這個時候的併發就需要你自己加以控制,以免出現衝突.
(注: 在前面的系列中已說過IndexReader不是對Index進行讀操作,而是從索引中刪除docuemnt時使用的對象)
有關這三個原則在實際使用Lucene API時候的體現,讓我們先看看下面這張表:

表中列出了有關索引的主要讀寫操作.其中空白處表示X軸的操作和Y軸的操作允許併發.
而X處表明X軸的操作和Y軸的操作不允許同時進行.
比如Add document到索引的時候不允許同時從索引中刪除document.
其實以上這張表就是前面三個準則的體現.Add Optimize Merge操作都是由IndexWriter來做的.而Delete則是通過IndexReader完成.所以表中空白處正是第一條和第二條準則的體現,而X(衝突)處正是第三個原則的具體表現.
爲了在不瞭解併發控制的情況下對Lucene API的亂用. Lucene提供了基於文件的鎖機制以確保索引文件不會被破壞.
當你對index 進行修改的時候, 比如添加刪除文檔的時候就會產生 ***write.lock文件,而當你從segment進行讀取信息或者合併segments的時候就會產生***commit.lock文件.在默認情況下,這些文件是放在系統臨時文件夾下的. 簡而言之, write.lock文件存在的時間比較長,也就是對index進行修改的鎖時間比較長,而commit.lock存在的時間往往很短.具體情況見下表.
如果索引存在於server, 很多clients想訪問的時候,自然希望能看到其他用戶的鎖文件,這時把鎖文件放到系統臨時文件夾就不好了.此時可以通過配置文件來改變鎖文件存放的位置.
比如在一個asp.net的應用下,你就可以象下面這樣利用web.config文件來實現你的目的.
<configuration>
    <appSettings>
        <add key="Lucene.Net.lockdir" value="c:yourdir" />
    </appSettings>
</configuration>
不僅如此,在某些情況下比如你的索引文件存放在一個CD-ROM中,這時根本就無法對索引進行修改,也就不存在所謂的併發衝突,這種情況下你甚至可以講鎖文件的機制取消掉.同樣通過配置文件.
<configuration>
    <appSettings>
        <add key="disableLuceneLocks" value="true" />
    </appSettings>
</configuration>
不過請注意不要亂用此功能,不然你的索引文件將不再受到安全的保護.
下面用一個例子說明鎖機制的體現.
using System;
using System.IO;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.Store;
using NUnit.Framework;
using Directory = Lucene.Net.Store.Directory;

[TestFixture]
public class LockTest
{
private Directory dir;
[SetUp]
public void Init()
{
String indexDir = "index";
dir = FSDirectory.GetDirectory(indexDir, true);
}
[Test]
[ExpectedException(typeof(IOException))]
public void WriteLock()
{
IndexWriter writer1 = null;
IndexWriter writer2 = null;
try
{
   writer1 = new IndexWriter(dir, new SimpleAnalyzer(), true);
   writer2 = new IndexWriter(dir, new SimpleAnalyzer(), true);
  
}
catch (IOException e)
{
   Console.Out.WriteLine(e.StackTrace);
}
finally
{
   writer1.Close();
   Assert.IsNull(writer2);
}
}
[Test]
public void CommitLock()
{
IndexReader reader1 = null;
IndexReader reader2 = null;
try
{
   IndexWriter writer = new IndexWriter(dir, new SimpleAnalyzer(),
                                        true);
   writer.Close();
   reader1 = IndexReader.Open(dir);
   reader2 = IndexReader.Open(dir);
}
finally
{
   reader1.Close();
   reader2.Close();
}
}
}
不過很令人失望的是在Lucene(Java)中應該收到的異常在dotLucene(1.4.3)我卻沒有捕獲到.隨後我在dotLucene的論壇上問了一下,至今尚未有解答.這也是開源項目的無奈了吧.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章