Как обновить индекс 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" в этом примере).

У меня блог более подробно с более полным примером исходного кода.