| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.search.lucene.best-practice">
- <title>Bonnes pratiques</title>
- <sect2 id="zend.search.lucene.best-practice.field-names">
- <title>Nommage des champs</title>
- <para>
- Il n'y a pas de limitation pour les noms de champs dans
- <classname>Zend_Search_Lucene</classname>.
- </para>
- <para>
- Cependant, il est préférable de ne pas utiliser les noms '<emphasis>id</emphasis>'
- et '<emphasis>score</emphasis>' afin d'éviter toute ambiguïté dans les propriétés de
- <classname>QueryHit</classname>.
- </para>
- <para>
- Les propriétés <property>id</property> et <property>score</property> de
- <classname>Zend_Search_Lucene_Search_QueryHit</classname> font toujours référence à
- l'identifiant interne du document Lucene et au <link
- linkend="zend.search.lucene.searching.results-scoring">score</link> de hit. Si le
- document indexé possède les mêmes champs stockés, vous devrez utiliser la méthode
- <methodname>getDocument()</methodname> pour y accéder :<programlisting language="php"><![CDATA[
- $hits = $index->find($query);
- foreach ($hits as $hit) {
- // Récupérer le champ de document 'title'
- $title = $hit->title;
- // Récupérer le champ de document 'contents'
- $contents = $hit->contents;
- // Récupérer l'id interne du document Lucene
- $id = $hit->id;
- // Récupérer le score de hit
- $score = $hit->score;
- // Récupérer le champ de document 'id'
- $docId = $hit->getDocument()->id;
- // Récupérer le champ de document 'score'
- $docId = $hit->getDocument()->score;
- // Un autre moyen de récupérer le champ 'title'
- $title = $hit->getDocument()->title;
- }
- ]]></programlisting></para>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.indexing-performance">
- <title>Performance de l'indexation</title>
- <para>
- La performance de l'indexation est un compromis entre les ressources utilisées, le
- temps d'indexation et la qualité de l'index.
- </para>
- <para>
- La qualité de l'index est complètement déterminée par le nombre de segments de
- l'index.
- </para>
- <para>
- Chaque segment d'index et une portion de données entièrement indépendante. Ainsi
- plus un index contient de segments, plus il sera gourmand en mémoire et en temps de
- calcul lors de la recherche.
- </para>
- <para>
- L'optimisation d'index est un processus consistant à fusionner plusieurs segments
- en un seul nouveau segment. Un index totalement optimisé ne contient qu'un seul
- segment.
- </para>
- <para>
- L'optimisation complète de l'index peut être effectuée avec la méthode
- <methodname>optimize()</methodname> :<programlisting language="php"><![CDATA[
- $index = Zend_Search_Lucene::open($indexPath);
- $index->optimize();
- ]]></programlisting></para>
- <para>
- L'optimisation d'index fonctionne avec des "data streams" et ne consomme pas pas
- une grande quantité de mémoire, mais nécessite des ressources de processeur et du
- temps.
- </para>
- <para>
- Par nature, les segments d'index de Lucene ne peuvent pas être mis à jour
- (l'opération de mise à jour nécessite une réécriture complète du segment). Ainsi,
- l'ajout de nouveau(x) document(s) à un index implique toujours la génération d'un
- nouveau segment. De fait, cela dégrade la qualité de l'index.
- </para>
- <para>
- Une optimisation automatique d'un index est effectuée après chaque génération de
- segment et consiste en la fusion des segments partiels.
- </para>
- <para>
- Il y a trois options pour contrôler le comportement de l'auto-optimisation (voir
- la section <link linkend="zend.search.lucene.index-creation.optimization">Optimisation
- d'index</link>) :<itemizedlist>
- <listitem>
- <para>
- <emphasis>MaxBufferedDocs</emphasis> représente le nombre maximum de
- documents qui peuvent être mis en mémoire tampon avant qu'un nouveau segment
- soit généré et écrit sur le disque dur.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>MaxMergeDocs</emphasis> représente le nombre maximum de
- documents qui seront fusionnés dans un nouveau segment lors du processus
- d'auto-optimisation.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>MergeFactor</emphasis> détermine à quelle fréquence
- l'auto-optimisation est effectuée.
- </para>
- </listitem>
- </itemizedlist> <note>
- <para>
- Toutes ces options sont des propriétés de la classe
- <classname>Zend_Search_Lucene</classname>, pas des propriétés d'index. Elles
- n'affectent que les instances de <classname>Zend_Search_Lucene</classname> et
- peuvent varier selon les scripts.
- </para>
- </note>
- </para>
- <para>
- <emphasis>MaxBufferedDocs</emphasis> n'a aucun effet si vous n'indexez qu'un seul
- document par exécution de script. En revanche, il est très important pour les
- indexations massives ("batch indexing"). Plus sa valeur est élevée, meilleures seront
- les performances d'indexation, mais plus la consommation de mémoire sera
- importante.
- </para>
- <para>
- Il n'existe pas de manière simple de calculer la meilleure valeur pour le
- paramètre <emphasis>MaxBufferedDocs</emphasis> car cela dépend de la taille moyenne des
- documents, de l'analyseur utilisé et de la mémoire disponible.
- </para>
- <para>
- Une bonne méthode pour trouver une valeur correcte consiste à effectuer plusieurs
- tests avec les documents les plus volumineux que vous vous attendez à voir figurer dans
- l'index.<footnote>
- <para>
- <methodname>memory_get_usage()</methodname> et <methodname>memory_get_peak_usage()</methodname>
- peuvent être utilisées pour contrôler l'utilisation de la mémoire.
- </para>
- </footnote>. Une bonne pratique consiste à ne pas utiliser plus de la moitié de la
- mémoire allouée.
- </para>
- <para>
- <emphasis>MaxMergeDocs</emphasis> limite la taille d'un segment (en termes de
- nombre de documents). De ce fait, il limite également la durée de l'auto-optimisation en
- garantissant que la méthode <methodname>addDocument()</methodname> ne sera pas exécutée plus d'un
- certain nombre de fois. C'est très important dans le cadre d'applications
- interactives.
- </para>
- <para>
- Diminuer la valeur du paramètre <emphasis>MaxMergeDocs</emphasis> peut aussi
- améliorer les performances lors de l'indexation en masse ("batch indexing").
- L'auto-optimisation est un processus itératif et utilise une technique ascendante. Les
- petits segments sont fusionnés vers de plus gros segments qui sont eux-mêmes fusionnés
- vers des segments encore plus gros, etc. L'optimisation complète est achevée lorsqu'il
- ne reste qu'un seul gros segment.
- </para>
- <para>
- De petits segments détériore généralement la qualité de l'index. Un grand nombre
- de petits segments peut aussi déclencher l'erreur "Too many open files" déterminée par
- les limitations du système d'exploitation<footnote>
- <para>
- <classname>Zend_Search_Lucene</classname> maintient chaque segment ouvert
- pour améliorer les performances de recherche.
- </para>
- </footnote>.
- </para>
- <para>
- En général, l'optimisation d'index en arrière-plan devrait être effectuée pour les
- modes d'indexation interactifs et la valeur de <emphasis>MaxMergeDocs</emphasis> ne
- devrait pas être trop faible pour les indexations de masse ("batch indexing").
- </para>
- <para>
- <emphasis>MergeFactor</emphasis> affecte la fréquence d'auto-optimisation. De
- faibles valeurs augmenteront la qualité des index non-optimisés. Des valeurs plus
- importantes amélioreront les performances de l'indexation, mais également le nombre de
- segments fusionnés. Ce qui peut également déclencher l'erreur "Too many open
- files".
- </para>
- <para>
- <emphasis>MergeFactor</emphasis> groupe les segments d'index par leur taille :
- <orderedlist>
- <listitem>
- <para>Pas plus grand que <emphasis>MaxBufferedDocs</emphasis>.</para>
- </listitem>
- <listitem>
- <para>
- Plus grand que <emphasis>MaxBufferedDocs</emphasis>, mais pas plus
- grand que
- <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis>.
- </para>
- </listitem>
- <listitem>
- <para>
- Plus grand que
- <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis>, mais
- pas plus grand que
- <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis>*<emphasis>MergeFactor</emphasis>.
- </para>
- </listitem>
- <listitem>
- <para>...</para>
- </listitem>
- </orderedlist>
- </para>
- <para>
- <classname>Zend_Search_Lucene</classname> vérifie à chaque appel de
- <methodname>addDocument()</methodname> si la fusion de n'importe quel segment pour déplacer le
- segment nouvellement créé dans le groupe suivant. Si c'est le cas, la fusion est
- effectuée.
- </para>
- <para>
- Ainsi, un index avec N groupes peut contenir <emphasis>MaxBufferedDocs</emphasis>
- + (N-1)*<emphasis>MergeFactor</emphasis> segments et contient au moins
- <emphasis>MaxBufferedDocs</emphasis>*<emphasis>MergeFactor</emphasis><superscript>(N-1)</superscript>
- documents.
- </para>
- <para>
- La formule ci-dessous donne une bonne approximation du nombre de segments dans un
- index :
- </para>
- <para>
- <emphasis>Nombre de segments</emphasis> <= <emphasis>MaxBufferedDocs</emphasis>
- + <emphasis>MergeFactor</emphasis>*log
- <subscript><emphasis>MergeFactor</emphasis></subscript> (<emphasis>Nombre de
- documents</emphasis>/<emphasis>MaxBufferedDocs</emphasis>)
- </para>
- <para>
- <emphasis>MaxBufferedDocs</emphasis> est déterminé par la mémoire allouée. Cela
- permet pour le facteur de fusion (MergeFactor) approprié d'avoir un nombre raisonnable
- de segments.
- </para>
- <para>
- L'optimisation du paramètre <emphasis>MergeFactor</emphasis> est plus efficace
- pour les performances de l'indexation de masse (batch indexing) que
- <emphasis>MaxMergeDocs</emphasis>. Mais cette méthode manque un peu de finesse. Le mieux
- est d'utiliser l'estimation ci-dessus pour optimiser <emphasis>MergeFactor</emphasis>,
- puis de jouer avec <emphasis>MaxMergeDocs</emphasis> pour obtenir les meilleures
- performances d'indexation de masse (batch indexing).
- </para>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.shutting-down">
- <title>Indexation à l'arrêt du programme</title>
- <para>
- L'instance de <classname>Zend_Search_Lucene</classname> effectue quelques tâches à
- la sortie du programme si des documents ont été ajoutés à l'index mais pas écrits dans
- un nouveau segment.
- </para>
- <para>Elle peut également déclencher le processus d'auto-optimisation.</para>
- <para>
- L'objet qui représente l'index est automatiquement fermé lorsque lui, ainsi que
- tous les objets de résultats de requête qui lui sont associés, sont hors de portée du
- script principal.
- </para>
- <para>
- Si l'objet d'index est stocké dans une variable globale, il ne sera fermé qu'à la
- fin de l'exécution du script<footnote>
- <para>
- Cela peut aussi se produire s'il y a une référence à l'index ou à l'un de
- ses résultats de recherche dans une structure de données cyclique, car le
- ramasse-miettes de <acronym>PHP</acronym> ne récupère les objets avec des références cycliques
- qu'en fin d'exécution de script
- </para>
- </footnote>.
- </para>
- <para>Le processus d'exception de <acronym>PHP</acronym> est également fermé à ce moment.</para>
- <para>
- Cela n'empêche pas la fermeture normale du processus de l'index, mais cela peut
- empêcher un diagnostic d'erreur précis si une erreur survient durant la
- fermeture.
- </para>
- <para>Il y a deux moyens qui peuvent permettre d'éviter ce problème.</para>
- <para>
- Le premier est de forcer l'index à sortir de la portée (du scope) :<programlisting
- role="php"><![CDATA[
- $index = Zend_Search_Lucene::open($indexPath);
- ...
- unset($index);
- ]]></programlisting></para>
- <para>
- Le second est d'effectuer une opération de commit avant la fin du script exécution
- :<programlisting language="php"><![CDATA[
- $index = Zend_Search_Lucene::open($indexPath);
- $index->commit();
- ]]></programlisting> Cette possibilité est également décrite dans la section "<link
- linkend="zend.search.lucene.advanced.static">Avancé - Utiliser les propriétés statiques
- de l'index</link>".
- </para>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.unique-id">
- <title>Récupération de documents par leur id unique</title>
- <para>
- C'est une pratique commune de stocker un identifiant unique de document dans
- l'index. Par exemple, une url, un chemin ou un identifiant tiré d'une base de
- données.
- </para>
- <para>
- <classname>Zend_Search_Lucene</classname> fournit une méthode
- <methodname>termDocs()</methodname> pour récupérer des documents contenant les termes
- spécifiés.
- </para>
- <para>
- C'est plus efficace que d'utiliser la méthode <methodname>find()</methodname> :<programlisting
- role="php"><![CDATA[
- // Récupération de documents avec la méthode find()
- // en utilisant une querystring
- $query = $idFieldName . ':' . $docId;
- $hits = $index->find($query);
- foreach ($hits as $hit) {
- $title = $hit->title;
- $contents = $hit->contents;
- ...
- }
- ...
- // Récupération de documents avec la méthode find()
- // en utilisant l'API de requête.
- $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;
- ...
- }
- ...
- // Récupération de documents avec la méthode termDocs()
- $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></para>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.memory-usage">
- <title>Utilisation de la mémoire</title>
- <para>
- <classname>Zend_Search_Lucene</classname> est un module relativement gourmand en
- mémoire.
- </para>
- <para>
- Il utilise la mémoire pour mettre en cache certaines informations et optimiser la
- recherche, ainsi que les performances de l'indexation.
- </para>
- <para>La mémoire requise diffère selon les modes.</para>
- <para>
- L'index du dictionnaire des termes est chargé durant la recherche. Il s'agit de
- chaque 128<superscript>ème</superscript><footnote>
- <para>
- Le format de fichier Lucene permet de configurer ce nombre, mais
- <classname>Zend_Search_Lucene</classname> n'expose pas cette possibilité dans
- l'API. Cependant vous pouvez toujours configurer ce nombre si l'index est géré
- par une autre implémentation de Lucene.
- </para>
- </footnote> terme du dictionnaire complet.
- </para>
- <para>
- De fait, la consommation de mémoire augmente si vous avez un grand nombre de
- termes uniques. Cela peut arriver si vous utilisez des phrases non "tokenizées" comme
- champ de recherche ou que vous indexez un large volume d'informations
- non-textuelles.
- </para>
- <para>
- Un index non-optimisé consiste en plusieurs segments. Cela augmente également
- l'utilisation de mémoire. Les segments étant indépendants, chacun possède son propre
- dictionnaire de termes et index de dictionnaire de termes. Si un index consiste en
- <emphasis>N</emphasis> segments, il risque, dans le pire des cas, de multiplier par
- <emphasis>N</emphasis> la consommation de mémoire. Lancez l'optimisation de l'index en
- fusionnant tous les segments afin d'éviter de telles consommations de mémoire.
- </para>
- <para>
- L'indexation utilise la même quantité de mémoire que la recherche, plus de la
- mémoire pour mettre les documents en tampon. La quantité de mémoire peut être gérée par
- le paramètre <emphasis>MaxBufferedDocs</emphasis>.
- </para>
- <para>
- L'optimisation d'index (complète ou partielle) utilise un processus de type flux
- ("streaming") et ne requiert pas une grosse quantité de mémoire.
- </para>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.encoding">
- <title>Encodage</title>
- <para>
- <classname>Zend_Search_Lucene</classname> travaille avec des chaînes en UTF-8 en
- interne. Ainsi toutes les chaînes de caractères retournée par
- <classname>Zend_Search_Lucene</classname> sont encodées en UTF-8.
- </para>
- <para>
- Vous ne devriez pas être concernés par l'encodage si vous travaillez avec des
- chaîne purement <acronym>ASCII</acronym>, mais vous devez être prudent si ce n'est pas le cas.
- </para>
- <para>
- Un mauvais encodage peut causer des notices (erreur) durant la conversation
- d'encodage, voire la perte de données.
- </para>
- <para>
- <classname>Zend_Search_Lucene</classname> offre un large éventail de possibilités
- d'encodage pour les documents indexés et les requêtes analysées.
- </para>
- <para>
- L'encodage peut être explicitement spécifié en passant un paramètre optionnel à la
- méthode de création d'un champ :<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> C'est le meilleur moyen d'éviter toute ambiguïté dans les encodages
- utilisés.
- </para>
- <para>
- Si le paramètre optionnel de l'encodage est omis, la locale courante est utilisée.
- La locale courante peut contenir des données d'encodage en plus des spécification de
- langue :<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>
- <para>
- La même approche est utilisée pour définir l'encodage des chaînes de
- requête.
- </para>
- <para>
- Si l'encodage n'est pas spécifié, la locale courante est utilisée pour le
- déterminer.
- </para>
- <para>
- L'encodage peut être passée comme paramètre optionnel si la requête est analysée
- explicitement avant la recherche :<programlisting language="php"><![CDATA[
- $query =
- Zend_Search_Lucene_Search_QueryParser::parse($queryStr, 'iso-8859-5');
- $hits = $index->find($query);
- ...
- ]]></programlisting></para>
- <para>
- L'encodage par défaut peut également être spécifié avec la méthode
- <methodname>setDefaultEncoding()</methodname> :<programlisting language="php"><![CDATA[
- Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('iso-8859-1');
- $hits = $index->find($queryStr);
- ...
- chaîne vide sous-entend "locale courante".
- ]]></programlisting></para>
- <para>
- Si l'encodage correct est spécifié, il pourra être correctement interprété par
- l'analyseur. Le comportement dépend de quel analyseur est utilisé. Consultez la section
- sur les <link linkend="zend.search.lucene.charset">Jeu de caractères</link> pour plus de
- détails.
- </para>
- </sect2>
- <sect2 id="zend.search.lucene.best-practice.maintenance">
- <title>Maintenance de l'index</title>
- <para>
- Il devrait être clair que <classname>Zend_Search_Lucene</classname> comme toute
- autre implémentation de Lucene ne comporte pas de "base de données".
- </para>
- <para>
- Les index ne devrait pas être utilisés pour du stockage de données. Ils ne
- fournissent pas de fonctionnalités de backup/restauration partiel, journalisation, logs,
- transactions et beaucoup d'autres fonctionnalités assimilées aux systèmes de gestion de
- bases de données.
- </para>
- <para>
- Cependant, <classname>Zend_Search_Lucene</classname> tente de garder ses index
- dans un état constant en tout temps.
- </para>
- <para>
- Le backup et la restauration d'un index devrait être effectué en copiant le
- contenu du répertoire de l'index.
- </para>
- <para>
- Si pour une raison quelconque, un index devait être corrompu, il devrait être
- restauré ou complètement reconstruit.
- </para>
- <para>
- C'est donc une bonne idée de faire des backups des gros index et de stocker les
- logs de modifications pour pouvoir effectuer des restaurations manuelles et des
- opérations de "roll-forward" si nécessaire. Cette pratique réduit considérablement le
- temps de restauration.
- </para>
- </sect2>
- </sect1>
|