vb.net - ¿Cómo actualizar un índice Lucene.NET?
indexing (7)
Estoy desarrollando un motor de búsqueda de escritorio en Visual Basic 9 (VS2008) usando Lucene.NET (v2.0).
Uso el siguiente código para inicializar IndexWriter
Private writer As IndexWriter
writer = New IndexWriter(indexDirectory, New StandardAnalyzer(), False)
writer.SetUseCompoundFile(True)
Si selecciono dos veces la misma carpeta de documentos (que contiene los archivos para indexar), se crean dos entradas diferentes para cada archivo en esa carpeta de documentos.
Quiero que IndexWriter descarte cualquier archivo que ya esté presente en el índice.
¿Qué debo hacer para asegurar esto?
Para actualizar un índice de lucene, necesita eliminar la entrada anterior y escribir en la nueva entrada. Por lo tanto, debe usar un IndexReader para buscar el elemento actual, usar el escritor para eliminarlo y luego agregar su nuevo elemento. Lo mismo sucederá con las entradas múltiples, que creo que es lo que está tratando de hacer. Solo encuentre todas las entradas, elimínelas todas y luego escriba las nuevas entradas.
Si desea eliminar todo el contenido del índice y volver a llenarlo, puede usar esta declaración
writer = New IndexWriter(indexDirectory, New StandardAnalyzer(), True)
El último parámetro del constructor IndexWriter determina si se crea un nuevo índice o si se abre un índice existente para agregar nuevos documentos.
Como mencionó Steve, necesita usar una instancia de IndexReader y llamar a su método DeleteDocuments. DeleteDocuments acepta una instancia de un objeto Término o el id. Interno de Lucene del documento (generalmente no se recomienda usar el Id. Interno como puede y cambiará cuando Lucene fusione segmentos).
La mejor manera es usar un identificador único que haya almacenado en el índice específico de su aplicación. Por ejemplo, en un índice de pacientes en un consultorio médico, si tiene un campo llamado "patient_id", puede crear un término y pasarlo como argumento para DeleteDocuments. Vea el siguiente ejemplo (lo siento, C #):
int patientID = 12;
IndexReader indexReader = IndexReader.Open( indexDirectory );
indexReader.DeleteDocuments( new Term( "patient_id", patientID ) );
Luego, podría agregar nuevamente la historia del paciente con una instancia de IndexWriter. Aprendí mucho de este artículo http://www.codeproject.com/KB/library/IntroducingLucene.aspx .
Espero que esto ayude.
A menos que solo esté modificando una pequeña cantidad de documentos (digamos, menos del 10% del total) es casi seguro más rápido (su millaje puede variar según los campos almacenados / indexados, etc.) para reindexar desde cero.
Dicho esto, siempre indexaría un directorio temporal, y luego movería el nuevo en su lugar cuando esté listo. De esta forma, hay poco tiempo de inactividad mientras se construye el índice, y si algo sale mal, aún tiene un buen índice.
Hay muchos ejemplos desactualizados al eliminar con un campo de id. El siguiente código funcionará con Lucene.NET 2.4.
No es necesario abrir un IndexReader si ya está usando un IndexWriter o para acceder a IndexSearcher.Reader. Puede usar IndexWriter.DeleteDocuments (Término), pero la parte difícil es asegurarse de que haya almacenado su campo de identificación correctamente en primer lugar. Asegúrese y use Field.Index.NOT_ANALYZED como la configuración de índice en su campo de identificación al almacenar el documento. Esto indexa el campo sin tokenizarlo, lo cual es muy importante, y ninguno de los otros valores de Field.Index funcionará cuando se use de esta manera:
IndexWriter writer = new IndexWriter("/MyIndexFolder", new StandardAnalyzer());
var doc = new Document();
var idField = new Field("id", "MyItemId", Field.Store.YES, Field.Index.NOT_ANALYZED);
doc.Add(idField);
writer.AddDocument(doc);
writer.Commit();
Ahora puede eliminar o actualizar fácilmente el documento con el mismo escritor:
Term idTerm = new Term("id", "MyItemId");
writer.DeleteDocuments(idTerm);
writer.Commit();
Una opción es, por supuesto, eliminar un documento y luego agregar la versión actualizada del documento.
Alternativamente, también puede usar el método UpdateDocument () de la clase IndexWriter:
writer.UpdateDocument(new Term("patient_id", document.Get("patient_id")), document);
Esto, por supuesto, requiere que tenga un mecanismo mediante el cual pueda ubicar el documento que desea actualizar ("patient_id" en este ejemplo).
He blogueado más detalles con un ejemplo de código fuente más completo .
Hay opciones, enumeradas a continuación, que se pueden usar según los requisitos.
Vea a continuación el complemento del código. [Código fuente en C #, por favor conviértalo en vb.net]
Lucene.Net.Documents.Document doc = ConvertToLuceneDocument(id, data);
Lucene.Net.Store.Directory dir = Lucene.Net.Store.FSDirectory.Open(new DirectoryInfo(UpdateConfiguration.IndexTextFiles));
Lucene.Net.Analysis.Analyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29);
Lucene.Net.Index.IndexWriter indexWriter = new Lucene.Net.Index.IndexWriter(dir, analyzer, false, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
Lucene.Net.Index.Term idTerm = new Lucene.Net.Index.Term("id", id);
foreach (FileInfo file in new DirectoryInfo(UpdateConfiguration.UpdatePath).EnumerateFiles())
{
Scenario 1: Single step update.
indexWriter.UpdateDocument(idTerm, doc, analyzer);
Scenario 2: Delete a document and then Update the document
indexWriter.DeleteDocuments(idTerm);
indexWriter.AddDocument(doc);
Scenario 3: Take necessary steps if a document does not exist.
Lucene.Net.Index.IndexReader iReader = Lucene.Net.Index.IndexReader.Open(indexWriter.GetDirectory(), true);
Lucene.Net.Search.IndexSearcher iSearcher = new Lucene.Net.Search.IndexSearcher(iReader);
int docCount = iSearcher.DocFreq(idTerm);
iSearcher.Close();
iReader.Close();
if (docCount == 0)
{
//TODO: Take necessary steps
//Possible Step 1: add document
//indexWriter.AddDocument(doc);
//Possible Step 2: raise the error for the unknown document
}
}
indexWriter.Optimize();
indexWriter.Close();