本文將介紹有關(guān)索引并發(fā)控制的問(wèn)題,以結(jié)束對(duì)Lucene.net建立索引問(wèn)題的討論.
1. 允許任意多的讀操作并發(fā).即可以有任意多的用戶在同一時(shí)間對(duì)同一份索引做查詢工作.
2. 允許任意多的讀操作在索引被正在被修改的時(shí)候進(jìn)行.即哪怕索引正在被優(yōu)化,添加刪除文檔,這時(shí)也是允許用戶對(duì)索引進(jìn)行查詢工作. (it’s so cool.)
3. 同一時(shí)間只允許一個(gè)對(duì)索引修改的操作.即同一時(shí)間只允許IndexWriter或IndexReader打開(kāi)同一份索引.不能允許兩個(gè)同時(shí)打開(kāi)一份索引.
Lucene提供了幾種對(duì)索引進(jìn)行讀寫(xiě)的操作.添加文檔到索引,從索引中刪除文檔,優(yōu)化索引,合并Segments.這些都是對(duì)索引進(jìn)行寫(xiě)操作的方法. 查詢的時(shí)候就會(huì)讀取索引的內(nèi)容.
有關(guān)索引并發(fā)的問(wèn)題是一個(gè)比較重要的問(wèn)題,而且是Lucene的初學(xué)者容易忽略的問(wèn)題,當(dāng)索引被破壞,或者程序突然出現(xiàn)異常的時(shí)候初學(xué)者往往不知道是自己的誤操作造成的.
下面讓我們看看Lucene是如何處理索引文件的并發(fā)控制的.
首先記住一下三點(diǎn)準(zhǔn)則:
1. 允許任意多的讀操作并發(fā).即可以有任意多的用戶在同一時(shí)間對(duì)同一份索引做查詢工作.
2. 允許任意多的讀操作在索引被正在被修改的時(shí)候進(jìn)行.即哪怕索引正在被優(yōu)化,添加刪除文檔,這時(shí)也是允許用戶對(duì)索引進(jìn)行查詢工作. (it’s so cool.)
3. 同一時(shí)間只允許一個(gè)對(duì)索引修改的操作.即同一時(shí)間只允許IndexWriter或IndexReader打開(kāi)同一份索引.不能允許兩個(gè)同時(shí)打開(kāi)一份索引.
第一個(gè)準(zhǔn)則很容易理解,第二個(gè)準(zhǔn)則說(shuō)明Lucene對(duì)并發(fā)的操作支持還是不錯(cuò)的.第三個(gè)準(zhǔn)則也很正常,不過(guò)需要注意的是第三個(gè)準(zhǔn)則只是表明IndexWriter和IndexReader不能并存,而沒(méi)有反對(duì)在多線程中利用同一個(gè)IndexWriter對(duì)索引進(jìn)行修改.這個(gè)功能可是經(jīng)常用到的,所以不要以為它是不允許的.不過(guò)這個(gè)時(shí)候的并發(fā)就需要你自己加以控制,以免出現(xiàn)沖突.
(注: 在前面的系列中已說(shuō)過(guò)IndexReader不是對(duì)Index進(jìn)行讀操作,而是從索引中刪除docuemnt時(shí)使用的對(duì)象)
有關(guān)這三個(gè)原則在實(shí)際使用Lucene API時(shí)候的體現(xiàn),讓我們先看看下面這張表:
而X處表明X軸的操作和Y軸的操作不允許同時(shí)進(jìn)行.
比如Add document到索引的時(shí)候不允許同時(shí)從索引中刪除document.
其實(shí)以上這張表就是前面三個(gè)準(zhǔn)則的體現(xiàn).Add Optimize Merge操作都是由IndexWriter來(lái)做的.而Delete則是通過(guò)IndexReader完成.所以表中空白處正是第一條和第二條準(zhǔn)則的體現(xiàn),而X(沖突)處正是第三個(gè)原則的具體表現(xiàn).
為了在不了解并發(fā)控制的情況下對(duì)Lucene API的亂用. Lucene提供了基于文件的鎖機(jī)制以確保索引文件不會(huì)被破壞.
當(dāng)你對(duì)index 進(jìn)行修改的時(shí)候, 比如添加刪除文檔的時(shí)候就會(huì)產(chǎn)生 ***write.lock文件,而當(dāng)你從segment進(jìn)行讀取信息或者合并segments的時(shí)候就會(huì)產(chǎn)生***commit.lock文件.在默認(rèn)情況下,這些文件是放在系統(tǒng)臨時(shí)文件夾下的. 簡(jiǎn)而言之, write.lock文件存在的時(shí)間比較長(zhǎng),也就是對(duì)index進(jìn)行修改的鎖時(shí)間比較長(zhǎng),而commit.lock存在的時(shí)間往往很短.具體情況見(jiàn)下表.
如果索引存在于server, 很多clients想訪問(wèn)的時(shí)候,自然希望能看到其他用戶的鎖文件,這時(shí)把鎖文件放到系統(tǒng)臨時(shí)文件夾就不好了.此時(shí)可以通過(guò)配置文件來(lái)改變鎖文件存放的位置.
比如在一個(gè)asp.net的應(yīng)用下,你就可以象下面這樣利用web.config文件來(lái)實(shí)現(xiàn)你的目的.
<configuration>
<appSettings>
<add key="Lucene.Net.lockdir" value="c:yourdir" />
</appSettings>
</configuration>
不僅如此,在某些情況下比如你的索引文件存放在一個(gè)CD-ROM中,這時(shí)根本就無(wú)法對(duì)索引進(jìn)行修改,也就不存在所謂的并發(fā)沖突,這種情況下你甚至可以講鎖文件的機(jī)制取消掉.同樣通過(guò)配置文件.
<configuration>
<appSettings>
<add key="disableLuceneLocks" value="true" />
</appSettings>
</configuration>
不過(guò)請(qǐng)注意不要亂用此功能,不然你的索引文件將不再受到安全的保護(hù).
下面用一個(gè)例子說(shuō)明鎖機(jī)制的體現(xiàn).
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();
}
}
}
不過(guò)很令人失望的是在Lucene(Java)中應(yīng)該收到的異常在dotLucene(1.4.3)我卻沒(méi)有捕獲到.隨后我在dotLucene的論壇上問(wèn)了一下,至今尚未有解答.這也是開(kāi)源項(xiàng)目的無(wú)奈了吧.
聯(lián)系客服