| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.search.lucene.best-practice">
- <title>Die besten Anwendungen</title>
- <sect2 id="zend.search.lucene.best-practice.field-names">
- <title>Feldnamen</title>
- <para>
- Es gibt keine Begrenzungen für Feldnamen in <classname>Zend_Search_Lucene</classname>.
- </para>
- <para>
- Trotzdem ist es eine gute Idee die '<emphasis>id</emphasis>' und
- '<emphasis>score</emphasis>' Namen nicht zu verwenden um Doppeldeutigkeiten in den Namen
- der <classname>QueryHit</classname> Eigenschaften zu verhindern.
- </para>
- <para>
- Die <classname>Zend_Search_Lucene_Search_QueryHit</classname> <property>id</property>
- und <property>score</property> Eigenschaften referieren immer zur internen Lucene
- Dokumenten Id und Treffer- <link
- linkend="zend.search.lucene.searching.results-scoring">Anzahl</link>. Wenn ein
- indiziertes Dokument die gleichen Felder gespeichert hat, muß die
- <methodname>getDocument()</methodname> Methode verwendet werden um auf Sie zuzugreifen:
- </para>
- <programlisting language="php"><![CDATA[
- $hits = $index->find($query);
- foreach ($hits as $hit) {
- // Das 'title' Dokumentfeld erhalten
- $title = $hit->title;
- // Das 'contents' Dokumentfeld erhalten
- $contents = $hit->contents;
- // Die interne Lucene Dokument ID erhalten
- $id = $hit->id;
- // Die Anzahl der Abfragetreffer erhalten
- $score = $hit->score;
- // Das 'id' Dokumentfeld erhalten
- $docId = $hit->getDocument()->id;
- // Das 'score' Dokumentfeld erhalten
- $docId = $hit->getDocument()->score;
- // Ein anderer Weg um das 'title' Dokumentfeld zu erhalten
- $title = $hit->getDocument()->title;
- }
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.indexing-performance">
- <title>Geschwindigkeit von Indezes</title>
- <para>
- Die Geschwindigkeit von Indezes ist ein Kompromiss zwischen verwendeten Ressourcen, der
- Zeit für das Indizieren und die Qualität des Index.
- </para>
- <para>
- Die Qualität des Index wird komplett eruiert durch die Anzahl an Indexsegmenten.
- </para>
- <para>
- Jedes Indexsegment ist ein komplett unabhängiger Teil von Daten. Deshalb benötigt ein
- Index der mehr Segmente hat, auch mehr Speicher und mehr Zeit für das Suchen.
- </para>
- <para>
- Indexoptimierung ist ein Prozess der mehrere Segmente in ein neues zusammenfügt. Ein
- komplett optimierter Index enthält nur ein Segment.
- </para>
- <para>
- Komplette Indexoptimierung kann mit der <methodname>optimize()</methodname> Methode
- durchgeführt werden:
- </para>
- <programlisting language="php"><![CDATA[
- $index = Zend_Search_Lucene::open($indexPath);
- $index->optimize();
- ]]></programlisting>
- <para>
- Index Optimierung arbeitet mit Daten Streams und benötigt nicht viel Speicher dafür aber
- Prozessorzessourcen und Zeit.
- </para>
- <para>
- Lucene Index Segmente sind nicht aktualisierbar durch Ihre Natur (eine Aktualisierung
- erfordert das die Segment Datei komplett neu geschrieben wird). Deshalb erzeugt das
- Hinzufügen neuer Dokumente zu einem Index auch immer ein neues Segment. Das verkleinert
- natürlich die Qualität des Index.
- </para>
- <para>
- Der automatische Optimierungsprozess des Index wird nach jeder Erstellung eines Segments
- durchgeführt und besteht darin das Teilsegmente zusammengeführt werden.
- </para>
- <para>
- Es gibt drei Optionen um das Verhalten der automatischen Optimierung zu beeinflussen
- (siehe das Kapitel <link linkend="zend.search.lucene.index-creation.optimization">Index
- Optimierung</link>):
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>MaxBufferedDocs</emphasis> ist die Anzahl an Dokumenten die im
- Speicher gepuffert werden bevor ein neues Segment erstellt und auf die
- Festplatte geschrieben wird.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>MaxMergeDocs</emphasis> ist die maximale Anzahl an Dokumenten die
- durch den automatischen Optimierungsprozess in ein neues Segment
- zusamengeführt werden.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>MergeFactor</emphasis> ermittelt wie oft die automatische
- Optimierung durchgeführt wird.
- </para>
- </listitem>
- </itemizedlist>
- <note>
- <para>
- Alle diese Optionen sind Objekteigenschaften von
- <classname>Zend_Search_Lucene</classname>, aber keine Indexeigenschaften. Sie
- beeinflussen nur das Verhalten des aktuellen
- <classname>Zend_Search_Lucene</classname> Objekts und können sich für
- verschiedene Skripte unterscheiden.
- </para>
- </note>
- </para>
- <para>
- <emphasis>MaxBufferedDocs</emphasis> hat keinen Effekt wenn nur ein Dokument pro
- Skriptausführung indiziert wird. Auf der anderen Seite ist das sehr wichtig für die
- Indizierung per Batch. Größere Werte erhöhen die Geschwindigkeit des Indizierens,
- benötigen aber auch mehr Speicher.
- </para>
- <para>
- Es gibt einfach keinen Weg um den besten Wert für den
- <emphasis>MaxBufferedDocs</emphasis> Parameter zu berechnen weil es von der
- durchschnittlichen Größe des Dokuments abhängt, dem verwendeten Analysator und dem
- erlaubten Speicher.
- </para>
- <para>
- Ein guter Weg um den richtigen Wert herauszufinden, ist die Durchführung von
- verschiedenen Tests mit den größten Dokumenten von denen man erwartet das Sie indiziert
- werden.
- <footnote>
- <para>
- <methodname>memory_get_usage()</methodname> und
- <methodname>memory_get_peak_usage()</methodname> können verwendet werden um die
- Verwendung des Speichers zu kontrollieren.
- </para>
- </footnote>
- Es ist eine gute Praxis nicht mehr als die Hälfte des erlaubten Speichers zu verwenden.
- </para>
- <para>
- <emphasis>MaxMergeDocs</emphasis> limitiert die Größe des Segments (in Dokumenten).
- Es begrenzt also die Zeit für die automatische Optimierung indem es garantiert das die
- <methodname>addDocument()</methodname> Methode nur eine bestimmte Anzahl oft ausgeführt
- wird. Das ist für interaktive Anwendungen sehr wichtig.
- </para>
- <para>
- Das Verkleinern des <emphasis>MaxMergeDocs</emphasis> Parameters kann auch die
- Geschwindigkeit des Batchinzieierens beeinflussen. Automatische Optimierung des Index
- ist ein iterativer Prozess und wird Schritt für Schritt durchgeführt. Kleine Segmente
- werden in größere zusammengeführt, und irgendwann werden Sie in sogar noch größere
- zusammengeführt und so weiter. Komplette Optimierung des Index wird durchgeführt wenn
- nur mehr ein großes Segment überbleibt.
- </para>
- <para>
- Kleinere Segmente verkleinern generell die Qualität des Index. Viele kleine Segmente
- können auch zu einem "Too many open files" Fehler führen, ausgelöst durch die
- Beschränkungen des Betriebsystems.
- <footnote>
- <para>
- <classname>Zend_Search_Lucene</classname> hält jedes Segment offen um die
- Geschwindigkeit des Suchens zu erhöhen.
- </para>
- </footnote>
- </para>
- <para>
- Generell sollte die Optimierung des Index für einen interaktiven Modus des Indizierens
- im Hintergrund durchgeführt werden und <emphasis>MaxMergeDocs</emphasis> sollte für die
- nicht zu klein für die Indizierung per Batch sein.
- </para>
- <para>
- <emphasis>MergeFactor</emphasis> beeinflußt die Frequenz der automatischen Optimierung.
- Kleinere Werte erhöhen die Qualität des nicht optimierten Index. Größere Werte erhöhen
- die Geschwindigkeit des Indizierens, aber auch die Anzahl an Segmenten. Das wiederum
- kann wieder zu einem "Too many open files" Fehler führen.
- </para>
- <para>
- <emphasis>MergeFactor</emphasis> gruppiert Indexsegmente anhand Ihrer Größe:
- <orderedlist>
- <listitem>
- <para>
- Nicht größer als <emphasis>MaxBufferedDocs</emphasis>.
- </para>
- </listitem>
- <listitem>
- <para>
- Größer als <emphasis>MaxBufferedDocs</emphasis>, aber nicht größer als
- <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis>.
- </para>
- </listitem>
- <listitem>
- <para>
- Größer als
- <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis>, aber
- nicht größer als
- <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis>*<emphasis>MergeFactor</emphasis>.
- </para>
- </listitem>
- <listitem>
- <para>...</para>
- </listitem>
- </orderedlist>
- </para>
- <para>
- <classname>Zend_Search_Lucene</classname> prüft während jedem Aufruf von
- <methodname>addDocument()</methodname> ob das Zusammenführen von Segmentgruppen dazu
- führt das neu erstellte Segmente in die nächste Gruppe verschoben werden. Wenn ja, wird
- das Zusammenführen durchgeführt.
- </para>
- <para>
- Also kann ein Index mit N Gruppen
- <emphasis>MaxBufferedDocs</emphasis> + (N-1)*<emphasis>MergeFactor</emphasis> Segmente
- und zumindest
- <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis><superscript>(N-1)</superscript>
- Dokumente enthalten.
- </para>
- <para>
- Das gibt eine gute Annäherung für die Anzahl an Segmenten im Index:
- </para>
- <para>
- <emphasis>NumberOfSegments</emphasis> <= <emphasis>MaxBufferedDocs</emphasis> +
- <emphasis>MergeFactor</emphasis>*log
- <subscript><emphasis>MergeFactor</emphasis></subscript>
- (<emphasis>NumberOfDocuments</emphasis>/<emphasis>MaxBufferedDocs</emphasis>)
- </para>
- <para>
- <emphasis>MaxBufferedDocs</emphasis> wird durch den erlaubten Speicher eruiert. Das
- erlaubt es dem gewünschten Faktor für das Zusammenführen eine erwünschte Anzahl an
- Segmenten zu erhalten.
- </para>
- <para>
- Das Tunen des <emphasis>MergeFactor</emphasis> Parameters ist effektiver für die
- Geschwindigkeit der Indizierens per Batch als <emphasis>MaxMergeDocs</emphasis>. Aber es
- ist auch gröber. Deshalb sollte die obige Annäherung für das Tunen des
- <emphasis>MergeFactor</emphasis>'s verwendet werden und anschließend mit
- <emphasis>MaxMergeDocs</emphasis> herumgespielt werden um die beste Geschwindigkeit für
- die Indizieren per Batch zu erhalten.
- </para>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.shutting-down">
- <title>Index während des Herunterfahrens</title>
- <para>
- Die <classname>Zend_Search_Lucene</classname> Instanz führt einiges an Arbeit während
- des Herunterfahrens durch, wenn Dokumente zum Index hinzugefügt aber nicht in ein neues
- Segment geschrieben wurden.
- </para>
- <para>
- Das kann auch einen automatischen Optimierungsprozess anwerfen.
- </para>
- <para>
- Das Indexobjekt wird automatisch geschlossen wenn es, und alle zurückgegebenen QueryHit
- Objekte, ausserhalb des Sichtbereichs sind.
- </para>
- <para>
- Wenn das Indexobjekt in einer globalen Variable gespeichert wird, wird es nur am Ende
- der Skriptausführung zerstört
- <footnote>
- <para>
- Das kann auch vorkommen wenn der Index oder die QueryHit Instanzen in zyklischen
- Datenstrukturen referenziert werden, weil <acronym>PHP</acronym> Objekte mit
- zyklischen Referenzen nur am Ende der Skriptausführung beseitigt.
- </para>
- </footnote>.
- </para>
- <para>
- Die Behandlung von <acronym>PHP</acronym> Ausnahmen wird in diesem Moment auch
- Herunterfahren.
- </para>
- <para>
- Das beeinflußt den normalen Shutdown Prozess des Index nicht, kann aber eine akurate
- Diagnostik von Fehlern verhindern wenn ein Fehler während des herunterfahrens
- stattfindet.
- </para>
- <para>
- Es gibt zwei Wege mit denen dieses Problem verhindert werden kann.
- </para>
- <para>
- Der erste ist, dass das Herausgehen aus dem Sichtbereich erzwungen wird:
- </para>
- <programlisting language="php"><![CDATA[
- $index = Zend_Search_Lucene::open($indexPath);
- ...
- unset($index);
- ]]></programlisting>
- <para>
- Und der zweite ist, das eine commit Operation vor dem Ausführungsende des Skripts
- durchgeführt wird:
- </para>
- <programlisting language="php"><![CDATA[
- $index = Zend_Search_Lucene::open($indexPath);
- $index->commit();
- ]]></programlisting>
- <para>
- Diese Möglichkeit wird auch im Kapitel "<link
- linkend="zend.search.lucene.advanced.static">Fortgeschrittene Verwendung von Indezes
- als statische Eigenschaften</link>" beschrieben.
- </para>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.unique-id">
- <title>Dokumente anhand der eindeutigen Id erhalten</title>
- <para>
- Eine übliche Praxis ist es eindeutige Dokument Id's im Index zu speichern. Beispiele
- beinhalten URL, Pfad, Datenbank Id.
- </para>
- <para>
- <classname>Zend_Search_Lucene</classname> bietet eine
- <methodname>termDocs()</methodname> Methode um Dokumente zu empfangen die spezielle
- Terme enthalten.
- </para>
- <para>
- Das ist effizienter als die Verwendung der <methodname>find()</methodname> Methode:
- </para>
- <programlisting language="php"><![CDATA[
- // Dokumente mit find() empfangen durch verwenden eines Abfragestrings
- $query = $idFieldName . ':' . $docId;
- $hits = $index->find($query);
- foreach ($hits as $hit) {
- $title = $hit->title;
- $contents = $hit->contents;
- ...
- }
- ...
- // Dokumente mit der find() Methode empfangen durch verwenden der Anfrage API
- $term = new Zend_Search_Lucene_Index_Term($docId, $idFieldName);
- $query = new Zend_Search_Lucene_Search_Query_Term($term);
- $hits = $index->find($query);
- foreach ($hits as $hit) {
- $title = $hit->title;
- $contents = $hit->contents;
- ...
- }
- ...
- // Dokumente mit der termDocs() Methode empfangen
- $term = new Zend_Search_Lucene_Index_Term($docId, $idFieldName);
- $docIds = $index->termDocs($term);
- foreach ($docIds as $id) {
- $doc = $index->getDocument($id);
- $title = $doc->title;
- $contents = $doc->contents;
- ...
- }
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.memory-usage">
- <title>Speicherverwendung</title>
- <para>
- <classname>Zend_Search_Lucene</classname> ist ein relativ speicherintensives Modul.
- </para>
- <para>
- Es verwendet Speicher um Informationen zu Cachen, das Suchen zu optimieren und das
- Indizieren zu beschleunigen.
- </para>
- <para>
- Der benötigte Speicher ist für unterschiedliche Modi verschieden.
- </para>
- <para>
- Der Verzeichnisindex der Ausdrücke wird während der Suche geladen. Das ist aktuelle
- jeder 128 <superscript>te</superscript> Ausdruck des kompletten Verzeichnisses.
- <footnote>
- <para>
- Das Lucene Dateiformat erlaubt es diese Zahl zu ändern, aber
- <classname>Zend_Search_Lucene</classname> bietet keine Möglichkeit das über
- seine <acronym>API</acronym> durchzuführen. Trotzdem gibt es die Möglichkeit
- diesen Wert zu ändern wenn er mit einer anderen Lucene Implementation
- vorbereitet wird.
- </para>
- </footnote>
- </para>
- <para>
- Deswegen ist der Speicherverbrauch erhöht wenn man eine große Anzahl an eindeutigen
- Ausdrücke hat. Das kann passieren wenn man ungeteilte Phrasen als Feld Werte verwendet,
- oder ein großes Volumen von nicht-textuellen Informationen hat.
- </para>
- <para>
- Ein nicht optimierter Index besteht aus verschiedenen Segmenten. Er erhöht auch den
- Speicherverbrauch. Segmente sind voneinander unabhängig, sodas jedes Segment sein
- eigenes Verzeichnis an Ausdrücken enthält und den Verzeichnisindex der Ausdrücke. Wenn
- der Index aus <emphasis>N</emphasis> Segmenten besteht kann der Speicherverbrauch im
- schlimmsten Fall <emphasis>N</emphasis> mal so groß sein. Eine Optimierung des Index
- kann durchgeführt werden um alle Segmente in eines zusammenzuführen um diesen
- Speicherverbrauch zu verhindern.
- </para>
- <para>
- Indizierung verwendet den gleichen Speicher wie das Suchen und zusätzlich Speicher für
- das Puffern von Dokumenten. Die Größe des Speichers der hierfür verwendet wird kann mit
- dem <emphasis>MaxBufferedDocs</emphasis> Parameter verwaltet werden.
- </para>
- <para>
- Index Optimierung (komplett oder teilweise) verwendet stream-artiges Bearbeiten von
- Daten und benötigt nicht viel Speicher.
- </para>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.encoding">
- <title>Verschlüsselung</title>
- <para>
- <classname>Zend_Search_Lucene</classname> arbeitet intern mit UTF-8 Strings. Das
- bedeutet also das alle von <classname>Zend_Search_Lucene</classname> zurückgegebenen
- Strings UTF-8 verschlüsselt sind.
- </para>
- <para>
- Man sollte sich keine Gedanken über Verschlüsselung machen solange man mit reinen
- <acronym>ASCII</acronym> Daten arbeitet, sollte aber vorsichtig sein wenn das nicht der
- Fall ist.
- </para>
- <para>
- Eine falsche Verschlüsselung kann Fehlernotizen während der Konvertierung oder den
- Verlust von Daten verursachen.
- </para>
- <para>
- <classname>Zend_Search_Lucene</classname> bietet einen breite Palette von Möglichkeiten
- für die Verschlüsselung von indizierten Dokumenten und analysierten Abfragen.
- </para>
- <para>
- Verschlüsselung kann explizit als optionaler Parameter bei den Felderstellung Methoden
- spezifiziert werden:
- </para>
- <programlisting language="php"><![CDATA[
- $doc = new Zend_Search_Lucene_Document();
- $doc->addField(Zend_Search_Lucene_Field::Text('title',
- $title,
- 'iso-8859-1'));
- $doc->addField(Zend_Search_Lucene_Field::UnStored('contents',
- $contents,
- 'utf-8'));
- ]]></programlisting>
- <para>
- Das ist der beste Weg um Problemen bei der verwendeten Verschlüsselung vorzubeugen.
- </para>
- <para>
- Wenn der optionale Parameter der Verschlüsselung unterdrückt wird, wird das aktuelle
- Gebietsschema verwendet. Das aktuelle Gebietsschema kann Daten zur
- Zeichenverschlüsselung, zusätzlich zur Spezifikation der Sprache, enthalten.
- </para>
- <programlisting language="php"><![CDATA[
- setlocale(LC_ALL, 'fr_FR');
- ...
- setlocale(LC_ALL, 'de_DE.iso-8859-1');
- ...
- setlocale(LC_ALL, 'ru_RU.UTF-8');
- ...
- ]]></programlisting>
- <para>
- Der selbe Weg wird verwendet um die Verschlüsselung beim Abfragestring zu setzen.
- </para>
- <para>
- Wenn die Verschlüsselung nicht definiert wird, wird das aktuelle Gebietsschema verwendet
- um die Verschlüsselung zu ermitteln.
- </para>
- <para>
- Verschlüsselung kann als optionaler Parameter übergeben werden, wenn die Abfrage
- explizit vor der Suche geparsed wird:
- </para>
- <programlisting language="php"><![CDATA[
- $query =
- Zend_Search_Lucene_Search_QueryParser::parse($queryStr, 'iso-8859-5');
- $hits = $index->find($query);
- ...
- ]]></programlisting>
- <para>
- Die Standardverschlüsselung kann auch mit der
- <methodname>setDefaultEncoding()</methodname> Methode spezifiziert werden:
- </para>
- <programlisting language="php"><![CDATA[
- Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('iso-8859-1');
- $hits = $index->find($queryStr);
- ...
- ]]></programlisting>
- <para>
- Ein leerer String impliziert das 'aktuelle Gebietsschema'.
- </para>
- <para>
- Wenn die richtige Verschlüsselung spezifiziert wurde, kann Sie vom Analysator richtig
- bearbeitet werden. Das aktuelle Verhalten hängt vom verwendeten Analysator ab. Siehe
- das Kapitel <link linkend="zend.search.lucene.charset">Zeichensatz</link> der
- Dokumentation für Details.
- </para>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.maintenance">
- <title>Index Wartung</title>
- <para>
- Es sollte klar sein das <classname>Zend_Search_Lucene</classname>, genauso wie jede
- andere Lucene Implementation, keine "Datenbank" ersetzt.
- </para>
- <para>
- Indizes sollten nicht als Datenspeicher verwendet werden. Sie bieten keine partiellen
- Backup/Wiederherstellungs Funktionen, Journal, Logging, Transactions und viele
- andere Features die mit Datenbank Management Systemen assoziiert werden.
- </para>
- <para>
- Trotzdem versucht <classname>Zend_Search_Lucene</classname> Indizes jederzeit in einem
- gültigen Status zu halten.
- </para>
- <para>
- Index Backup/Wiederherstellung sollte durch Kopieren des Inhalts des Index
- Verzeichnisses durchgeführt werden.
- </para>
- <para>
- Wenn der Index durch irgendeinen Grund beschädigt wird, sollte der beschädigte Index
- wiederhergestellt oder komplett neu gebaut werden.
- </para>
- <para>
- Es ist also eine gute Idee von großen Indizes ein Backup zu machen und ein Änderungslog
- zu speichern um manuelle Wiederherstellung + Roll-Forward Operationen durchzuführen wenn
- es notwendig ist. Diese Praxis reduziert die Wiederherstellungszeit des Index
- dramatisch.
- </para>
- </sect2>
- </sect1>
|