<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 24249 -->
<!-- Reviewed: no -->
<sect1 id="zend.search.lucene.searching">
    <title>Chercher dans un index</title>
    <sect2 id="zend.search.lucene.searching.query_building">
        <title>Construire des requêtes</title>
        <para>
            Il y a deux manières de chercher dans un index. La première
            utilise le parseur de requête pour construire une requête à partir
            d'une chaîne de caractères. La seconde consiste à créer vos
            propres requêtes par programme à l'aide de l'<acronym>API</acronym>
            <classname>Zend_Search_Lucene</classname>.
        </para>
        <para>
            Avant de choisir d'utiliser le parseur de requête fourni, veuillez
            considérer ce qui suit :
            <orderedlist>
                <listitem>
                    <para>
                        Si vous créez par programme une chaîne et qu'ensuite vous la passez dans
                        le parseur de requêtes, vous devriez considérer la possibilité
                        de construire vos requêtes directement avec l'<acronym>API</acronym> de
                        requêtes. En règle générale, le parseur est fait pour le texte saisi par
                        un utilisateur, pas pour du texte généré par programme.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        Les champs non "tokenizés" devraient de préférences être ajoutés
                        directement aux requêtes et pas être passés dans le parseur. Si
                        les valeurs d'un champ sont générées par programme, les clauses de
                        requête pour ce champ devraient également être créées par programme.
                        Un analyseur, utilisé par le parseur de requêtes, est modélisé pour
                        convertir le texte saisi par l'utilisateur en des termes. Les valeurs
                        générées par programme, telles que dates, mot-clés, etc. devraient être
                        ajoutés avec l'<acronym>API</acronym> de requêtes.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        Dans un formulaire de requête, les champs de texte général devraient
                        utiliser le parseur de requêtes. Tous les autres, tels qu'intervalles de
                        dates, mot-clés, etc., seront de préférence ajoutés directement dans
                        l'<acronym>API</acronym> de requêtes. Un champ avec une somme limitée de
                        valeurs qui peut être défini dans un menu déroulant ne devrait pas être
                        ajouté à une chaîne de requête qui serait ensuite parsée, mais devrait être
                        ajouté en tant que clause de type 'TermQuery'.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        Les requêtes booléennes permettent au programmeur de combiner de manière
                        logique deux ou plus requêtes en une seule. De fait, c'est le meilleur
                        moyen d'ajouter des critères additionnels à une requête définie dans une
                        chaîne (querystring).
                    </para>
                </listitem>
            </orderedlist>
        </para>
        <para>
            Les deux manières utilisent la même méthode d'<acronym>API</acronym> pour chercher
            dans l'index :
        </para>
        <programlisting language="php"><![CDATA[
$index = Zend_Search_Lucene::open('/data/my_index');
$index->find($query);
]]></programlisting>
        <para>
            La méthode <methodname>Zend_Search_Lucene::find()</methodname> détermine automatiquement
            le type de données entrantes et utilise le parseur de requêtes ou construit un objet
            approprié à partir d''une donnée entrante de type chaîne de caractères.
        </para>
        <para>
            Il est important de noter que le parseur de requêtes utilise l'analyseur standard
            pour "tokenizer" les différentes partie d'une chaîne. Ainsi, toutes les transformations
            qui sont appliquées aux textes indexés le sont également aux chaînes de requête.
        </para>
        <para>
            L'analyseur standard peut transformer la chaîne de requête en minuscules pour
            gérer l'insensibilité à la casse, retirer les mots exclus (ou "stop-words"), et
            encapsuler les autres transformations.
        </para>
        <para>
            La méthode de l'<acronym>API</acronym> ne transforme ni ne filtre les termes entrant
            d'aucune façon. Elle est ainsi plus pratique pour les champs générés par le programme
            ou ceux qui ne sont pas "tokenizés".
        </para>
        <sect3 id="zend.search.lucene.searching.query_building.parsing">
            <title>Parsage de requêtes</title>
            <para>
                La méthode <methodname>Zend_Search_Lucene_Search_QueryParser::parse()</methodname>
                peut être utilisée pour parser des chaînes de requête en objets de requête.
            </para>
            <para>
                Cet objet de requête peut être utilisé dans une méthode de construction de requête de
                l'<acronym>API</acronym> pour combiner des requêtes entrées par l'utilisateur avec
                des requêtes générées par programme.
            </para>
            <para>
                Pour l'instant, dans certains cas c'est le seul moyen de chercher des valeurs dans
                des champs "non-tokenizés" :
                Actually, in some cases it's the only way to search for values within untokenized
                fields:
                <programlisting language="php"><![CDATA[
$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
$pathTerm  = new Zend_Search_Lucene_Index_Term(
                     '/data/doc_dir/' . $filename, 'path'
                 );
$pathQuery = new Zend_Search_Lucene_Search_Query_Term($pathTerm);
$query = new Zend_Search_Lucene_Search_Query_Boolean();
$query->addSubquery($userQuery, true /* required */);
$query->addSubquery($pathQuery, true /* required */);
$hits = $index->find($query);
]]></programlisting>
            </para>
            <para>
                La méthode <methodname>Zend_Search_Lucene_Search_QueryParser::parse()</methodname>
                prend également un paramètre optionnel d'encodage, qui permet de spécifier l'encodage
                de la chaîne de requête :
                <programlisting language="php"><![CDATA[
$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr,
                                                          'iso-8859-5');
]]></programlisting>
            </para>
            <para>
                Si le paramètre d'encodage est omis, la locale courante est utilisée.
            </para>
            <para>
                Il est également possible de spécifier l'encodage par défaut de la chaîne
                de requête avec la méthode <methodname>Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding()</methodname> :
                <programlisting language="php"><![CDATA[
Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('iso-8859-5');
...
$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
]]></programlisting>
            </para>
            <para>
                <methodname>Zend_Search_Lucene_Search_QueryParser::getDefaultEncoding()</methodname>
                retourne la valeur actuelle de l'encodage par défaut d'une chaîne de requête (une
                chaîne vide signifiant "locale courante").
            </para>
        </sect3>
    </sect2>
    <sect2 id="zend.search.lucene.searching.results">
        <title>Résultats de recherche</title>
        <para>
            Le résultat de recherche est un tableau d'objets
            <classname>Zend_Search_Lucene_Search_QueryHit</classname>. Chacun d'eux a deux propriétés :
            <code>$hit->id</code> est un identifiant numérique de document dans l'index et
            <code>$hit->score</code> est le score du hit dans le résultat de recherche. Les résultats
            sont triés par score (descendant depuis le meilleur score).
        </para>
        <para>
            L'objet <classname>Zend_Search_Lucene_Search_QueryHit</classname> expose également
            chaque champ du <classname>Zend_Search_Lucene_Document</classname> trouvé dans la
            recherche en tant que propriété du hit. Dans l'exemple suivant, un hit est retourné avec
            deux champs du document correspondant : title et author.
        </para>
        <programlisting language="php"><![CDATA[
$index = Zend_Search_Lucene::open('/data/my_index');
$hits = $index->find($query);
foreach ($hits as $hit) {
    echo $hit->score;
    echo $hit->title;
    echo $hit->author;
}
]]></programlisting>
        <para>
            Les champs stockés sont toujours retournés encodés en UTF-8.
        </para>
        <para>
            Optionnellement, l'objet original <classname>Zend_Search_Lucene_Document</classname>
            peut être retourné depuis le <classname>Zend_Search_Lucene_Search_QueryHit</classname>.
            Vous pouvez récupérer les parties stockées du document en utilisant la méthode
            <methodname>getDocument()</methodname> de l'objet index, puis les obtenir avec la
            méthode <methodname>getFieldValue()</methodname> :
        </para>
        <programlisting language="php"><![CDATA[
$index = Zend_Search_Lucene::open('/data/my_index');
$hits = $index->find($query);
foreach ($hits as $hit) {
    // return Zend_Search_Lucene_Document object for this hit
    echo $document = $hit->getDocument();
    // return a Zend_Search_Lucene_Field object
    // from the Zend_Search_Lucene_Document
    echo $document->getField('title');
    // return the string value of the Zend_Search_Lucene_Field object
    echo $document->getFieldValue('title');
    // same as getFieldValue()
    echo $document->title;
}
]]></programlisting>
        <para>
            Les champs disponibles dans l'objet <classname>Zend_Search_Lucene_Document</classname>
            sont déterminés lors de l'indexation. Les champs sont soit indexés, soit indexés et stockés
            dans le document par l'application d'indexage (p. ex. LuceneIndexCreation.jar).
        </para>
        <para>
            Notez que l'identité du document ('path' dans notre exemple) est également
            stocké dans l'index et doit être récupéré depuis l'index.
        </para>
    </sect2>
    <sect2 id="zend.search.lucene.searching.results-limiting">
        <title>Limiter le nombre de résultats</title>
        <para>
            L'opération la plus lourde au niveau du calcul dans une recherche est la calculation
            des scores. Cela peut prendre plusieurs secondes pour un grand ensemble de résultats
            (dizaine de milliers de hits).
        </para>
        <para>
            <classname>Zend_Search_Lucene</classname> donne la possibilité de limiter la taille
            de l'ensemble de résultats avec les méthodes <methodname>getResultSetLimit()</methodname>
            et <methodname>setResultSetLimit()</methodname> :
            <programlisting language="php"><![CDATA[
$currentResultSetLimit = Zend_Search_Lucene::getResultSetLimit();
Zend_Search_Lucene::setResultSetLimit($newLimit);
]]></programlisting>
            La valeur par défaut de 0 signifie 'pas de limite'.
        </para>
        <para>
            Cela ne retournera pas les 'N meilleurs' résultats, mais seulement les 'N premiers'.
            <footnote>
                <para>
                    Les hits retournés demeurent triés par score ou par l'ordre spécifié, s'il est spécifié.
                </para>
            </footnote>.
        </para>
    </sect2>
    <sect2 id="zend.search.lucene.searching.results-scoring">
        <title>Etablissement des scores des résultats de recherche</title>
        <para>
            <classname>Zend_Search_Lucene</classname> utilise le même algorithme de scoring que
            Java Lucene. Par défaut, tous les hits dans l'ensemble de résultats sont triés par score.
            Les hits avec le plus grand score viennent en premier, et les documents avec des hauts scores
            devraient mieux correspondre à la requête que ceux avec des scores moins élevés.
        </para>
        <para>
            En gros, les hits qui contiennent le terme ou la phrase cherché plus fréquemment
            auront un score plus élevé.
        </para>
        <para>
            Le score d'un hit peut être récupéré en accédant à la propriété <code>score</code> du hit :
        </para>
        <programlisting language="php"><![CDATA[
$hits = $index->find($query);
foreach ($hits as $hit) {
    echo $hit->id;
    echo $hit->score;
}
]]></programlisting>
        <para>
            La classe <classname>Zend_Search_Lucene_Search_Similarity</classname> est utilisée
            pour calculer le score pour chaque hit. Consultez la section <link
                linkend="zend.search.lucene.extending.scoring">Extensibility. Scoring
                Algorithms</link> pour des détails.
        </para>
    </sect2>
    <sect2 id="zend.search.lucene.searching.sorting">
        <title>Tri des résultats de recherche</title>
        <para>
            Par défaut, les résultats de recherche sont triés par score. Le programmeur peut
            changer ce comportement en définissant des paramètres pour le champ de tri (ou une liste de champs), le
            type de tri et le sens de tri.
        </para>
        <para>
            L'appel à <code>$index->find()</code> peut prendre plusieurs paramètres optionnels :
            <programlisting language="php"><![CDATA[
$index->find($query [, $sortField [, $sortType [, $sortOrder]]]
                    [, $sortField2 [, $sortType [, $sortOrder]]]
             ...);
]]></programlisting>
        </para>
        <para>
            Le nom d'un champ stocké par lequel on veut trier les résultats devrait
            être passé comme paramètre <varname>$sortField</varname>.
        </para>
        <para>
            <varname>$sortType</varname> peut être omis ou prendre l'une des valeurs suivantes :
            <constant>SORT_REGULAR</constant> (compare les éléments normalement- valeur par défaut),
            <constant>SORT_NUMERIC</constant> (compare les éléments comme des valeurs numériques),
            <constant>SORT_STRING</constant> (compare les éléments comme des chaînes de caractères).
        </para>
        <para>
            <varname>$sortOrder</varname> peut être omis ou prendre l'une des valeurs suivantes :
            <constant>SORT_ASC</constant> (trie dans l'ordre croissant- valeur par défaut),
            <constant>SORT_DESC</constant> (trie dans l'ordre décroissant).
        </para>
        <para>
            Exemples:
            <programlisting language="php"><![CDATA[
$index->find($query, 'quantity', SORT_NUMERIC, SORT_DESC);
]]></programlisting>
            <programlisting language="php"><![CDATA[
$index->find($query, 'fname', SORT_STRING, 'lname', SORT_STRING);
]]></programlisting>
            <programlisting language="php"><![CDATA[
$index->find($query, 'name', SORT_STRING, 'quantity', SORT_NUMERIC, SORT_DESC);
]]></programlisting>
        </para>
        <para>
            Soyez prudents en personnalisant vos clés de tri; la requête aura besoin de récupérer
            tous les documents correspondant de l'index, ce qui peut réduire considérablement les
            performances de recherche.
        </para>
    </sect2>
    <sect2 id="zend.search.lucene.searching.highlighting">
        <title>Mise en évidence des résultats de recherche</title>
        <para>
            <classname>Zend_Search_Lucene</classname> propose deux options pour mettre en
            évidence les résultats de recherche.
        </para>
        <para>
            La première consiste à utiliser la classe <classname>Zend_Search_Lucene_Document_Html</classname>
            (voyez <link linkend="zend.search.lucene.index-creation.html-documents">la section
            Documents HTML</link> pour des détails) en utilisant les méthodes suivantes :
            <programlisting language="php"><![CDATA[
/**
 * Mise en évidence de texte avec la couleur spécifiée
 *
 * @param string|array $words
 * @param string $colour
 * @return string
 */
public function highlight($words, $colour = '#66ffff');
]]></programlisting>
            <programlisting language="php"><![CDATA[
/**
 * Mise en évidence du texte en utilisant le View helper spécifié ou une
 * fonction callback.
 *
 * @param string|array $words  Les mots à mettre en évidence. Ils peuvent être organisés
                               dans un tableau ou une chaîne de caractères.
 * @param callback $callback   La méthode callback, utilisée pour transformer
                               (mettre en évidence) le texte.
 * @param array    $params     Un tableau de paramètres additionnels passés à la fonction
                               callback (le premier paramètre non optionnel est un fragment
                               de code HTML pour la mise en évidence).
 * @return string
 * @throws Zend_Search_Lucene_Exception
 */
public function highlightExtended($words, $callback, $params = array())
]]></programlisting>
        </para>
        <para>
            Pour personnaliser le comportement de mise en évidence, utilisez la méthode
            <methodname>highlightExtended()</methodname> avec le callback spécifié qui prendra
            un ou plusieurs paramètres.
            <footnote>
                <para>
                    Le premier paramètre est un fragment de code HTML pour la mise en évidence et
                    les suivants sont dépendants du comportement du callback. La valeur de retour
                    est un fragment HTML mise en évidence.
                </para>
            </footnote>
            , ou étendez la classe <classname>Zend_Search_Lucene_Document_Html</classname> et
            redéfinissez la méthode <methodname>applyColour($stringToHighlight, $colour)</methodname>
            qui est utilisée comme le callback de mise en évidence par défaut.
            <footnote>
                <para>
                    Dans les deux cas, le HTML retourné est automatiquement transformé en
                    <acronym>XHTML</acronym> valide.
                </para>
            </footnote>
        </para>
        <para>
            Les <link linkend="zend.view.helpers">View helpers</link> peuvent également être utilisés
            comme des callbacks dans un contexte d'affichage du script :
            <programlisting language="php"><![CDATA[
$doc->highlightExtended('word1 word2 word3...', array($this, 'myViewHelper'));
]]></programlisting>
        </para>
        <para>
            Le résultat de l'opération de mise en évidence est récupéré avec
            la méthode <code>Zend_Search_Lucene_Document_Html->getHTML()</code>.
        </para>
        <note>
            <para>
                La mise en évidence est exécutée dans les termes de l'analyseur courant. Donc toutes
                les formes de mot(s) reconnues par l'analyseur seront mises en évidence.
            </para>
            <para>
                Ex.: Si l'analyseur courant est insensible à la casse et que l'on demande à mettre
                en évidence le mot 'text', alors 'text', 'Text', 'TEXT' ou toute autre combinaison de
                casse seront mis en évidence.
            </para>
            <para>
                Dans le même ordre d'idées, si l'analyseur courant supporte les requêtes proches (stemming)
                et que l'on souhaite mettre en évidence 'indexed', alors 'index', 'indexing', 'indices' et
                d'autres mots proches seront mis en évidences.
            </para>
            <para>
                A l'inverse, si un mot est ignoré par l'analyseur courant (ex. si un filtre pour
                ignorer les mots trop courts est appliqué à l'analyseur), alors rien ne sera mis en évidence.
            </para>
        </note>
        <para>
            La seconde option est d'utiliser la méthode
            <code>Zend_Search_Lucene_Search_Query->highlightMatches(string $inputHTML[,
                $defaultEncoding = 'UTF-8'[,
                Zend_Search_Lucene_Search_Highlighter_Interface $highlighter]])</code>:
            <programlisting language="php"><![CDATA[
$query = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
$highlightedHTML = $query->highlightMatches($sourceHTML);
]]></programlisting>
        </para>
        <para>
            Le second paramètre optionnel est l'encodage par défaut du document HTML. Il est
            utilisé si l'encodage n'est pas spécifié dans le metatag HTTP-EQUIV Content-Type.
        </para>
        <para>
            Le troisième paramètre optionnel est un objet de mise en évidence qui doit
            implémenter l'interface <classname>Zend_Search_Lucene_Search_Highlighter_Interface</classname>:
            <programlisting language="php"><![CDATA[
interface Zend_Search_Lucene_Search_Highlighter_Interface
{
    /**
     * Définit le document pour la mise en évidence
     *
     * @param Zend_Search_Lucene_Document_Html $document
     */
    public function setDocument(Zend_Search_Lucene_Document_Html $document);
    /**
     * Récupère le document pour la mise en évidence
     *
     * @return Zend_Search_Lucene_Document_Html $document
     */
    public function getDocument();
    /**
     * Mise en évidence des mots spécifiés (appelée une fois par sous-requête)
     *
     * @param string|array $words  Les mots à mettre en évidence. Ils peuvent être organisés
     *                             dans un tableau ou une chaîne de caractères.
     */
    public function highlight($words);
}
]]></programlisting>
            Où l'objet <classname>Zend_Search_Lucene_Document_Html</classname> est un objet
            construit à partir de la source HTML fournie par la méthode
            <classname>Zend_Search_Lucene_Search_Query->highlightMatches()</classname>
        </para>
        <para>
            Si le paramètre <varname>$highlighter</varname> est omis, un objet
            <classname>Zend_Search_Lucene_Search_Highlighter_Default</classname> est
            instancié et utilisé.
        </para>
        <para>
            La méthode de mise en évidence <methodname>highlight()</methodname> est invoquée une
            fois par sous-requête, ainsi elle a la possibilité de différencier la mise en évidence
            pour chacune.
        </para>
        <para>
            La mise en évidence par défaut le fait en parcourant une table prédéfinie de couleurs.
            Vous pouvez implémenter votre propre classe de mise en évidence ou juste étendre la classe
            par défaut et redéfinir la table de couleurs.
        </para>
        <para>
            <code>Zend_Search_Lucene_Search_Query->htmlFragmentHighlightMatches()</code> a un comportement
            similaire. La seule différence est qu'il prend en entrée et retourne un fragment HTML sans
            les balises &lt;>HTML>, &lt;HEAD>, &lt;BODY>. Néanmoins, le fragment est automatiquement
            transformé en <acronym>XHTML</acronym> valide.
        </para>
    </sect2>
</sect1>
