2010-11-22 74 views
6

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

在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); 

错误。下面是我得到的消息:

Lucene.Net.Store.LockObtainFailedException: 锁定获取超时: SimpleFSLock @ C:\ Users \用户名\桌面\ SiteSolution \网站\ lucene的\写.lock

此外,这里的堆栈跟踪:

[LockObtainFailedException: Lock obtain timed out: [email protected]:\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 

我怎样才能解决这个问题?

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

真正的问题是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); 
    } 

有什么想法?

回答

9

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

当您不正确地终止您的过程时,该文件不会被删除。所以Lucene认为有人仍然坚持锁定。这就是为什么你应该总是有一个关闭索引的语句finally

如果您确定该文件存在错误(即没有Lucene进程正在运行),那么删除该文件就可以了。然而,您的索引可能处于讹误状态,因为写作在中途明显终止。

+0

感谢您的回答!我的静态IndexWriter从来没有真正关闭......这是一个问题吗? – 2010-11-25 06:49:22

+0

@Maxim:如果多个进程需要编写,将是一个问题的唯一原因。否则,通常最好让作者保持打开状态,让lucene决定何时刷新到磁盘。 – Xodarap 2010-11-25 22:48:22

+0

@ Xodarap:我已经开始重新研究这个项目,但我仍然没有完全解决这个问题。我即将更新与我正在使用的一些代码的问题。我了解基本的实现逻辑,但我不确定是否已正确实施。 – 2011-02-19 01:17:39

2

似乎是lucene的死锁。

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

之后,重新运行索引编写。

1
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); 
} 
+1

此代码不能编译。 DirectoryInfo构造函数接受一个字符串,而不是AzureDirectory对象。也许我错过了一些东西。 – 2014-06-29 21:33:14

+0

如果您将索引位置路径字符串而不是目录传递给DirectoryInfo(),则此代码有效。 – 2016-06-07 18:07:22

0

研究这个自己似乎indended的方法是使用多个物理指标,然后使用的IndexWriter的.addIndexesNoOptimize或.addIndexes合并所有并发指数的变化将它们合并。

Lucene documentation

0

没有检查自己,但不会这项工作(创建azureDirectory对象之后写的)?

azureDirectory.ClearLock("write.lock") 
0

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

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

我希望这有助于。执行上面的代码片段后,我的索引成功重建。