Das Schreiben in den Lucene-Index, ein Dokument nach dem anderen, verlangsamt sich im Laufe der Zeit

8

Wir haben ein Programm, das ständig läuft, verschiedene Dinge tut und einige Datensätze in unserer Datenbank ändert. Diese Datensätze werden mit Lucene indiziert. Jedes Mal, wenn wir eine Entität ändern, machen wir so etwas wie:

  1. Öffnen Sie die Transaktion db, öffnen Sie Lucene IndexWriter
  2. Nehmen Sie die Änderungen an der Datenbank in der Transaktion vor und aktualisieren Sie diese Entität in Lucene mithilfe von indexWriter.deleteDocuments(..) und dann indexWriter.addDocument(..) .
  3. Wenn alles gut gegangen ist, übergeben Sie die db-Transaktion und übergeben Sie den IndexWriter.

Das funktioniert gut, aber im Laufe der Zeit benötigt indexWriter.commit() immer mehr Zeit. Anfangs dauert es ungefähr 0,5 Sekunden, aber nach ein paar hundert solcher Transaktionen dauert es mehr als 3 Sekunden. Ich bezweifle nicht, dass es noch länger dauern würde, wenn das Skript länger laufen würde.

Meine bisherige Lösung bestand darin, die indexWriter.addDocument(..) und indexWriter.commit() auskommentieren und den gesamten Index hin und wieder neu erstellen, indem Sie zuerst indexWriter.deleteAll() verwenden und dann alle Dokumente innerhalb einer Lucene-Transaktion / IndexWriter ( ungefähr 250k Dokumente in ungefähr 14 Sekunden). Dies widerspricht jedoch offensichtlich dem transaktionalen Ansatz von Datenbanken und Lucene, der beide synchron hält und die Aktualisierungen für die Benutzer unserer Tools, die mit Lucene suchen, für die Datenbank sichtbar macht.

Es ist merkwürdig, dass ich in 14 Sekunden 250.000 Dokumente hinzufügen kann, aber das Hinzufügen von 1 Dokument dauert 3 Sekunden. Was mache ich falsch, wie kann ich die Situation verbessern?

    
Adrian Smith 28.08.2015, 11:07
quelle

2 Antworten

11

Was Sie falsch machen, ist die Annahme, dass die integrierten Transaktionsfunktionen von Lucene Leistung haben und Garantien, die mit einer typischen relationalen Datenbank vergleichbar sind, wenn sie wirklich nicht . Genauer gesagt synchronisiert ein Commit in diesem Fall alle Indexdateien mit dem Datenträger, wodurch die Commit-Zeiten proportional zur Indexgröße sind. Deshalb benötigt Ihr indexWriter.commit() im Laufe der Zeit immer mehr Zeit. Die Javadoc für IndexWriter.commit() warnt sogar das:

  

Dies kann eine kostspielige Operation sein, also sollten Sie die Kosten in Ihrem testen   Anwendung und tun Sie es nur, wenn wirklich notwendig.

Können Sie sich eine Datenbank-Dokumentation vorstellen, die Sie auffordert, Commits zu vermeiden?

Da Ihr Hauptziel darin besteht, Datenbankupdates durch Lucene-Suchen zeitnah sichtbar zu halten, tun Sie Folgendes, um die Situation zu verbessern:

  1. Haben indexWriter.deleteDocuments(..) und indexWriter.addDocument(..) nach einem erfolgreichen Datenbank-Commit anstelle von
  2. ausgelöst
  3. Führen Sie indexWriter.commit() in regelmäßigen Abständen statt jeder Transaktion aus, nur um sicherzustellen, dass Ihre Änderungen letztendlich auf den Datenträger geschrieben werden
  4. Verwenden Sie ein SearcherManager zum Suchen und Aufrufen maybeRefresh() regelmäßig, um aktualisierte Dokumente anzuzeigen innerhalb eines angemessenen Zeitrahmens

Im folgenden Beispielprogramm wird gezeigt, wie Dokumentupdates abgerufen werden können, indem Sie maybeRefresh() regelmäßig ausführen. Es erstellt einen Index von 100000 Dokumenten, verwendet eine ScheduledExecutorService Um periodische Aufrufe von commit() und maybeRefresh() einzurichten, werden Sie aufgefordert, ein einzelnes Dokument zu aktualisieren. Anschließend wird wiederholt gesucht, bis das Update sichtbar ist. Alle Ressourcen werden beim Beenden des Programms ordnungsgemäß bereinigt. Beachten Sie, dass der steuernde Faktor für den Zeitpunkt, zu dem die Aktualisierung sichtbar wird, ist, wenn maybeRefresh() aufgerufen wird, nicht commit() .

%Vor%

Dieses Beispiel wurde erfolgreich mit Lucene 5.3.1 und JDK 1.8.0_66 getestet.

    
heenenee 06.12.2015, 10:51
quelle
3

Mein erster Ansatz: Begib dich nicht so oft. Wenn Sie ein Dokument löschen und erneut hinzufügen, wird wahrscheinlich eine Zusammenführung ausgelöst. Zusammenführungen sind etwas langsam.

Wenn Sie einen Fast-Real-Time-IndexReader verwenden, können Sie immer noch wie gewohnt suchen (es werden keine gelöschten Dokumente angezeigt), aber Sie erhalten keine Commit-Strafe. Sie können das Commit später durchführen, um sicherzustellen, dass das Dateisystem mit Ihrem Index übereinstimmt. Sie können dies während der Verwendung Ihres Indexes tun, damit Sie nicht alle anderen Operationen blockieren müssen.

Siehe auch diesen interessanten Blogeintrag (und tun Sie es Lesen Sie auch die anderen Beiträge, sie bieten großartige Informationen).

    
RobAu 28.08.2015 11:23
quelle

Tags und Links