在ASP.NET MVC站点中使用Lucene.Net进行目录锁定错误

时间:2021-06-03 03:07:44

I'm building an ASP.NET MVC site where I want to use Lucene.Net for search. I've already built a SearchController and all of its methods, but I'm getting an error at runtime that occurs when the SearchController is first initialized.

我正在构建一个ASP.NET MVC站点,我想使用Lucene.Net进行搜索。我已经构建了一个SearchController及其所有方法,但是我在运行时遇到一个错误,这个错误是在首次初始化SearchController时发生的。

In SearchController, here's how I'm creating an IndexWriter:

在SearchController中,这是我如何创建IndexWriter:

public static string IndexLocation = HostingEnvironment.MapPath("~/lucene");
public static Lucene.Net.Analysis.Standard.StandardAnalyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer();
public static IndexWriter writer = new IndexWriter(IndexLocation,analyzer);

The error occurs on the last line. Here's the message that I'm getting:

错误发生在最后一行。这是我得到的信息:

Lucene.Net.Store.LockObtainFailedException: Lock obtain timed out: SimpleFSLock@C:\Users\Username\Desktop\SiteSolution\Site\lucene\write.lock

Lucene.Net.Store.LockObtainFailedException:Lock获取超时:SimpleFSLock @ C:\ Users \ Username \ Desktop \ SiteSolution \ Site \ lucene \ write.lock

Furthermore, here's the stack trace:

此外,这是堆栈跟踪:

[LockObtainFailedException: Lock obtain timed out: SimpleFSLock@C:\Users\Username\Desktop\SiteSolution\Site\lucene\write.lock]
   Lucene.Net.Store.Lock.Obtain(Int64 lockWaitTimeout) in C:\Users\Username\Desktop\Lucene.Net_2_9_2\src\Lucene.Net\Store\Lock.cs:107
   Lucene.Net.Index.IndexWriter.Init(Directory d, Analyzer a, Boolean create, Boolean closeDir, IndexDeletionPolicy deletionPolicy, Boolean autoCommit, Int32 maxFieldLength, IndexingChain indexingChain, IndexCommit commit) in C:\Users\Username\Desktop\Lucene.Net_2_9_2\src\Lucene.Net\Index\IndexWriter.cs:1827
   Lucene.Net.Index.IndexWriter.Init(Directory d, Analyzer a, Boolean closeDir, IndexDeletionPolicy deletionPolicy, Boolean autoCommit, Int32 maxFieldLength, IndexingChain indexingChain, IndexCommit commit) in C:\Users\Username\Desktop\Lucene.Net_2_9_2\src\Lucene.Net\Index\IndexWriter.cs:1801
   Lucene.Net.Index.IndexWriter..ctor(String path, Analyzer a) in C:\Users\Username\Desktop\Lucene.Net_2_9_2\src\Lucene.Net\Index\IndexWriter.cs:1350
   Site.Controllers.SearchController..cctor() in C:\Users\Username\Desktop\SiteSolution\Site\Controllers\SearchController.cs:95

[TypeInitializationException: The type initializer for 'Site.Controllers.SearchController' threw an exception.]

[TargetInvocationException: Exception has been thrown by the target of an invocation.]
   System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck) +0
   System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache) +86
   System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache) +230
   System.Activator.CreateInstance(Type type, Boolean nonPublic) +67
   System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +80

[InvalidOperationException: An error occurred when trying to create a controller of type 'Site.Controllers.SearchController'. Make sure that the controller has a parameterless public constructor.]
   System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +190
   System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +68
   System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +118
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +46
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +63
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +13
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8682818
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

How can I resolve this issue?

我该如何解决这个问题?

UPDATE: I've started working on this particular project again, and it seems that I haven't fully resolved this issue yet.

更新:我已经开始再次研究这个特定项目了,似乎我还没有完全解决这个问题。

The real issue is that the write.lock file isn't being removed after index usage ends. Based on the answer I have accepted, I understand the basic implementation logic, but I'm not sure if I have implemented it correctly. Here are some other methods in my class that are probably invalid:

真正的问题是在索引使用结束后没有删除write.lock文件。根据我接受的答案,我理解基本的实现逻辑,但我不确定我是否已正确实现它。以下是我班级中可能无效的其他一些方法:

    public ActionResult Search(string query)
    {

        var reader = writer.GetReader(); // Get reader from writer
        var searcher = new IndexSearcher(reader); // Build IndexSearch

        //Execute search...

        // Dispose of objects
        searcher = null;
        reader = null;

        return View();
    }

    public void AddToIndex(Document doc)
    {
        writer.AddDocument(doc);
        writer.Flush();
        writer.Optimize();
        writer.Flush();
    }

    private bool disposed = false;

    protected override void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Release managed resources.
            }
            try
            {
                writer.Close();
                writer = null;
            }
            catch
            {

            }
            // Release unmanaged resources.
            // Set large fields to null.
            // Call Dispose on your base class.
            disposed = true;
        }
        base.Dispose(disposing);
    }

Any thoughts?

有什么想法吗?

6 个解决方案

#1


11  

The reason why this happens is that the writer creates an empty file called write.lock as a cross-process lock. When that file exists, Lucene assumes that someone has a write lock on that directory.

发生这种情况的原因是编写器创建了一个名为write.lock的空文件作为跨进程锁。当该文件存在时,Lucene假定有人在该目录上有写锁定。

When you terminate your process incorrectly, the file will not get deleted. So Lucene thinks that someone is still holding on to the lock. That's why you should always have a finally statement which closes the index.

