Eug*_*ica 27 .net lucene lucene.net
我想使用Lucene.NET在两个应用程序之间共享全文搜索:一个是ASP.NET MVC应用程序,另一个是控制台应用程序.两个应用程序都应该搜索和更新索引.如何处理并发?
我在ifdefined.com上找到了一个教程,其中讨论了类似的用例.我担心锁定将是一个很大的瓶颈.
PS:我还注意到IndexSearcher使用了索引的快照,在上面提到的教程中,只有在索引更新时才会创建搜索器.这是一个好方法吗?我可以在每次搜索时创建一个常规搜索器对象,如果是,那么开销是多少?
我找到了一个相关的问题 Lucene.Net是否管理多个访问同一索引的线程,一个索引而另一个正在搜索?什么声称进程间并发是安全的.这是否意味着它不是指数的竞争条件?
也是一个非常重要的方面.如果让10-15个线程试图通过获取此解决方案中提供的共享锁来更新Lucene索引,那么所涉及的性能损失是多少?
使用它几个月之后,我必须补充一点,搜索的开放索引通常可以在高CPU和内存加载下创建OutOfMemory异常,如果查询使用排序.指数开仓操作的成本很小(根据我的经验),但GC的成本可能相当高.
And*_*ith 31
首先,我们必须定义一个"写"操作.一旦开始写入操作,写入操作将对象锁定,并将继续,直到您关闭正在执行工作的对象.比如创建一个IndexWriter并索引一个文档会导致write对象成为一个锁,并且它将保持这个锁,直到你关闭IndexWriter.
现在我们可以谈谈锁定了一下.这个对象的锁是一个基于文件的锁.像前面提到的mythz一样,有一个名为'write.lock'的文件被创建.一旦写入锁定被反对,它就是独家!此锁导致所有索引修改操作(IndexWriter和IndexReader中的某些方法)等待锁定被删除.
总的来说,你对索引有多次读取.你甚至可以同时读写,没问题.但是有多个编写器时会出现问题.如果一个线程等待锁定的时间太长,它将超时.
1)可能的解决方案#1直接操作
如果您确定索引操作简短而快速,则可以同时使用相同的索引.否则,您将不得不考虑如何组织应用程序的索引操作.
2)可能的解决方案#2 Web服务
由于您正在使用Web解决方案,因此可以创建Web服务.在实现这个Web服务时,我会将一个工作线程专门用于索引.我会创建一个工作队列来包含工作,如果队列包含多个工作要做,它应该抓住它们并将它们分批处理.这将解决所有问题.
3)创建另一个索引,然后合并
如果控制台应用程序在索引上做了大量工作,您可以考虑使用控制台应用程序,您可以在控制台应用程序中创建单独的索引,然后使用IndexWriter.AddIndexes在某个安全的预定时间合并索引.
从这里你可以通过两种方式做到这一点,你可以与直接索引合并.或者您可以合并以创建第三个索引,然后在此索引准备就绪时替换原始索引.你必须小心你在这里所做的事情,以确保你不会在大量使用时锁定某些东西并导致其他写操作超时.
4)索引和搜索多个索引
我个人认为人们需要将他们的索引分开.这有助于分离程序的职责,并最大限度地减少停机时间,并保持所有索引的单点.例如,如果您的控制台应用程序只负责添加某些字段,或者您需要扩展索引,则可以将索引分开,但通过在每个文档中使用ID字段来维护标识.现在,您可以利用内置支持使用MultiSercher类搜索多个索引.或者,如果你想要的话,还有一个很好的ParallelMultiSearch类可以同时搜索两个索引.
5)研究SOLR
还有一些可以帮助您为索引维护单个位置的问题,您可以将程序更改为使用SOLR服务器.http://lucene.apache.org/solr/还有一个很好的SOLRNET http://code.google.com/p/solrnet/库,可以在这种情况下提供帮助.虽然我对solr没有经验,但我的印象是它会帮助你管理这样的情况.此外,它还有其他好处,例如点击突出显示和通过查找"MoreLikeThis"项目搜索相关项目,或提供拼写检查.
我确定还有其他方法,但这些都是我能想到的.总的来说,您的解决方案取决于您正在撰写的人数以及您需要的最新搜索索引.总的来说,如果您可以延迟某些操作并在任何情况下进行一些批处理操作将为您提供最佳性能.我的建议是了解你的工作能力并从那里开始.祝好运
我还有一个由多个客户端使用的lucene搜索索引,我通过使"Lucene Search Service"成为在其自己的App Domain中运行的单独Web服务来解决此问题.由于两个客户端都使用相同的Web服务来搜索或更新索引,因此我可以通过锁定Lucene的Indexers使其成为线程安全的.
除此之外,如果你想让它继续进行,我建议使用文件锁来确保只有一个客户端可以写入索引.
为了让它使用一个新的索引,我创建了一个,然后告诉搜索索引服务交换使用新索引通过安全处理当前索引上的任何索引器并重命名目录,例如
如果您在不同的进程中有多个编写器,并且他们将花费超过10秒的时间将其更改写入索引(这将导致等待编写器超时),那么您可以使用命名的互斥锁同步跨进程的访问.只需在每个应用程序中打开/创建具有相同全局名称的互斥锁Mutex.WaitOne
,并Mutex.ReleaseMutex
在写入之前和写入之后使用.
var mut = Mutex.OpenExisting("myUniqueMutexName"); // wrap in try..catch to create if non-existent
mut.WaitOne();
try {
// write logic
}
finally {
// recover from write failure
mut.ReleaseMutex();
}
Run Code Online (Sandbox Code Playgroud)
可能更好地使Mutex成为单身,因为它们构造起来有点贵.
更新(每条评论):
如果进程位于不同的机器上,我认为您唯一的选择是将自己的文件系统锁定(使用旧式锁定文件)分层以同步访问.由于内置锁定无论如何都使用了文件系统锁,我实际上建议你每次构造时都增加IndexWriter超时.
var iw = new IndexWriter();
iw.WRITE_LOCK_TIMEOUT = 60000;
Run Code Online (Sandbox Code Playgroud)
您也可以继续尝试指定的次数.
var committed = false;
var attempts = 0;
while(!committed && attempts < 10) {
try {
// write logic
committed = true;
} catch (LockObtainFailedException) {
attempts++;
}
}
Run Code Online (Sandbox Code Playgroud)