Как обновить индекс Lucene.NET?
Я разрабатываю Desktop Search Engine в Visual Basic 9 (VS2008) с помощью Lucene.NET(v2.0).
Я использую следующий код для инициализации IndexWriter
Private writer As IndexWriter
writer = New IndexWriter(indexDirectory, New StandardAnalyzer(), False)
writer.SetUseCompoundFile(True)
Если я дважды выбираю одну и ту же папку документа (содержащую файлы для индексирования), в индексе создаются две разные записи для каждого файла в этой папке.
Я хочу, чтобы IndexWriter удалял любые файлы, которые уже присутствуют в индексе.
Что мне делать, чтобы обеспечить это?
Ответы
Ответ 1
Чтобы обновить индекс lucene, вам нужно удалить старую запись и записать ее в новую запись. Поэтому вам нужно использовать IndexReader для поиска текущего элемента, использовать запись для его удаления, а затем добавить новый элемент. То же самое будет верно для нескольких записей, которые, как я думаю, вы пытаетесь сделать. Просто найдите все записи, удалите их все и затем напишите в новых записях.
Ответ 2
Как сказал Стив, вам нужно использовать экземпляр IndexReader и вызвать его метод DeleteDocuments. DeleteDocuments принимает либо экземпляр объекта Term, либо внутренний идентификатор Lucene документа (обычно не рекомендуется использовать внутренний идентификатор, как он может и будет меняться по мере того, как Lucene объединяет сегменты).
Лучший способ - использовать уникальный идентификатор, который вы сохранили в индексе, специфичном для вашего приложения. Например, в указателе пациентов в офисе врача, если у вас есть поле под названием "patient_id", вы можете создать термин и передать это как аргумент DeleteDocuments. См. Следующий пример (извините, С#):
int patientID = 12;
IndexReader indexReader = IndexReader.Open( indexDirectory );
indexReader.DeleteDocuments( new Term( "patient_id", patientID ) );
Затем вы можете добавить запись пациента снова с экземпляром IndexWriter. Я многому научился из этой статьи http://www.codeproject.com/KB/library/IntroducingLucene.aspx.
Надеюсь, что это поможет.
Ответ 3
Есть много устаревших примеров при удалении с полем id. Код ниже будет работать с Lucene.NET 2.4.
Не нужно открывать IndexReader, если вы уже используете IndexWriter или обращаетесь к IndexSearcher.Reader. Вы можете использовать IndexWriter.DeleteDocuments(Term), но сложная часть - убедиться, что вы правильно сохранили свое поле идентификатора. Обязательно используйте Field.Index.NOT_ANALYZED как параметр индекса в поле id при хранении документа. Это индексирует поле без его токенизации, что очень важно, и ни одно из других значений Field.Index не будет работать при использовании этого способа:
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();
Теперь вы можете легко удалить или обновить документ с помощью одного и того же автора:
Term idTerm = new Term("id", "MyItemId");
writer.DeleteDocuments(idTerm);
writer.Commit();
Ответ 4
Если вы хотите удалить весь контент в индексе и пополнить его, вы можете использовать этот оператор
writer = New IndexWriter(indexDirectory, New StandardAnalyzer(), True)
Последний параметр конструктора IndexWriter определяет, создается ли новый индекс или открыт ли существующий индекс для добавления новых документов,
Ответ 5
Есть варианты, перечисленные ниже, которые могут использоваться в соответствии с требованиями.
См. ниже привязку кода. [Исходный код на С#, пожалуйста, преобразуйте его в 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();
Ответ 6
Если вы только модифицируете небольшое количество документов (скажем, менее 10% от общего числа), это почти наверняка быстрее (ваш пробег может варьироваться в зависимости от сохраненных/индексированных полей и т.д.), чтобы переиндексировать с нуля.
Тем не менее, я всегда буду индексировать временный каталог, а затем переместить новый, когда это будет сделано. Таким образом, там небольшой простоя, пока индекс строится, и если что-то пойдет не так, у вас все еще есть хороший индекс.
Ответ 7
Одним из вариантов является, конечно, удаление документа, а затем добавление обновленной версии документа.
В качестве альтернативы вы также можете использовать метод UpdateDocument() класса IndexWriter:
writer.UpdateDocument(new Term("patient_id", document.Get("patient_id")), document);
Это, конечно, требует наличия механизма, с помощью которого вы можете найти документ, который хотите обновить ( "patient_id" в этом примере).
У меня блог более подробно с более полным примером исходного кода.