Zend_Search_Lucene-Searching.xml 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!-- EN-Revision: 24249 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.search.lucene.searching">
  5. <title>Chercher dans un index</title>
  6. <sect2 id="zend.search.lucene.searching.query_building">
  7. <title>Construire des requêtes</title>
  8. <para>
  9. Il y a deux manières de chercher dans un index. La première
  10. utilise le parseur de requête pour construire une requête à partir
  11. d'une chaîne de caractères. La seconde consiste à créer vos
  12. propres requêtes par programme à l'aide de l'<acronym>API</acronym>
  13. <classname>Zend_Search_Lucene</classname>.
  14. </para>
  15. <para>
  16. Avant de choisir d'utiliser le parseur de requête fourni, veuillez
  17. considérer ce qui suit :
  18. <orderedlist>
  19. <listitem>
  20. <para>
  21. Si vous créez par programme une chaîne et qu'ensuite vous la passez dans
  22. le parseur de requêtes, vous devriez considérer la possibilité
  23. de construire vos requêtes directement avec l'<acronym>API</acronym> de
  24. requêtes. En règle générale, le parseur est fait pour le texte saisi par
  25. un utilisateur, pas pour du texte généré par programme.
  26. </para>
  27. </listitem>
  28. <listitem>
  29. <para>
  30. Les champs non "tokenizés" devraient de préférences être ajoutés
  31. directement aux requêtes et pas être passés dans le parseur. Si
  32. les valeurs d'un champ sont générées par programme, les clauses de
  33. requête pour ce champ devraient également être créées par programme.
  34. Un analyseur, utilisé par le parseur de requêtes, est modélisé pour
  35. convertir le texte saisi par l'utilisateur en des termes. Les valeurs
  36. générées par programme, telles que dates, mot-clés, etc. devraient être
  37. ajoutés avec l'<acronym>API</acronym> de requêtes.
  38. </para>
  39. </listitem>
  40. <listitem>
  41. <para>
  42. Dans un formulaire de requête, les champs de texte général devraient
  43. utiliser le parseur de requêtes. Tous les autres, tels qu'intervalles de
  44. dates, mot-clés, etc., seront de préférence ajoutés directement dans
  45. l'<acronym>API</acronym> de requêtes. Un champ avec une somme limitée de
  46. valeurs qui peut être défini dans un menu déroulant ne devrait pas être
  47. ajouté à une chaîne de requête qui serait ensuite parsée, mais devrait être
  48. ajouté en tant que clause de type 'TermQuery'.
  49. </para>
  50. </listitem>
  51. <listitem>
  52. <para>
  53. Les requêtes booléennes permettent au programmeur de combiner de manière
  54. logique deux ou plus requêtes en une seule. De fait, c'est le meilleur
  55. moyen d'ajouter des critères additionnels à une requête définie dans une
  56. chaîne (querystring).
  57. </para>
  58. </listitem>
  59. </orderedlist>
  60. </para>
  61. <para>
  62. Les deux manières utilisent la même méthode d'<acronym>API</acronym> pour chercher
  63. dans l'index :
  64. </para>
  65. <programlisting language="php"><![CDATA[
  66. $index = Zend_Search_Lucene::open('/data/my_index');
  67. $index->find($query);
  68. ]]></programlisting>
  69. <para>
  70. La méthode <methodname>Zend_Search_Lucene::find()</methodname> détermine automatiquement
  71. le type de données entrantes et utilise le parseur de requêtes ou construit un objet
  72. approprié à partir d''une donnée entrante de type chaîne de caractères.
  73. </para>
  74. <para>
  75. Il est important de noter que le parseur de requêtes utilise l'analyseur standard
  76. pour "tokenizer" les différentes partie d'une chaîne. Ainsi, toutes les transformations
  77. qui sont appliquées aux textes indexés le sont également aux chaînes de requête.
  78. </para>
  79. <para>
  80. L'analyseur standard peut transformer la chaîne de requête en minuscules pour
  81. gérer l'insensibilité à la casse, retirer les mots exclus (ou "stop-words"), et
  82. encapsuler les autres transformations.
  83. </para>
  84. <para>
  85. La méthode de l'<acronym>API</acronym> ne transforme ni ne filtre les termes entrant
  86. d'aucune façon. Elle est ainsi plus pratique pour les champs générés par le programme
  87. ou ceux qui ne sont pas "tokenizés".
  88. </para>
  89. <sect3 id="zend.search.lucene.searching.query_building.parsing">
  90. <title>Parsage de requêtes</title>
  91. <para>
  92. La méthode <methodname>Zend_Search_Lucene_Search_QueryParser::parse()</methodname>
  93. peut être utilisée pour parser des chaînes de requête en objets de requête.
  94. </para>
  95. <para>
  96. Cet objet de requête peut être utilisé dans une méthode de construction de requête de
  97. l'<acronym>API</acronym> pour combiner des requêtes entrées par l'utilisateur avec
  98. des requêtes générées par programme.
  99. </para>
  100. <para>
  101. Pour l'instant, dans certains cas c'est le seul moyen de chercher des valeurs dans
  102. des champs "non-tokenizés" :
  103. Actually, in some cases it's the only way to search for values within untokenized
  104. fields:
  105. <programlisting language="php"><![CDATA[
  106. $userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
  107. $pathTerm = new Zend_Search_Lucene_Index_Term(
  108. '/data/doc_dir/' . $filename, 'path'
  109. );
  110. $pathQuery = new Zend_Search_Lucene_Search_Query_Term($pathTerm);
  111. $query = new Zend_Search_Lucene_Search_Query_Boolean();
  112. $query->addSubquery($userQuery, true /* required */);
  113. $query->addSubquery($pathQuery, true /* required */);
  114. $hits = $index->find($query);
  115. ]]></programlisting>
  116. </para>
  117. <para>
  118. La méthode <methodname>Zend_Search_Lucene_Search_QueryParser::parse()</methodname>
  119. prend également un paramètre optionnel d'encodage, qui permet de spécifier l'encodage
  120. de la chaîne de requête :
  121. <programlisting language="php"><![CDATA[
  122. $userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr,
  123. 'iso-8859-5');
  124. ]]></programlisting>
  125. </para>
  126. <para>
  127. Si le paramètre d'encodage est omis, la locale courante est utilisée.
  128. </para>
  129. <para>
  130. Il est également possible de spécifier l'encodage par défaut de la chaîne
  131. de requête avec la méthode <methodname>Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding()</methodname> :
  132. <programlisting language="php"><![CDATA[
  133. Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('iso-8859-5');
  134. ...
  135. $userQuery = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
  136. ]]></programlisting>
  137. </para>
  138. <para>
  139. <methodname>Zend_Search_Lucene_Search_QueryParser::getDefaultEncoding()</methodname>
  140. retourne la valeur actuelle de l'encodage par défaut d'une chaîne de requête (une
  141. chaîne vide signifiant "locale courante").
  142. </para>
  143. </sect3>
  144. </sect2>
  145. <sect2 id="zend.search.lucene.searching.results">
  146. <title>Résultats de recherche</title>
  147. <para>
  148. Le résultat de recherche est un tableau d'objets
  149. <classname>Zend_Search_Lucene_Search_QueryHit</classname>. Chacun d'eux a deux propriétés :
  150. <code>$hit->id</code> est un identifiant numérique de document dans l'index et
  151. <code>$hit->score</code> est le score du hit dans le résultat de recherche. Les résultats
  152. sont triés par score (descendant depuis le meilleur score).
  153. </para>
  154. <para>
  155. L'objet <classname>Zend_Search_Lucene_Search_QueryHit</classname> expose également
  156. chaque champ du <classname>Zend_Search_Lucene_Document</classname> trouvé dans la
  157. recherche en tant que propriété du hit. Dans l'exemple suivant, un hit est retourné avec
  158. deux champs du document correspondant : title et author.
  159. </para>
  160. <programlisting language="php"><![CDATA[
  161. $index = Zend_Search_Lucene::open('/data/my_index');
  162. $hits = $index->find($query);
  163. foreach ($hits as $hit) {
  164. echo $hit->score;
  165. echo $hit->title;
  166. echo $hit->author;
  167. }
  168. ]]></programlisting>
  169. <para>
  170. Les champs stockés sont toujours retournés encodés en UTF-8.
  171. </para>
  172. <para>
  173. Optionnellement, l'objet original <classname>Zend_Search_Lucene_Document</classname>
  174. peut être retourné depuis le <classname>Zend_Search_Lucene_Search_QueryHit</classname>.
  175. Vous pouvez récupérer les parties stockées du document en utilisant la méthode
  176. <methodname>getDocument()</methodname> de l'objet index, puis les obtenir avec la
  177. méthode <methodname>getFieldValue()</methodname> :
  178. </para>
  179. <programlisting language="php"><![CDATA[
  180. $index = Zend_Search_Lucene::open('/data/my_index');
  181. $hits = $index->find($query);
  182. foreach ($hits as $hit) {
  183. // return Zend_Search_Lucene_Document object for this hit
  184. echo $document = $hit->getDocument();
  185. // return a Zend_Search_Lucene_Field object
  186. // from the Zend_Search_Lucene_Document
  187. echo $document->getField('title');
  188. // return the string value of the Zend_Search_Lucene_Field object
  189. echo $document->getFieldValue('title');
  190. // same as getFieldValue()
  191. echo $document->title;
  192. }
  193. ]]></programlisting>
  194. <para>
  195. Les champs disponibles dans l'objet <classname>Zend_Search_Lucene_Document</classname>
  196. sont déterminés lors de l'indexation. Les champs sont soit indexés, soit indexés et stockés
  197. dans le document par l'application d'indexage (p. ex. LuceneIndexCreation.jar).
  198. </para>
  199. <para>
  200. Notez que l'identité du document ('path' dans notre exemple) est également
  201. stocké dans l'index et doit être récupéré depuis l'index.
  202. </para>
  203. </sect2>
  204. <sect2 id="zend.search.lucene.searching.results-limiting">
  205. <title>Limiter le nombre de résultats</title>
  206. <para>
  207. L'opération la plus lourde au niveau du calcul dans une recherche est la calculation
  208. des scores. Cela peut prendre plusieurs secondes pour un grand ensemble de résultats
  209. (dizaine de milliers de hits).
  210. </para>
  211. <para>
  212. <classname>Zend_Search_Lucene</classname> donne la possibilité de limiter la taille
  213. de l'ensemble de résultats avec les méthodes <methodname>getResultSetLimit()</methodname>
  214. et <methodname>setResultSetLimit()</methodname> :
  215. <programlisting language="php"><![CDATA[
  216. $currentResultSetLimit = Zend_Search_Lucene::getResultSetLimit();
  217. Zend_Search_Lucene::setResultSetLimit($newLimit);
  218. ]]></programlisting>
  219. La valeur par défaut de 0 signifie 'pas de limite'.
  220. </para>
  221. <para>
  222. Cela ne retournera pas les 'N meilleurs' résultats, mais seulement les 'N premiers'.
  223. <footnote>
  224. <para>
  225. Les hits retournés demeurent triés par score ou par l'ordre spécifié, s'il est spécifié.
  226. </para>
  227. </footnote>.
  228. </para>
  229. </sect2>
  230. <sect2 id="zend.search.lucene.searching.results-scoring">
  231. <title>Etablissement des scores des résultats de recherche</title>
  232. <para>
  233. <classname>Zend_Search_Lucene</classname> utilise le même algorithme de scoring que
  234. Java Lucene. Par défaut, tous les hits dans l'ensemble de résultats sont triés par score.
  235. Les hits avec le plus grand score viennent en premier, et les documents avec des hauts scores
  236. devraient mieux correspondre à la requête que ceux avec des scores moins élevés.
  237. </para>
  238. <para>
  239. En gros, les hits qui contiennent le terme ou la phrase cherché plus fréquemment
  240. auront un score plus élevé.
  241. </para>
  242. <para>
  243. Le score d'un hit peut être récupéré en accédant à la propriété <code>score</code> du hit :
  244. </para>
  245. <programlisting language="php"><![CDATA[
  246. $hits = $index->find($query);
  247. foreach ($hits as $hit) {
  248. echo $hit->id;
  249. echo $hit->score;
  250. }
  251. ]]></programlisting>
  252. <para>
  253. La classe <classname>Zend_Search_Lucene_Search_Similarity</classname> est utilisée
  254. pour calculer le score pour chaque hit. Consultez la section <link
  255. linkend="zend.search.lucene.extending.scoring">Extensibility. Scoring
  256. Algorithms</link> pour des détails.
  257. </para>
  258. </sect2>
  259. <sect2 id="zend.search.lucene.searching.sorting">
  260. <title>Tri des résultats de recherche</title>
  261. <para>
  262. Par défaut, les résultats de recherche sont triés par score. Le programmeur peut
  263. changer ce comportement en définissant des paramètres pour le champ de tri (ou une liste de champs), le
  264. type de tri et le sens de tri.
  265. </para>
  266. <para>
  267. L'appel à <code>$index->find()</code> peut prendre plusieurs paramètres optionnels :
  268. <programlisting language="php"><![CDATA[
  269. $index->find($query [, $sortField [, $sortType [, $sortOrder]]]
  270. [, $sortField2 [, $sortType [, $sortOrder]]]
  271. ...);
  272. ]]></programlisting>
  273. </para>
  274. <para>
  275. Le nom d'un champ stocké par lequel on veut trier les résultats devrait
  276. être passé comme paramètre <varname>$sortField</varname>.
  277. </para>
  278. <para>
  279. <varname>$sortType</varname> peut être omis ou prendre l'une des valeurs suivantes :
  280. <constant>SORT_REGULAR</constant> (compare les éléments normalement- valeur par défaut),
  281. <constant>SORT_NUMERIC</constant> (compare les éléments comme des valeurs numériques),
  282. <constant>SORT_STRING</constant> (compare les éléments comme des chaînes de caractères).
  283. </para>
  284. <para>
  285. <varname>$sortOrder</varname> peut être omis ou prendre l'une des valeurs suivantes :
  286. <constant>SORT_ASC</constant> (trie dans l'ordre croissant- valeur par défaut),
  287. <constant>SORT_DESC</constant> (trie dans l'ordre décroissant).
  288. </para>
  289. <para>
  290. Exemples:
  291. <programlisting language="php"><![CDATA[
  292. $index->find($query, 'quantity', SORT_NUMERIC, SORT_DESC);
  293. ]]></programlisting>
  294. <programlisting language="php"><![CDATA[
  295. $index->find($query, 'fname', SORT_STRING, 'lname', SORT_STRING);
  296. ]]></programlisting>
  297. <programlisting language="php"><![CDATA[
  298. $index->find($query, 'name', SORT_STRING, 'quantity', SORT_NUMERIC, SORT_DESC);
  299. ]]></programlisting>
  300. </para>
  301. <para>
  302. Soyez prudents en personnalisant vos clés de tri; la requête aura besoin de récupérer
  303. tous les documents correspondant de l'index, ce qui peut réduire considérablement les
  304. performances de recherche.
  305. </para>
  306. </sect2>
  307. <sect2 id="zend.search.lucene.searching.highlighting">
  308. <title>Mise en évidence des résultats de recherche</title>
  309. <para>
  310. <classname>Zend_Search_Lucene</classname> propose deux options pour mettre en
  311. évidence les résultats de recherche.
  312. </para>
  313. <para>
  314. La première consiste à utiliser la classe <classname>Zend_Search_Lucene_Document_Html</classname>
  315. (voyez <link linkend="zend.search.lucene.index-creation.html-documents">la section
  316. Documents HTML</link> pour des détails) en utilisant les méthodes suivantes :
  317. <programlisting language="php"><![CDATA[
  318. /**
  319. * Mise en évidence de texte avec la couleur spécifiée
  320. *
  321. * @param string|array $words
  322. * @param string $colour
  323. * @return string
  324. */
  325. public function highlight($words, $colour = '#66ffff');
  326. ]]></programlisting>
  327. <programlisting language="php"><![CDATA[
  328. /**
  329. * Mise en évidence du texte en utilisant le View helper spécifié ou une
  330. * fonction callback.
  331. *
  332. * @param string|array $words Les mots à mettre en évidence. Ils peuvent être organisés
  333. dans un tableau ou une chaîne de caractères.
  334. * @param callback $callback La méthode callback, utilisée pour transformer
  335. (mettre en évidence) le texte.
  336. * @param array $params Un tableau de paramètres additionnels passés à la fonction
  337. callback (le premier paramètre non optionnel est un fragment
  338. de code HTML pour la mise en évidence).
  339. * @return string
  340. * @throws Zend_Search_Lucene_Exception
  341. */
  342. public function highlightExtended($words, $callback, $params = array())
  343. ]]></programlisting>
  344. </para>
  345. <para>
  346. Pour personnaliser le comportement de mise en évidence, utilisez la méthode
  347. <methodname>highlightExtended()</methodname> avec le callback spécifié qui prendra
  348. un ou plusieurs paramètres.
  349. <footnote>
  350. <para>
  351. Le premier paramètre est un fragment de code HTML pour la mise en évidence et
  352. les suivants sont dépendants du comportement du callback. La valeur de retour
  353. est un fragment HTML mise en évidence.
  354. </para>
  355. </footnote>
  356. , ou étendez la classe <classname>Zend_Search_Lucene_Document_Html</classname> et
  357. redéfinissez la méthode <methodname>applyColour($stringToHighlight, $colour)</methodname>
  358. qui est utilisée comme le callback de mise en évidence par défaut.
  359. <footnote>
  360. <para>
  361. Dans les deux cas, le HTML retourné est automatiquement transformé en
  362. <acronym>XHTML</acronym> valide.
  363. </para>
  364. </footnote>
  365. </para>
  366. <para>
  367. Les <link linkend="zend.view.helpers">View helpers</link> peuvent également être utilisés
  368. comme des callbacks dans un contexte d'affichage du script :
  369. <programlisting language="php"><![CDATA[
  370. $doc->highlightExtended('word1 word2 word3...', array($this, 'myViewHelper'));
  371. ]]></programlisting>
  372. </para>
  373. <para>
  374. Le résultat de l'opération de mise en évidence est récupéré avec
  375. la méthode <code>Zend_Search_Lucene_Document_Html->getHTML()</code>.
  376. </para>
  377. <note>
  378. <para>
  379. La mise en évidence est exécutée dans les termes de l'analyseur courant. Donc toutes
  380. les formes de mot(s) reconnues par l'analyseur seront mises en évidence.
  381. </para>
  382. <para>
  383. Ex.: Si l'analyseur courant est insensible à la casse et que l'on demande à mettre
  384. en évidence le mot 'text', alors 'text', 'Text', 'TEXT' ou toute autre combinaison de
  385. casse seront mis en évidence.
  386. </para>
  387. <para>
  388. Dans le même ordre d'idées, si l'analyseur courant supporte les requêtes proches (stemming)
  389. et que l'on souhaite mettre en évidence 'indexed', alors 'index', 'indexing', 'indices' et
  390. d'autres mots proches seront mis en évidences.
  391. </para>
  392. <para>
  393. A l'inverse, si un mot est ignoré par l'analyseur courant (ex. si un filtre pour
  394. ignorer les mots trop courts est appliqué à l'analyseur), alors rien ne sera mis en évidence.
  395. </para>
  396. </note>
  397. <para>
  398. La seconde option est d'utiliser la méthode
  399. <code>Zend_Search_Lucene_Search_Query->highlightMatches(string $inputHTML[,
  400. $defaultEncoding = 'UTF-8'[,
  401. Zend_Search_Lucene_Search_Highlighter_Interface $highlighter]])</code>:
  402. <programlisting language="php"><![CDATA[
  403. $query = Zend_Search_Lucene_Search_QueryParser::parse($queryStr);
  404. $highlightedHTML = $query->highlightMatches($sourceHTML);
  405. ]]></programlisting>
  406. </para>
  407. <para>
  408. Le second paramètre optionnel est l'encodage par défaut du document HTML. Il est
  409. utilisé si l'encodage n'est pas spécifié dans le metatag HTTP-EQUIV Content-Type.
  410. </para>
  411. <para>
  412. Le troisième paramètre optionnel est un objet de mise en évidence qui doit
  413. implémenter l'interface <classname>Zend_Search_Lucene_Search_Highlighter_Interface</classname>:
  414. <programlisting language="php"><![CDATA[
  415. interface Zend_Search_Lucene_Search_Highlighter_Interface
  416. {
  417. /**
  418. * Définit le document pour la mise en évidence
  419. *
  420. * @param Zend_Search_Lucene_Document_Html $document
  421. */
  422. public function setDocument(Zend_Search_Lucene_Document_Html $document);
  423. /**
  424. * Récupère le document pour la mise en évidence
  425. *
  426. * @return Zend_Search_Lucene_Document_Html $document
  427. */
  428. public function getDocument();
  429. /**
  430. * Mise en évidence des mots spécifiés (appelée une fois par sous-requête)
  431. *
  432. * @param string|array $words Les mots à mettre en évidence. Ils peuvent être organisés
  433. * dans un tableau ou une chaîne de caractères.
  434. */
  435. public function highlight($words);
  436. }
  437. ]]></programlisting>
  438. Où l'objet <classname>Zend_Search_Lucene_Document_Html</classname> est un objet
  439. construit à partir de la source HTML fournie par la méthode
  440. <classname>Zend_Search_Lucene_Search_Query->highlightMatches()</classname>
  441. </para>
  442. <para>
  443. Si le paramètre <varname>$highlighter</varname> est omis, un objet
  444. <classname>Zend_Search_Lucene_Search_Highlighter_Default</classname> est
  445. instancié et utilisé.
  446. </para>
  447. <para>
  448. La méthode de mise en évidence <methodname>highlight()</methodname> est invoquée une
  449. fois par sous-requête, ainsi elle a la possibilité de différencier la mise en évidence
  450. pour chacune.
  451. </para>
  452. <para>
  453. La mise en évidence par défaut le fait en parcourant une table prédéfinie de couleurs.
  454. Vous pouvez implémenter votre propre classe de mise en évidence ou juste étendre la classe
  455. par défaut et redéfinir la table de couleurs.
  456. </para>
  457. <para>
  458. <code>Zend_Search_Lucene_Search_Query->htmlFragmentHighlightMatches()</code> a un comportement
  459. similaire. La seule différence est qu'il prend en entrée et retourne un fragment HTML sans
  460. les balises &lt;>HTML>, &lt;HEAD>, &lt;BODY>. Néanmoins, le fragment est automatiquement
  461. transformé en <acronym>XHTML</acronym> valide.
  462. </para>
  463. </sect2>
  464. </sect1>