2009-01-24 16 views
11

Ich entwickle eine Desktop-Suchmaschine in Visual Basic 9 (VS2008) mit Lucene.NET (v2.0).Wie aktualisiert man einen Lucene.NET Index?

Ich verwende den folgenden Code, um die Indexwriter

Private writer As IndexWriter 

writer = New IndexWriter(indexDirectory, New StandardAnalyzer(), False) 

writer.SetUseCompoundFile(True) 

zu initialisieren Wenn ich den gleichen Dokumentenordner (die Dateien indiziert werden) wählen Sie zweimal, zwei verschiedene Einträge für jede Datei in diesem Dokument Ordner werden in der erstellt Index.

Ich möchte, dass der IndexWriter alle Dateien verwirft, die bereits im Index vorhanden sind.

Was soll ich tun, um dies zu gewährleisten?

+0

Versuchen Sie, den Index jedes Mal von Grund auf neu zu erstellen, oder versuchen Sie, bestimmte Einträge im Index zu aktualisieren? Bitte klären Sie Ihre Frage. – itsadok

Antwort

4

Um einen Lucene-Index zu aktualisieren, müssen Sie den alten Eintrag löschen und in den neuen Eintrag schreiben. Sie müssen also einen IndexReader verwenden, um das aktuelle Objekt zu finden, verwenden Sie den Writer, um es zu löschen, und fügen Sie dann Ihr neues Objekt hinzu. Das Gleiche gilt für mehrere Einträge, von denen ich denke, dass Sie versuchen, dies zu tun. Suchen Sie einfach alle Einträge, löschen Sie sie alle und schreiben Sie dann die neuen Einträge.

+0

Könnten Sie mich auf eine Demo verweisen, die die Verwendung von IndexReader zeigt (um den aktuellen Eintrag zu finden) und um den Index zu aktualisieren? – user57175

+0

Dies scheint dazu zu führen, dass Dokumente fehlen, wenn ich die Suche erneut einsende – JsonStatham

5

Wenn Sie alle Inhalte im Index und füllen Sie ihn löschen möchten, können Sie diese Anweisung verwenden

writer = New IndexWriter(indexDirectory, New StandardAnalyzer(), True) 

Der letzte Parameter des IndexWriter constructor bestimmt, ob ein neuer Index erstellt wird, oder ob eine vorhandene Der Index wird für das Hinzufügen neuer Dokumente geöffnet.

+1

einfachste Antwort zum Löschen des Index beim Neuaufbau, thx – jcvandan

19

Wie Steve erwähnt, müssen Sie eine Instanz von IndexReader verwenden und die DeleteDocuments-Methode aufrufen. DeleteDocuments akzeptiert entweder eine Instanz eines Term-Objekts oder die interne Lucene-ID des Dokuments (es wird im Allgemeinen nicht empfohlen, die interne ID so zu verwenden, wie sie kann und wird sich ändern, wenn Lucene Segmente zusammenführt).

Der beste Weg ist die Verwendung eines eindeutigen Bezeichners, den Sie in dem für Ihre Anwendung spezifischen Index gespeichert haben. Wenn Sie beispielsweise in einem Patientenregister in einer Arztpraxis ein Feld namens "Patient_ID" hatten, könnten Sie einen Begriff erstellen und diesen als Argument an DeleteDocuments übergeben. Siehe das folgende Beispiel (sorry, C#):

int patientID = 12; 
IndexReader indexReader = IndexReader.Open(indexDirectory); 
indexReader.DeleteDocuments(new Term("patient_id", patientID)); 

Dann Sie die Patientenakte wieder mit einer Instanz von Indexwriter hinzufügen könnten. Ich habe viel aus diesem Artikel gelernt http://www.codeproject.com/KB/library/IntroducingLucene.aspx.

Hoffe, das hilft.

3

Es sei denn, Sie ändern nur eine kleine Anzahl von Dokumenten (sagen wir, weniger als 10% der Gesamtmenge) ist es fast sicher schneller (Ihre Laufleistung kann je nach gespeicherten/indizierten Feldern variieren), um von Grund auf neu zu indizieren.

Das gesagt, würde ich immer zu einem Temp-Verzeichnis indizieren, und dann das neue an Ort und Stelle verschieben, wenn es fertig ist. Auf diese Weise gibt es wenig Ausfallzeit während der Index aufgebaut wird, und wenn etwas schief geht, haben Sie immer noch einen guten Index.

11

Es gibt viele veraltete Beispiele zum Löschen mit einem ID-Feld. Der folgende Code funktioniert mit Lucene.NET 2.4.

Es ist nicht notwendig, einen IndexReader zu öffnen, wenn Sie bereits einen IndexWriter verwenden oder auf IndexSearcher.Reader zugreifen. Sie können IndexWriter.DeleteDocuments (Term) verwenden, aber der schwierige Teil besteht darin, sicherzustellen, dass Sie Ihr ID-Feld korrekt an erster Stelle gespeichert haben. Seien Sie sicher und verwenden Sie Field.Index.NOT_ANALYZED als Indexeinstellung für Ihr ID-Feld beim Speichern des Dokuments. Diese Indizes des Feld, ohne es zu Zeichenüber, was sehr wichtig ist, und keiner der anderen Field.Index Werte, wenn auf diese Weise benutzt arbeiten:

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

Jetzt können Sie ganz einfach löschen oder das Dokument mit dem gleichen Verfasser aktualisieren:

+1

Auch diese Signatur für IndexWriter ist jetzt veraltet (und wird in Lucene 3.0 entfernt). Der vorgeschlagene ctor wäre ein neuer IndexWriter (Verzeichnis, Analysator, maxFieldLength) und für den Analyzer ist die Signatur wieder veraltet. Vorgeschlagen wird ein neuer StandardAnalyzer (Version). – autonomatt

2

Eine Option ist natürlich, ein Dokument zu entfernen und dann die aktualisierte Version des Dokuments hinzuzufügen.

Alternativ können Sie auch die update() -Methode der Indexwriter-Klasse verwenden:

writer.UpdateDocument(new Term("patient_id", document.Get("patient_id")), document); 

Dies erfordert natürlich Sie einen Mechanismus haben, von dem Sie das Dokument suchen können Sie aktualisieren möchten („patient_id“ in diesem Beispiel).

Ich habe blogged more details with a more complete source code example.

4

Es gibt unten aufgelistete Optionen, die gemäß den Anforderungen verwendet werden können.

Siehe unten Code Snap. [Quellcode in C#, bitte in vb.net konvertieren]

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(); 
Verwandte Themen