Zend_Search_Lucene-Extending.xml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 15157 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.search.lucene.extending">
  5. <title>Erweiterbarkeit</title>
  6. <sect2 id="zend.search.lucene.extending.analysis">
  7. <title>Textanalyse</title>
  8. <para>
  9. Die <classname>Zend_Search_Lucene_Analysis_Analyzer</classname> Klasse wird vom Indexer verwendet,
  10. um die Textfelder der Dokumente in Abschnitte aufzuteilen.
  11. </para>
  12. <para>
  13. Die <classname>Zend_Search_Lucene_Analysis_Analyzer::getDefault()</classname> und
  14. <classname>Zend_Search_Lucene_Analysis_Analyzer::setDefault()</classname> Methoden werden verwendet, um
  15. den Standardanalysator zu bekommen oder festzulegen.
  16. </para>
  17. <para>
  18. Man kann einen eigenen Textanalysator zuordnen oder ihn aus den vordefinierten
  19. Analysatoren auswählen: <classname>Zend_Search_Lucene_Analysis_Analyzer_Common_Text</classname>
  20. und <classname>Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive</classname>
  21. (Standard). Beide interpretieren einen Abschnitt als eine Sequenz aus Buchstaben.
  22. <classname>Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive</classname>
  23. konvertiert alle Abschnitte in Kleinbuchstaben.
  24. </para>
  25. <para>
  26. Um zwischen Analysatoren zu wechseln:
  27. </para>
  28. <programlisting role="php"><![CDATA[
  29. Zend_Search_Lucene_Analysis_Analyzer::setDefault(
  30. new Zend_Search_Lucene_Analysis_Analyzer_Common_Text());
  31. ...
  32. $index->addDocument($doc);
  33. ]]></programlisting>
  34. <para>
  35. Die <classname>Zend_Search_Lucene_Analysis_Analyzer_Common</classname> Klasse wurde als Anker für alle
  36. benutzerdefinierten Analysatoren entwickelt. Benutzer sollten nur die
  37. <code>reset()</code> und <code>nextToken()</code> Methoden definieren, welche ihren String
  38. von der $_input Eigenschaft nimmt und die Abschnitte Stück für Stück zurückgibt
  39. (ein <code>null</code> Wert indiziert das Ende des Streams).
  40. </para>
  41. <para>
  42. Die <code>nextToken()</code> Methode sollte die <code>normalize()</code> Methode auf
  43. jedem Token aufrufen. Das erlaubt die Verwendung von Abschnittsfiltern im eigenen Analysator.
  44. </para>
  45. <para>
  46. Hier ist ein Beispiel für einen eigenen Analysator, welcher Wörter mit Ziffern als
  47. Begriffe akzeptiert:
  48. <example id="zend.search.lucene.extending.analysis.example-1">
  49. <title>Eigener Textanalysator</title>
  50. <programlisting role="php"><![CDATA[
  51. /**
  52. * Hier ist ein eigener Textanalysator, der Worte mit Ziffern
  53. * als einen Begriff behandelt
  54. */
  55. class My_Analyzer extends Zend_Search_Lucene_Analysis_Analyzer_Common
  56. {
  57. private $_position;
  58. /**
  59. * Reset token stream
  60. */
  61. public function reset()
  62. {
  63. $this->_position = 0;
  64. }
  65. /**
  66. * Tokenization stream API
  67. * Get next token
  68. * Returns null at the end of stream
  69. *
  70. * @return Zend_Search_Lucene_Analysis_Token|null
  71. */
  72. public function nextToken()
  73. {
  74. if ($this->_input === null) {
  75. return null;
  76. }
  77. while ($this->_position < strlen($this->_input)) {
  78. // skip white space
  79. while ($this->_position < strlen($this->_input) &&
  80. !ctype_alnum( $this->_input[$this->_position] )) {
  81. $this->_position++;
  82. }
  83. $termStartPosition = $this->_position;
  84. // read token
  85. while ($this->_position < strlen($this->_input) &&
  86. ctype_alnum( $this->_input[$this->_position] )) {
  87. $this->_position++;
  88. }
  89. // Empty token, end of stream.
  90. if ($this->_position == $termStartPosition) {
  91. return null;
  92. }
  93. $token = new Zend_Search_Lucene_Analysis_Token(
  94. substr($this->_input,
  95. $termStartPosition,
  96. $this->_position -
  97. $termStartPosition),
  98. $termStartPosition,
  99. $this->_position);
  100. $token = $this->normalize($token);
  101. if ($token !== null) {
  102. return $token;
  103. }
  104. // Continue if token is skipped
  105. }
  106. return null;
  107. }
  108. }
  109. Zend_Search_Lucene_Analysis_Analyzer::setDefault(
  110. new My_Analyzer());
  111. ]]></programlisting>
  112. </example>
  113. </para>
  114. </sect2>
  115. <sect2 id="zend.search.lucene.extending.filters">
  116. <title>Filtern von Tokens</title>
  117. <para>
  118. Der <classname>Zend_Search_Lucene_Analysis_Analyzer_Common</classname> Analisator bietet auch einen
  119. Mechanismus zum Filtern von Tokens.
  120. </para>
  121. <para>
  122. Die <classname>Zend_Search_Lucene_Analysis_TokenFilter</classname> Klasse bietet ein abstraktes Interface für
  123. solche Filter. Eigene Filter sollten diese Klasse direkt oder indirekt erweitern.
  124. </para>
  125. <para>
  126. Alle eigenen Filter müssen die <code>normalize()</code> Methode implementieren, welche den
  127. Eingabe Token verändern oder signalisieren, dass der Token übersprungen werden sollte.
  128. </para>
  129. <para>
  130. Es gibt bereits drei Filter die im Analyse Unterpaket definierte sind:
  131. <itemizedlist>
  132. <listitem>
  133. <para>
  134. <classname>Zend_Search_Lucene_Analysis_TokenFilter_LowerCase</classname>
  135. </para>
  136. </listitem>
  137. <listitem>
  138. <para>
  139. <classname>Zend_Search_Lucene_Analysis_TokenFilter_ShortWords</classname>
  140. </para>
  141. </listitem>
  142. <listitem>
  143. <para>
  144. <classname>Zend_Search_Lucene_Analysis_TokenFilter_StopWords</classname>
  145. </para>
  146. </listitem>
  147. </itemizedlist>
  148. </para>
  149. <para>
  150. Der <code>LowerCase</code> Filter wird bereits standardmäßig für den
  151. <classname>Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive</classname> Analysator
  152. verwendet.
  153. </para>
  154. <para>
  155. Die <code>ShortWords</code> und <code>StopWords</code> Filter können mit bereits definierten oder
  156. eigenen Analysatoren wie folgt verwendet werden:
  157. <programlisting role="php"><![CDATA[
  158. $stopWords = array('a', 'an', 'at', 'the', 'and', 'or', 'is', 'am');
  159. $stopWordsFilter =
  160. new Zend_Search_Lucene_Analysis_TokenFilter_StopWords($stopWords);
  161. $analyzer =
  162. new Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive();
  163. $analyzer->addFilter($stopWordsFilter);
  164. Zend_Search_Lucene_Analysis_Analyzer::setDefault($analyzer);
  165. ]]></programlisting>
  166. <programlisting role="php"><![CDATA[
  167. $shortWordsFilter = new Zend_Search_Lucene_Analysis_TokenFilter_ShortWords();
  168. $analyzer =
  169. new Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive();
  170. $analyzer->addFilter($shortWordsFilter);
  171. Zend_Search_Lucene_Analysis_Analyzer::setDefault($analyzer);
  172. ]]></programlisting>
  173. </para>
  174. <para>
  175. Der <classname>Zend_Search_Lucene_Analysis_TokenFilter_StopWords</classname> Konstruktor nimmt
  176. ein Array mit Stopwörtern als Eingabe entgegen. Aber Stopwörter können auch aus einer
  177. Datei geladen werden:
  178. <programlisting role="php"><![CDATA[
  179. $stopWordsFilter = new Zend_Search_Lucene_Analysis_TokenFilter_StopWords();
  180. $stopWordsFilter->loadFromFile($my_stopwords_file);
  181. $analyzer =
  182. new Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive();
  183. $analyzer->addFilter($stopWordsFilter);
  184. Zend_Search_Lucene_Analysis_Analyzer::setDefault($analyzer);
  185. ]]></programlisting>
  186. Die Datei sollte eine normale Textdatei mit einem Wort pro Zeile sein. Das '#' Zeichen markiert eine
  187. Zeile als Kommentar.
  188. </para>
  189. <para>
  190. Der <classname>Zend_Search_Lucene_Analysis_TokenFilter_ShortWords</classname> Konstruktor hat ein
  191. optionales Argument. Es ist das Limit für die Wortlänge, der standardmäßig 2 ist.
  192. </para>
  193. </sect2>
  194. <sect2 id="zend.search.lucene.extending.scoring">
  195. <title>Algorithmen für Punktwertermittlung</title>
  196. <para>
  197. Der Punktwert einer Abfrage <literal>q</literal> für das Dokument <literal>d</literal>
  198. ist wie folgt definiert:
  199. </para>
  200. <para>
  201. <code>score(q,d) = sum( tf(t in d) * idf(t) * getBoost(t.field in d) * lengthNorm(t.field in d) ) *
  202. coord(q,d) * queryNorm(q)</code>
  203. </para>
  204. <para>
  205. tf(t in d) - <classname>Zend_Search_Lucene_Search_Similarity::tf($freq)</classname> -
  206. ein Punktwertfaktor, der auf der Häufigkeit des Begriffes oder der Phrase innerhalb des
  207. Dokuments basiert.
  208. </para>
  209. <para>
  210. idf(t) - <classname>Zend_Search_Lucene_Search_Similarity::tf($term, $reader)</classname> -
  211. ein Punktwertfaktor für einen einfachen Begriff mit dem spezifischen Index.
  212. </para>
  213. <para>
  214. getBoost(t.field in d) - der Verstärkungsfaktor für das Begriffsfeld.
  215. </para>
  216. <para>
  217. lengthNorm($term) - der Normalisierungswert für ein Feld, der die Gesamtzahl der
  218. Begriffe innerhalb eines Fields enthält. Dieser Wert wird im Index abgelegt. Diese Wert
  219. werden zusammen mit dem Verstärkungsfaktor im Index abgelegt und vom Suchcode für
  220. alle Treffer eines Feldes zu Punktwerten multipliziert.
  221. </para>
  222. <para>
  223. Treffer in längeren Feldern sind weniger präzise, so dass Implementierungen dieser
  224. Methode normalerweise kleinere Werte zurückgeben, wenn numTokens groß ist, und größere
  225. Werte, wenn numTokens klein ist.
  226. </para>
  227. <para>
  228. coord(q,d) - <classname>Zend_Search_Lucene_Search_Similarity::coord($overlap, $maxOverlap)</classname> -
  229. ein Punktwertfaktor, der auf dem Anteil aller Abfragebegriffe basiert, die ein Dokument
  230. enthält.
  231. </para>
  232. <para>
  233. Das Vorhandensein eines grossen Teils der Abfragebegriffe gibt einen besseren Treffer
  234. für die Abfrage an, so dass Implementierungen dieser Methode normalerweise größere
  235. Werte zurückgeben, wenn das Verhältnis zwischen diesen Parametern groß ist, und kleinere
  236. Werte, wenn es klein ist.
  237. </para>
  238. <para>
  239. queryNorm(q) - der Normalisierungswert für eine Abfrage, welcher die Summe der
  240. quadrierten Gewichtungen jedes Begriffes eine Abfrage enthält. Dieser Wert wird für das
  241. Gewicht jedes Abfragebegriffes multipliziert.
  242. term.
  243. </para>
  244. <para>
  245. Dieses wirkt sich nicht auf die Reihenfolge ist, versucht aber, die Punktwerte
  246. für verschiedenen Abfragen vergleichbar zu machen.
  247. </para>
  248. <para>
  249. Der Algorithmen für die Punktwertermittlung kann durch die Definition einer eigenen
  250. Ähnlichkeitsklasse angepasst werden. Hierfür muss die
  251. <classname>Zend_Search_Lucene_Search_Similarity</classname> Klasse wie unten angegeben erweitert und anschließend die
  252. <classname>Zend_Search_Lucene_Search_Similarity::setDefault($similarity);</classname> Methode verwendet
  253. werden um Sie als Standard zu setzen.
  254. </para>
  255. <programlisting role="php"><![CDATA[
  256. class MySimilarity extends Zend_Search_Lucene_Search_Similarity {
  257. public function lengthNorm($fieldName, $numTerms) {
  258. return 1.0/sqrt($numTerms);
  259. }
  260. public function queryNorm($sumOfSquaredWeights) {
  261. return 1.0/sqrt($sumOfSquaredWeights);
  262. }
  263. public function tf($freq) {
  264. return sqrt($freq);
  265. }
  266. /**
  267. * Es wird jetzt nicht verwendet. Berechnet den Wert eines Treffers
  268. * für eine ungenauen Phrasenanfrage.
  269. */
  270. public function sloppyFreq($distance) {
  271. return 1.0;
  272. }
  273. public function idfFreq($docFreq, $numDocs) {
  274. return log($numDocs/(float)($docFreq+1)) + 1.0;
  275. }
  276. public function coord($overlap, $maxOverlap) {
  277. return $overlap/(float)$maxOverlap;
  278. }
  279. }
  280. $mySimilarity = new MySimilarity();
  281. Zend_Search_Lucene_Search_Similarity::setDefault($mySimilarity);
  282. ]]></programlisting>
  283. </sect2>
  284. <sect2 id="zend.search.lucene.extending.storage">
  285. <title>Storage Container</title>
  286. <para>
  287. Die abstrakte Klasse <classname>Zend_Search_Lucene_Storage_Directory</classname> definiert
  288. Funktionalitäten für Verzeichnisse.
  289. </para>
  290. <para>
  291. Der <classname>Zend_Search_Lucene</classname> Konstruktur verwendet als Eingabe entweder einen
  292. String oder ein <classname>Zend_Search_Lucene_Storage_Directory</classname> Objekt.
  293. </para>
  294. <para>
  295. Die <classname>Zend_Search_Lucene_Storage_Directory_Filesystem</classname> Klasse implementiert
  296. Verzeichnisfunktionalitäten für ein Dateisystem.
  297. </para>
  298. <para>
  299. Wenn ein String als Eingabe für den <classname>Zend_Search_Lucene</classname> Konstruktur
  300. verwendet wird, behandelt der Indexleser (das <classname>Zend_Search_Lucene Objekt</classname>)
  301. es wie einen Dateipfad und instanziiert das
  302. <classname>Zend_Search_Lucene_Storage_Directory_Filesystem</classname> Objekt.
  303. </para>
  304. <para>
  305. Du kannst deinen eigenen Verzeichnisimplementation durch die Erweiterung der
  306. <classname>Zend_Search_Lucene_Storage_Directory</classname> Klasse definieren.
  307. </para>
  308. <para>
  309. <classname>Zend_Search_Lucene_Storage_Directory</classname> Methoden:
  310. </para>
  311. <programlisting><![CDATA[
  312. abstract class Zend_Search_Lucene_Storage_Directory {
  313. /**
  314. * Schließt den Speicher
  315. *
  316. * @return void
  317. */
  318. abstract function close();
  319. /**
  320. * Erstellt im Verzeichnis eine neue, leere Datei mit dem übergebenen Dateinamen $filename.
  321. *
  322. * @param string $name
  323. * @return void
  324. */
  325. abstract function createFile($filename);
  326. /**
  327. * Entfernt eine vorhande Datei $filename aus dem Verzeichnis.
  328. *
  329. * @param string $filename
  330. * @return void
  331. */
  332. abstract function deleteFile($filename);
  333. /**
  334. * Gibt true zurück, wenn eine Datei mit dem übergebenen Dateinamen $filename existiert
  335. *
  336. * @param string $filename
  337. * @return boolean
  338. */
  339. abstract function fileExists($filename);
  340. /**
  341. * Gibt die länge eine Datei $filename im Verzeichnis zurück
  342. *
  343. * @param string $filename
  344. * @return integer
  345. */
  346. abstract function fileLength($filename);
  347. /**
  348. * Gibt den UNIX Zeitstempel für die letzte Änderung der Datei $filename zurück.
  349. *
  350. * @param string $filename
  351. * @return integer
  352. */
  353. abstract function fileModified($filename);
  354. /**
  355. * Benennt eine vorhandene Datei im Verzeichnis um.
  356. *
  357. * @param string $from
  358. * @param string $to
  359. * @return void
  360. */
  361. abstract function renameFile($from, $to);
  362. /**
  363. * Ändert die Änderungstzeit der Datei $filename auf jetzt um
  364. *
  365. * @param string $filename
  366. * @return void
  367. */
  368. abstract function touchFile($filename);
  369. /**
  370. * Gibt ein Zend_Search_Lucene_Storage_File Objekt für den^
  371. * Dateinamen $filename aus dem Verzeichnis zurück.
  372. *
  373. * @param string $filename
  374. * @return Zend_Search_Lucene_Storage_File
  375. */
  376. abstract function getFileObject($filename);
  377. }
  378. ]]>
  379. </programlisting>
  380. <para>
  381. Die <code>getFileObject($filename)</code> Methode einer
  382. <classname>Zend_Search_Lucene_Storage_Directory</classname> Instanz gibt ein
  383. <classname>Zend_Search_Lucene_Storage_File</classname> Objekt zurück.
  384. </para>
  385. <para>
  386. Die abstrakte Klasse <classname>Zend_Search_Lucene_Storage_File</classname> implementiert einfache
  387. Funktionen für Dateiabstraktion und das Lesen von Indexdateien.
  388. </para>
  389. <para>
  390. Es muß außerdem <classname>Zend_Search_Lucene_Storage_File</classname> für eine eigene
  391. Verzeichnisimplementation erweitert werden.
  392. </para>
  393. <para>
  394. Nur zwei Methoden der <classname>Zend_Search_Lucene_Storage_File</classname> Klasse müssen in
  395. der eigenen Implementation überschrieben werden:
  396. </para>
  397. <programlisting><![CDATA[
  398. class MyFile extends Zend_Search_Lucene_Storage_File {
  399. /**
  400. * Setzt den Indikator für die Dateiposition rückt den Dateizeiger
  401. * voran. Die neue Position, gemessen in Bytes vom Dateianfangm
  402. * wird erreicht durch das Hinzufügen eines Versatzes zu der
  403. * angegebenen Position. Dessen Werte sind wie folgt definiert:
  404. * SEEK_SET - Setze die Position auf den Versatz.
  405. * SEEK_CUR - Setze die Position auf die aktuelle Position plus Versatz.
  406. * SEEK_END - Setze die Position aufs Dateisende plus Versatz. (Um den
  407. * Zeiger auf eine Position vor dem Dateiende zu bewegen, übergebe einen
  408. * negativen Wert als Versatz.)
  409. * Bei Erfolg wird 0, andernfalls -1 zurückgegeben
  410. *
  411. * @param integer $offset
  412. * @param integer $whence
  413. * @return integer
  414. */
  415. public function seek($offset, $whence=SEEK_SET) {
  416. ...
  417. }
  418. /**
  419. * Lese $length Bytes aus der Datei und setze den Dateizeiger vor.
  420. *
  421. * @param integer $length
  422. * @return string
  423. */
  424. protected function _fread($length=1) {
  425. ...
  426. }
  427. }
  428. ]]>
  429. </programlisting>
  430. </sect2>
  431. </sect1>
  432. <!--
  433. vim:se ts=4 sw=4 et:
  434. -->