PageRenderTime 44ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Search/Lucene/Search/Query/Range.php

https://github.com/joseph-montanez/ZendTickets
PHP | 377 lines | 176 code | 49 blank | 152 comment | 48 complexity | 110c02fde10d062f7421b271d86a6199 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, MIT
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Search_Lucene
  17. * @subpackage Search
  18. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Range.php 23775 2011-03-01 17:25:24Z ralph $
  21. */
  22. /** Zend_Search_Lucene_Search_Query */
  23. require_once 'Zend/Search/Lucene/Search/Query.php';
  24. /**
  25. * @category Zend
  26. * @package Zend_Search_Lucene
  27. * @subpackage Search
  28. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  29. * @license http://framework.zend.com/license/new-bsd New BSD License
  30. */
  31. class Zend_Search_Lucene_Search_Query_Range extends Zend_Search_Lucene_Search_Query
  32. {
  33. /**
  34. * Lower term.
  35. *
  36. * @var Zend_Search_Lucene_Index_Term
  37. */
  38. private $_lowerTerm;
  39. /**
  40. * Upper term.
  41. *
  42. * @var Zend_Search_Lucene_Index_Term
  43. */
  44. private $_upperTerm;
  45. /**
  46. * Search field
  47. *
  48. * @var string
  49. */
  50. private $_field;
  51. /**
  52. * Inclusive
  53. *
  54. * @var boolean
  55. */
  56. private $_inclusive;
  57. /**
  58. * Matched terms.
  59. *
  60. * Matched terms list.
  61. * It's filled during the search (rewrite operation) and may be used for search result
  62. * post-processing
  63. *
  64. * Array of Zend_Search_Lucene_Index_Term objects
  65. *
  66. * @var array
  67. */
  68. private $_matches = null;
  69. /**
  70. * Zend_Search_Lucene_Search_Query_Range constructor.
  71. *
  72. * @param Zend_Search_Lucene_Index_Term|null $lowerTerm
  73. * @param Zend_Search_Lucene_Index_Term|null $upperTerm
  74. * @param boolean $inclusive
  75. * @throws Zend_Search_Lucene_Exception
  76. */
  77. public function __construct($lowerTerm, $upperTerm, $inclusive)
  78. {
  79. if ($lowerTerm === null && $upperTerm === null) {
  80. require_once 'Zend/Search/Lucene/Exception.php';
  81. throw new Zend_Search_Lucene_Exception('At least one term must be non-null');
  82. }
  83. if ($lowerTerm !== null && $upperTerm !== null && $lowerTerm->field != $upperTerm->field) {
  84. require_once 'Zend/Search/Lucene/Exception.php';
  85. throw new Zend_Search_Lucene_Exception('Both terms must be for the same field');
  86. }
  87. $this->_field = ($lowerTerm !== null)? $lowerTerm->field : $upperTerm->field;
  88. $this->_lowerTerm = $lowerTerm;
  89. $this->_upperTerm = $upperTerm;
  90. $this->_inclusive = $inclusive;
  91. }
  92. /**
  93. * Get query field name
  94. *
  95. * @return string|null
  96. */
  97. public function getField()
  98. {
  99. return $this->_field;
  100. }
  101. /**
  102. * Get lower term
  103. *
  104. * @return Zend_Search_Lucene_Index_Term|null
  105. */
  106. public function getLowerTerm()
  107. {
  108. return $this->_lowerTerm;
  109. }
  110. /**
  111. * Get upper term
  112. *
  113. * @return Zend_Search_Lucene_Index_Term|null
  114. */
  115. public function getUpperTerm()
  116. {
  117. return $this->_upperTerm;
  118. }
  119. /**
  120. * Get upper term
  121. *
  122. * @return boolean
  123. */
  124. public function isInclusive()
  125. {
  126. return $this->_inclusive;
  127. }
  128. /**
  129. * Re-write query into primitive queries in the context of specified index
  130. *
  131. * @param Zend_Search_Lucene_Interface $index
  132. * @return Zend_Search_Lucene_Search_Query
  133. */
  134. public function rewrite(Zend_Search_Lucene_Interface $index)
  135. {
  136. $this->_matches = array();
  137. if ($this->_field === null) {
  138. // Search through all fields
  139. $fields = $index->getFieldNames(true /* indexed fields list */);
  140. } else {
  141. $fields = array($this->_field);
  142. }
  143. require_once 'Zend/Search/Lucene.php';
  144. $maxTerms = Zend_Search_Lucene::getTermsPerQueryLimit();
  145. foreach ($fields as $field) {
  146. $index->resetTermsStream();
  147. require_once 'Zend/Search/Lucene/Index/Term.php';
  148. if ($this->_lowerTerm !== null) {
  149. $lowerTerm = new Zend_Search_Lucene_Index_Term($this->_lowerTerm->text, $field);
  150. $index->skipTo($lowerTerm);
  151. if (!$this->_inclusive &&
  152. $index->currentTerm() == $lowerTerm) {
  153. // Skip lower term
  154. $index->nextTerm();
  155. }
  156. } else {
  157. $index->skipTo(new Zend_Search_Lucene_Index_Term('', $field));
  158. }
  159. if ($this->_upperTerm !== null) {
  160. // Walk up to the upper term
  161. $upperTerm = new Zend_Search_Lucene_Index_Term($this->_upperTerm->text, $field);
  162. while ($index->currentTerm() !== null &&
  163. $index->currentTerm()->field == $field &&
  164. strcmp($index->currentTerm()->text, $upperTerm->text) < 0) {
  165. $this->_matches[] = $index->currentTerm();
  166. if ($maxTerms != 0 && count($this->_matches) > $maxTerms) {
  167. require_once 'Zend/Search/Lucene/Exception.php';
  168. throw new Zend_Search_Lucene_Exception('Terms per query limit is reached.');
  169. }
  170. $index->nextTerm();
  171. }
  172. if ($this->_inclusive && $index->currentTerm() == $upperTerm) {
  173. // Include upper term into result
  174. $this->_matches[] = $upperTerm;
  175. }
  176. } else {
  177. // Walk up to the end of field data
  178. while ($index->currentTerm() !== null && $index->currentTerm()->field == $field) {
  179. $this->_matches[] = $index->currentTerm();
  180. if ($maxTerms != 0 && count($this->_matches) > $maxTerms) {
  181. require_once 'Zend/Search/Lucene/Exception.php';
  182. throw new Zend_Search_Lucene_Exception('Terms per query limit is reached.');
  183. }
  184. $index->nextTerm();
  185. }
  186. }
  187. $index->closeTermsStream();
  188. }
  189. if (count($this->_matches) == 0) {
  190. require_once 'Zend/Search/Lucene/Search/Query/Empty.php';
  191. return new Zend_Search_Lucene_Search_Query_Empty();
  192. } else if (count($this->_matches) == 1) {
  193. require_once 'Zend/Search/Lucene/Search/Query/Term.php';
  194. return new Zend_Search_Lucene_Search_Query_Term(reset($this->_matches));
  195. } else {
  196. require_once 'Zend/Search/Lucene/Search/Query/MultiTerm.php';
  197. $rewrittenQuery = new Zend_Search_Lucene_Search_Query_MultiTerm();
  198. foreach ($this->_matches as $matchedTerm) {
  199. $rewrittenQuery->addTerm($matchedTerm);
  200. }
  201. return $rewrittenQuery;
  202. }
  203. }
  204. /**
  205. * Optimize query in the context of specified index
  206. *
  207. * @param Zend_Search_Lucene_Interface $index
  208. * @return Zend_Search_Lucene_Search_Query
  209. */
  210. public function optimize(Zend_Search_Lucene_Interface $index)
  211. {
  212. require_once 'Zend/Search/Lucene/Exception.php';
  213. throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)');
  214. }
  215. /**
  216. * Return query terms
  217. *
  218. * @return array
  219. * @throws Zend_Search_Lucene_Exception
  220. */
  221. public function getQueryTerms()
  222. {
  223. if ($this->_matches === null) {
  224. require_once 'Zend/Search/Lucene/Exception.php';
  225. throw new Zend_Search_Lucene_Exception('Search or rewrite operations have to be performed before.');
  226. }
  227. return $this->_matches;
  228. }
  229. /**
  230. * Constructs an appropriate Weight implementation for this query.
  231. *
  232. * @param Zend_Search_Lucene_Interface $reader
  233. * @return Zend_Search_Lucene_Search_Weight
  234. * @throws Zend_Search_Lucene_Exception
  235. */
  236. public function createWeight(Zend_Search_Lucene_Interface $reader)
  237. {
  238. require_once 'Zend/Search/Lucene/Exception.php';
  239. throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)');
  240. }
  241. /**
  242. * Execute query in context of index reader
  243. * It also initializes necessary internal structures
  244. *
  245. * @param Zend_Search_Lucene_Interface $reader
  246. * @param Zend_Search_Lucene_Index_DocsFilter|null $docsFilter
  247. * @throws Zend_Search_Lucene_Exception
  248. */
  249. public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null)
  250. {
  251. require_once 'Zend/Search/Lucene/Exception.php';
  252. throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)');
  253. }
  254. /**
  255. * Get document ids likely matching the query
  256. *
  257. * It's an array with document ids as keys (performance considerations)
  258. *
  259. * @return array
  260. * @throws Zend_Search_Lucene_Exception
  261. */
  262. public function matchedDocs()
  263. {
  264. require_once 'Zend/Search/Lucene/Exception.php';
  265. throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)');
  266. }
  267. /**
  268. * Score specified document
  269. *
  270. * @param integer $docId
  271. * @param Zend_Search_Lucene_Interface $reader
  272. * @return float
  273. * @throws Zend_Search_Lucene_Exception
  274. */
  275. public function score($docId, Zend_Search_Lucene_Interface $reader)
  276. {
  277. require_once 'Zend/Search/Lucene/Exception.php';
  278. throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)');
  279. }
  280. /**
  281. * Query specific matches highlighting
  282. *
  283. * @param Zend_Search_Lucene_Search_Highlighter_Interface $highlighter Highlighter object (also contains doc for highlighting)
  284. */
  285. protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter)
  286. {
  287. $words = array();
  288. $docBody = $highlighter->getDocument()->getFieldUtf8Value('body');
  289. require_once 'Zend/Search/Lucene/Analysis/Analyzer.php';
  290. $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($docBody, 'UTF-8');
  291. $lowerTermText = ($this->_lowerTerm !== null)? $this->_lowerTerm->text : null;
  292. $upperTermText = ($this->_upperTerm !== null)? $this->_upperTerm->text : null;
  293. if ($this->_inclusive) {
  294. foreach ($tokens as $token) {
  295. $termText = $token->getTermText();
  296. if (($lowerTermText == null || $lowerTermText <= $termText) &&
  297. ($upperTermText == null || $termText <= $upperTermText)) {
  298. $words[] = $termText;
  299. }
  300. }
  301. } else {
  302. foreach ($tokens as $token) {
  303. $termText = $token->getTermText();
  304. if (($lowerTermText == null || $lowerTermText < $termText) &&
  305. ($upperTermText == null || $termText < $upperTermText)) {
  306. $words[] = $termText;
  307. }
  308. }
  309. }
  310. $highlighter->highlight($words);
  311. }
  312. /**
  313. * Print a query
  314. *
  315. * @return string
  316. */
  317. public function __toString()
  318. {
  319. // It's used only for query visualisation, so we don't care about characters escaping
  320. return (($this->_field === null)? '' : $this->_field . ':')
  321. . (($this->_inclusive)? '[' : '{')
  322. . (($this->_lowerTerm !== null)? $this->_lowerTerm->text : 'null')
  323. . ' TO '
  324. . (($this->_upperTerm !== null)? $this->_upperTerm->text : 'null')
  325. . (($this->_inclusive)? ']' : '}')
  326. . (($this->getBoost() != 1)? '^' . round($this->getBoost(), 4) : '');
  327. }
  328. }