如果错误地终止进程,则不会删除该文件。所以Lucene认为有人仍然坚持锁定。这就是为什么你应该总是有一个关闭索引的finally语句。

If you are sure that the file is there in error (i.e. no Lucene processes are running) it is fine to just delete the file. Your index may, however, be in a corrupted state, since the writing was obviously terminated midstream.

如果你确定该文件存在错误(即没有运行Lucene进程),只需删除该文件即可。但是,您的索引可能处于损坏状态,因为写作明显在中途终止。

#2


2  

Seems to be a dead-lock on lucene.

似乎是对lucene的死锁。

If supposedly NO index update into the collection,
simply remove this lock file C:\Users\Username\Desktop\SiteSolution\Site\lucene\write.lock.

如果假设没有索引更新到集合中,只需删除此锁定文件C:\ Users \ Username \ Desktop \ SiteSolution \ Site \ lucene \ write.lock。

After that re-run the index writing.

之后重新运行索引编写。

#3


2  

try
{
    writer = new IndexWriter(directory, new StandardAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
}

catch (LockObtainFailedException ex)
{
     DirectoryInfo indexDirInfo = new DirectoryInfo(directory);
     FSDirectory indexFSDir = FSDirectory.Open(indexDirInfo, new Lucene.Net.Store.SimpleFSLockFactory(indexDirInfo));
     IndexWriter.Unlock(indexFSDir);
     writer = new IndexWriter(directory, new StandardAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
}

#4


0  

Researching this myself it seems that the indended approach would be to use multiple physical indexes and then merge them using the IndexWriter's .addIndexesNoOptimize or .addIndexes to merge all concurrent index changes.

自己研究这个似乎是indended方法将使用多个物理索引,然后使用IndexWriter的.addIndexesNoOptimize或.addIndexes合并它们以合并所有并发索引更改。

Lucene documentation

Lucene文档

#5


0  

Haven't checked it myself but wouldn't this work (write after creating azureDirectory object)?

没有自己检查但是不会这样(在创建azureDirectory对象后写)?

azureDirectory.ClearLock("write.lock")

#6


0  

I encountered the same issue and I was using an IProviderContext. In my case I had to: Optimize,Commit and Dispose the ProviderContext.

我遇到了同样的问题,我正在使用IProviderContext。在我的情况下,我不得不:优化,提交和处置ProviderContext。

providerContext.Optimize();
providerContext.Commit();
providerContext.Dispose();

I hope this helps. After implementing the above snippet, my index rebuilt successfully.

我希望这有帮助。实现上面的代码片段后,我的索引成功重建。

#1


11  

The reason why this happens is that the writer creates an empty file called write.lock as a cross-process lock. When that file exists, Lucene assumes that someone has a write lock on that directory.

发生这种情况的原因是编写器创建了一个名为write.lock的空文件作为跨进程锁。当该文件存在时,Lucene假定有人在该目录上有写锁定。

When you terminate your process incorrectly, the file will not get deleted. So Lucene thinks that someone is still holding on to the lock. That's why you should always have a finally statement which closes the index.

如果错误地终止进程,则不会删除该文件。所以Lucene认为有人仍然坚持锁定。这就是为什么你应该总是有一个关闭索引的finally语句。

If you are sure that the file is there in error (i.e. no Lucene processes are running) it is fine to just delete the file. Your index may, however, be in a corrupted state, since the writing was obviously terminated midstream.

如果你确定该文件存在错误(即没有运行Lucene进程),只需删除该文件即可。但是,您的索引可能处于损坏状态,因为写作明显在中途终止。

#2


2  

Seems to be a dead-lock on lucene.

似乎是对lucene的死锁。

If supposedly NO index update into the collection,
simply remove this lock file C:\Users\Username\Desktop\SiteSolution\Site\lucene\write.lock.

如果假设没有索引更新到集合中,只需删除此锁定文件C:\ Users \ Username \ Desktop \ SiteSolution \ Site \ lucene \ write.lock。

After that re-run the index writing.

之后重新运行索引编写。

#3


2  

try
{
    writer = new IndexWriter(directory, new StandardAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
}

catch (LockObtainFailedException ex)
{
     DirectoryInfo indexDirInfo = new DirectoryInfo(directory);
     FSDirectory indexFSDir = FSDirectory.Open(indexDirInfo, new Lucene.Net.Store.SimpleFSLockFactory(indexDirInfo));
     IndexWriter.Unlock(indexFSDir);
     writer = new IndexWriter(directory, new StandardAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
}

#4


0  

Researching this myself it seems that the indended approach would be to use multiple physical indexes and then merge them using the IndexWriter's .addIndexesNoOptimize or .addIndexes to merge all concurrent index changes.

自己研究这个似乎是indended方法将使用多个物理索引,然后使用IndexWriter的.addIndexesNoOptimize或.addIndexes合并它们以合并所有并发索引更改。

Lucene documentation

Lucene文档

#5


0  

Haven't checked it myself but wouldn't this work (write after creating azureDirectory object)?

没有自己检查但是不会这样(在创建azureDirectory对象后写)?

azureDirectory.ClearLock("write.lock")

#6


0  

I encountered the same issue and I was using an IProviderContext. In my case I had to: Optimize,Commit and Dispose the ProviderContext.

我遇到了同样的问题,我正在使用IProviderContext。在我的情况下,我不得不:优化,提交和处置ProviderContext。

providerContext.Optimize();
providerContext.Commit();
providerContext.Dispose();

I hope this helps. After implementing the above snippet, my index rebuilt successfully.

我希望这有帮助。实现上面的代码片段后,我的索引成功重建。