| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 13831 -->
- <!-- 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
- <code>QueryHit</code>.</para>
- <para>Les propriétés <code>id</code> et <code>score</code> 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
- <code>getDocument()</code> pour y accéder :<programlisting role="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 un 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
- <code>optimize()</code> :<programlisting role="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><code>memory_get_usage()</code> et <code>memory_get_peak_usage()</code>
- 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 <code>addDocument()</code> 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 <code>addDocument()</code>
- 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 PHP 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 PHP 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 role="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 <code>termDocs()</code> pour
- récupérer des documents contenant les termes spécifiés.</para>
- <para>C'est plus efficace que d'utiliser la méthode <code>find()</code> :<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 ASCII, 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 role="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 role="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 role="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
- <code>setDefaultEncoding()</code> :<programlisting role="php"><![CDATA[
- Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('iso-8859-1');
- $hits = $index->find($queryStr);
- ...
- ]]></programlisting>Une chaîne vide sous-entend "locale courante".</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>
|