2010-11-22 14 views
6

Estoy creando un sitio ASP.NET MVC donde deseo usar Lucene.Net para buscar. Ya he creado un SearchController y todos sus métodos, pero recibo un error en el tiempo de ejecución que ocurre cuando el SearchController se inicializa por primera vez.Error de bloqueo del directorio con el uso de Lucene.Net en un sitio MVC de ASP.NET

En SearchController, así es como estoy creando un 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); 

El error se produce en la última línea. Este es el mensaje que estoy recibiendo:

Lucene.Net.Store.LockObtainFailedException: Lock obtener tiempo de espera: SimpleFSLock @ C: \ Users \ nombre de usuario \ Desktop \ SiteSolution \ Site \ Lucene \ escritura .lock

Además, aquí está el seguimiento de pila:

[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 

¿Cómo puedo resolver este problema?

ACTUALIZACIÓN: He comenzado a trabajar en este proyecto en particular de nuevo, y parece que todavía no he resuelto este problema.

El problema real es que el archivo write.lock no se elimina después de que finalice el uso del índice. En base a la respuesta que he aceptado, entiendo la lógica de implementación básica, pero no estoy seguro de haberla implementado correctamente. Aquí hay algunos otros métodos en mi clase que probablemente sean inválidos:

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

¿Alguna idea?

Respuesta

9

La razón por la que esto ocurre es que el escritor crea un archivo vacío llamado write.lock como un bloqueo de proceso cruzado. Cuando ese archivo existe, Lucene supone que alguien tiene un bloqueo de escritura en ese directorio.

Cuando finaliza su proceso incorrectamente, el archivo no se eliminará. Entonces Lucene piensa que alguien todavía está agarrado a la cerradura. Es por eso que siempre debe tener una declaración finally que cierra el índice.

Si está seguro de que el archivo está allí por error (es decir, no se están ejecutando los procesos de Lucene), puede simplemente eliminar el archivo. Sin embargo, su índice puede estar en un estado dañado, ya que la escritura fue terminada obviamente a mitad de camino.

+0

¡Gracias por su respuesta! Mi IndexWriter estático nunca se cierra realmente ... ¿es eso un problema? –

+0

@Maxim: la única razón por la que sería un problema es si varios procesos necesitan escribir. De lo contrario, generalmente es mejor mantener el escritor abierto y dejar que Lucene decida cuándo vaciar el disco. – Xodarap

+0

@ Xodarap: He comenzado a trabajar de nuevo en este proyecto, y todavía no he resuelto el problema por completo. Estoy a punto de actualizar la pregunta con parte del código que estoy usando. Entiendo la lógica de implementación básica, pero no estoy seguro de haberlo implementado correctamente. –

2

Parece ser un bloqueo muerto en lucene.

Si supuestamente NO hay actualización de índice en la colección,
simplemente elimine este archivo de bloqueo C:\Users\Username\Desktop\SiteSolution\Site\lucene\write.lock.

Después de eso, vuelva a ejecutar la escritura del índice.

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

Este código no se compila. El constructor de DirectoryInfo toma una cadena, no el objeto AzureDirectory. Quizás me estoy perdiendo algo. –

+0

Si pasa la cadena de ruta de ubicación de índice en lugar del directorio a DirectoryInfo(), este código funciona. –

0

investigando este mismo parece que el enfoque indentado sería utilizar varios índices físicos y luego combinarlos usando .addIndexesNoOptimize o .addIndexes del IndexWriter fusionar todos los cambios de índice concurrentes.

Lucene documentation

0

no ha comprobado yo mismo, pero no habría este trabajo (escribir después de crear el objeto azureDirectory)?

azureDirectory.ClearLock("write.lock") 
0

Tuve el mismo problema y estaba usando un IProviderContext. En mi caso tuve que: Optimizar, comprometer y desechar el ProviderContext.

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

Espero que esto ayude. Después de implementar el fragmento anterior, mi índice se reconstruyó correctamente.

Cuestiones relacionadas