MultiSearcher.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  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. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. */
  20. /** Zend_Search_Lucene_TermStreamsPriorityQueue */
  21. require_once 'Zend/Search/Lucene/TermStreamsPriorityQueue.php';
  22. /** Zend_Search_Lucene_Interface */
  23. require_once 'Zend/Search/Lucene/Interface.php';
  24. /**
  25. * Multisearcher allows to search through several independent indexes.
  26. *
  27. * @category Zend
  28. * @package Zend_Search_Lucene
  29. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  30. * @license http://framework.zend.com/license/new-bsd New BSD License
  31. */
  32. class Zend_Search_Lucene_Interface_MultiSearcher implements Zend_Search_Lucene_Interface
  33. {
  34. /**
  35. * List of indices for searching.
  36. * Array of Zend_Search_Lucene_Interface objects
  37. *
  38. * @var array
  39. */
  40. protected $_indices;
  41. /**
  42. * Object constructor.
  43. *
  44. * @param array $indices Arrays of indices for search
  45. * @throws Zend_Search_Lucene_Exception
  46. */
  47. public function __construct($indices = array())
  48. {
  49. $this->_indices = $indices;
  50. foreach ($this->_indices as $index) {
  51. if (!$index instanceof Zend_Search_Lucene_Interface) {
  52. require_once 'Zend/Search/Lucene/Exception.php';
  53. throw new Zend_Search_Lucene_Exception('sub-index objects have to implement Zend_Search_Lucene_Interface.');
  54. }
  55. }
  56. }
  57. /**
  58. * Add index for searching.
  59. *
  60. * @param Zend_Search_Lucene_Interface $index
  61. */
  62. public function addIndex(Zend_Search_Lucene_Interface $index)
  63. {
  64. $this->_indices[] = $index;
  65. }
  66. /**
  67. * Get current generation number
  68. *
  69. * Returns generation number
  70. * 0 means pre-2.1 index format
  71. * -1 means there are no segments files.
  72. *
  73. * @param Zend_Search_Lucene_Storage_Directory $directory
  74. * @return integer
  75. * @throws Zend_Search_Lucene_Exception
  76. */
  77. public static function getActualGeneration(Zend_Search_Lucene_Storage_Directory $directory)
  78. {
  79. require_once 'Zend/Search/Lucene/Exception.php';
  80. throw new Zend_Search_Lucene_Exception("Generation number can't be retrieved for multi-searcher");
  81. }
  82. /**
  83. * Get segments file name
  84. *
  85. * @param integer $generation
  86. * @return string
  87. */
  88. public static function getSegmentFileName($generation)
  89. {
  90. return Zend_Search_Lucene::getSegmentFileName($generation);
  91. }
  92. /**
  93. * Get index format version
  94. *
  95. * @return integer
  96. * @throws Zend_Search_Lucene_Exception
  97. */
  98. public function getFormatVersion()
  99. {
  100. require_once 'Zend/Search/Lucene/Exception.php';
  101. throw new Zend_Search_Lucene_Exception("Format version can't be retrieved for multi-searcher");
  102. }
  103. /**
  104. * Set index format version.
  105. * Index is converted to this format at the nearest upfdate time
  106. *
  107. * @param int $formatVersion
  108. */
  109. public function setFormatVersion($formatVersion)
  110. {
  111. foreach ($this->_indices as $index) {
  112. $index->setFormatVersion($formatVersion);
  113. }
  114. }
  115. /**
  116. * Returns the Zend_Search_Lucene_Storage_Directory instance for this index.
  117. *
  118. * @return Zend_Search_Lucene_Storage_Directory
  119. */
  120. public function getDirectory()
  121. {
  122. require_once 'Zend/Search/Lucene/Exception.php';
  123. throw new Zend_Search_Lucene_Exception("Index directory can't be retrieved for multi-searcher");
  124. }
  125. /**
  126. * Returns the total number of documents in this index (including deleted documents).
  127. *
  128. * @return integer
  129. */
  130. public function count()
  131. {
  132. $count = 0;
  133. foreach ($this->_indices as $index) {
  134. $count += $this->_indices->count();
  135. }
  136. return $count;
  137. }
  138. /**
  139. * Returns one greater than the largest possible document number.
  140. * This may be used to, e.g., determine how big to allocate a structure which will have
  141. * an element for every document number in an index.
  142. *
  143. * @return integer
  144. */
  145. public function maxDoc()
  146. {
  147. return $this->count();
  148. }
  149. /**
  150. * Returns the total number of non-deleted documents in this index.
  151. *
  152. * @return integer
  153. */
  154. public function numDocs()
  155. {
  156. $docs = 0;
  157. foreach ($this->_indices as $index) {
  158. $docs += $this->_indices->numDocs();
  159. }
  160. return $docs;
  161. }
  162. /**
  163. * Checks, that document is deleted
  164. *
  165. * @param integer $id
  166. * @return boolean
  167. * @throws Zend_Search_Lucene_Exception Exception is thrown if $id is out of the range
  168. */
  169. public function isDeleted($id)
  170. {
  171. foreach ($this->_indices as $index) {
  172. $indexCount = $index->count();
  173. if ($indexCount > $id) {
  174. return $index->isDeleted($id);
  175. }
  176. $id -= $indexCount;
  177. }
  178. require_once 'Zend/Search/Lucene/Exception.php';
  179. throw new Zend_Search_Lucene_Exception('Document id is out of the range.');
  180. }
  181. /**
  182. * Set default search field.
  183. *
  184. * Null means, that search is performed through all fields by default
  185. *
  186. * Default value is null
  187. *
  188. * @param string $fieldName
  189. */
  190. public static function setDefaultSearchField($fieldName)
  191. {
  192. foreach ($this->_indices as $index) {
  193. $index->setDefaultSearchField($fieldName);
  194. }
  195. }
  196. /**
  197. * Get default search field.
  198. *
  199. * Null means, that search is performed through all fields by default
  200. *
  201. * @return string
  202. * @throws Zend_Search_Lucene_Exception
  203. */
  204. public static function getDefaultSearchField()
  205. {
  206. if (count($this->_indices) == 0) {
  207. require_once 'Zend/Search/Lucene/Exception.php';
  208. throw new Zend_Search_Lucene_Exception('Indices list is empty');
  209. }
  210. $defaultSearchField = reset($this->_indices)->getDefaultSearchField();
  211. foreach ($this->_indices as $index) {
  212. if ($index->getDefaultSearchField() !== $defaultSearchField) {
  213. require_once 'Zend/Search/Lucene/Exception.php';
  214. throw new Zend_Search_Lucene_Exception('Indices have different default search field.');
  215. }
  216. }
  217. return $defaultSearchField;
  218. }
  219. /**
  220. * Set result set limit.
  221. *
  222. * 0 (default) means no limit
  223. *
  224. * @param integer $limit
  225. */
  226. public static function setResultSetLimit($limit)
  227. {
  228. foreach ($this->_indices as $index) {
  229. $index->setResultSetLimit($limit);
  230. }
  231. }
  232. /**
  233. * Set result set limit.
  234. *
  235. * 0 means no limit
  236. *
  237. * @return integer
  238. * @throws Zend_Search_Lucene_Exception
  239. */
  240. public static function getResultSetLimit()
  241. {
  242. if (count($this->_indices) == 0) {
  243. require_once 'Zend/Search/Lucene/Exception.php';
  244. throw new Zend_Search_Lucene_Exception('Indices list is empty');
  245. }
  246. $defaultResultSetLimit = reset($this->_indices)->getResultSetLimit();
  247. foreach ($this->_indices as $index) {
  248. if ($index->getResultSetLimit() !== $defaultResultSetLimit) {
  249. require_once 'Zend/Search/Lucene/Exception.php';
  250. throw new Zend_Search_Lucene_Exception('Indices have different default search field.');
  251. }
  252. }
  253. return $defaultResultSetLimit;
  254. }
  255. /**
  256. * Retrieve index maxBufferedDocs option
  257. *
  258. * maxBufferedDocs is a minimal number of documents required before
  259. * the buffered in-memory documents are written into a new Segment
  260. *
  261. * Default value is 10
  262. *
  263. * @return integer
  264. * @throws Zend_Search_Lucene_Exception
  265. */
  266. public function getMaxBufferedDocs()
  267. {
  268. if (count($this->_indices) == 0) {
  269. require_once 'Zend/Search/Lucene/Exception.php';
  270. throw new Zend_Search_Lucene_Exception('Indices list is empty');
  271. }
  272. $maxBufferedDocs = reset($this->_indices)->getMaxBufferedDocs();
  273. foreach ($this->_indices as $index) {
  274. if ($index->getMaxBufferedDocs() !== $maxBufferedDocs) {
  275. require_once 'Zend/Search/Lucene/Exception.php';
  276. throw new Zend_Search_Lucene_Exception('Indices have different default search field.');
  277. }
  278. }
  279. return $maxBufferedDocs;
  280. }
  281. /**
  282. * Set index maxBufferedDocs option
  283. *
  284. * maxBufferedDocs is a minimal number of documents required before
  285. * the buffered in-memory documents are written into a new Segment
  286. *
  287. * Default value is 10
  288. *
  289. * @param integer $maxBufferedDocs
  290. */
  291. public function setMaxBufferedDocs($maxBufferedDocs)
  292. {
  293. foreach ($this->_indices as $index) {
  294. $index->setMaxBufferedDocs($maxBufferedDocs);
  295. }
  296. }
  297. /**
  298. * Retrieve index maxMergeDocs option
  299. *
  300. * maxMergeDocs is a largest number of documents ever merged by addDocument().
  301. * Small values (e.g., less than 10,000) are best for interactive indexing,
  302. * as this limits the length of pauses while indexing to a few seconds.
  303. * Larger values are best for batched indexing and speedier searches.
  304. *
  305. * Default value is PHP_INT_MAX
  306. *
  307. * @return integer
  308. * @throws Zend_Search_Lucene_Exception
  309. */
  310. public function getMaxMergeDocs()
  311. {
  312. if (count($this->_indices) == 0) {
  313. require_once 'Zend/Search/Lucene/Exception.php';
  314. throw new Zend_Search_Lucene_Exception('Indices list is empty');
  315. }
  316. $maxMergeDocs = reset($this->_indices)->getMaxMergeDocs();
  317. foreach ($this->_indices as $index) {
  318. if ($index->getMaxMergeDocs() !== $maxMergeDocs) {
  319. require_once 'Zend/Search/Lucene/Exception.php';
  320. throw new Zend_Search_Lucene_Exception('Indices have different default search field.');
  321. }
  322. }
  323. return $maxMergeDocs;
  324. }
  325. /**
  326. * Set index maxMergeDocs option
  327. *
  328. * maxMergeDocs is a largest number of documents ever merged by addDocument().
  329. * Small values (e.g., less than 10,000) are best for interactive indexing,
  330. * as this limits the length of pauses while indexing to a few seconds.
  331. * Larger values are best for batched indexing and speedier searches.
  332. *
  333. * Default value is PHP_INT_MAX
  334. *
  335. * @param integer $maxMergeDocs
  336. */
  337. public function setMaxMergeDocs($maxMergeDocs)
  338. {
  339. foreach ($this->_indices as $index) {
  340. $index->setMaxMergeDocs($maxMergeDocs);
  341. }
  342. }
  343. /**
  344. * Retrieve index mergeFactor option
  345. *
  346. * mergeFactor determines how often segment indices are merged by addDocument().
  347. * With smaller values, less RAM is used while indexing,
  348. * and searches on unoptimized indices are faster,
  349. * but indexing speed is slower.
  350. * With larger values, more RAM is used during indexing,
  351. * and while searches on unoptimized indices are slower,
  352. * indexing is faster.
  353. * Thus larger values (> 10) are best for batch index creation,
  354. * and smaller values (< 10) for indices that are interactively maintained.
  355. *
  356. * Default value is 10
  357. *
  358. * @return integer
  359. * @throws Zend_Search_Lucene_Exception
  360. */
  361. public function getMergeFactor()
  362. {
  363. if (count($this->_indices) == 0) {
  364. require_once 'Zend/Search/Lucene/Exception.php';
  365. throw new Zend_Search_Lucene_Exception('Indices list is empty');
  366. }
  367. $mergeFactor = reset($this->_indices)->getMergeFactor();
  368. foreach ($this->_indices as $index) {
  369. if ($index->getMergeFactor() !== $mergeFactor) {
  370. require_once 'Zend/Search/Lucene/Exception.php';
  371. throw new Zend_Search_Lucene_Exception('Indices have different default search field.');
  372. }
  373. }
  374. return $mergeFactor;
  375. }
  376. /**
  377. * Set index mergeFactor option
  378. *
  379. * mergeFactor determines how often segment indices are merged by addDocument().
  380. * With smaller values, less RAM is used while indexing,
  381. * and searches on unoptimized indices are faster,
  382. * but indexing speed is slower.
  383. * With larger values, more RAM is used during indexing,
  384. * and while searches on unoptimized indices are slower,
  385. * indexing is faster.
  386. * Thus larger values (> 10) are best for batch index creation,
  387. * and smaller values (< 10) for indices that are interactively maintained.
  388. *
  389. * Default value is 10
  390. *
  391. * @param integer $maxMergeDocs
  392. */
  393. public function setMergeFactor($mergeFactor)
  394. {
  395. foreach ($this->_indices as $index) {
  396. $index->setMaxMergeDocs($maxMergeDocs);
  397. }
  398. }
  399. /**
  400. * Performs a query against the index and returns an array
  401. * of Zend_Search_Lucene_Search_QueryHit objects.
  402. * Input is a string or Zend_Search_Lucene_Search_Query.
  403. *
  404. * @param mixed $query
  405. * @return array Zend_Search_Lucene_Search_QueryHit
  406. * @throws Zend_Search_Lucene_Exception
  407. */
  408. public function find($query)
  409. {
  410. $hitsList = array();
  411. $indexShift = 0;
  412. foreach ($this->_indices as $index) {
  413. $hits = $index->find($query);
  414. if ($indexShift != 0) {
  415. foreach ($hits as $hit) {
  416. $hit->id += $indexShift;
  417. }
  418. }
  419. $indexShift += $index->count();
  420. $hitsList[] = $hits;
  421. }
  422. /** @todo Implement advanced sorting */
  423. return call_user_func_array('array_merge', $hitsList);
  424. }
  425. /**
  426. * Returns a list of all unique field names that exist in this index.
  427. *
  428. * @param boolean $indexed
  429. * @return array
  430. */
  431. public function getFieldNames($indexed = false)
  432. {
  433. $fieldNamesList = array();
  434. foreach ($this->_indices as $index) {
  435. $fieldNamesList[] = $index->getFieldNames($indexed);
  436. }
  437. return array_unique(call_user_func_array('array_merge', $fieldNamesList));
  438. }
  439. /**
  440. * Returns a Zend_Search_Lucene_Document object for the document
  441. * number $id in this index.
  442. *
  443. * @param integer|Zend_Search_Lucene_Search_QueryHit $id
  444. * @return Zend_Search_Lucene_Document
  445. * @throws Zend_Search_Lucene_Exception Exception is thrown if $id is out of the range
  446. */
  447. public function getDocument($id)
  448. {
  449. if ($id instanceof Zend_Search_Lucene_Search_QueryHit) {
  450. /* @var $id Zend_Search_Lucene_Search_QueryHit */
  451. $id = $id->id;
  452. }
  453. foreach ($this->_indices as $index) {
  454. $indexCount = $index->count();
  455. if ($indexCount > $id) {
  456. return $index->getDocument($id);
  457. }
  458. $id -= $indexCount;
  459. }
  460. require_once 'Zend/Search/Lucene/Exception.php';
  461. throw new Zend_Search_Lucene_Exception('Document id is out of the range.');
  462. }
  463. /**
  464. * Returns true if index contain documents with specified term.
  465. *
  466. * Is used for query optimization.
  467. *
  468. * @param Zend_Search_Lucene_Index_Term $term
  469. * @return boolean
  470. */
  471. public function hasTerm(Zend_Search_Lucene_Index_Term $term)
  472. {
  473. foreach ($this->_indices as $index) {
  474. if ($index->hasTerm($term)) {
  475. return true;
  476. }
  477. }
  478. return false;
  479. }
  480. /**
  481. * Returns IDs of all the documents containing term.
  482. *
  483. * @param Zend_Search_Lucene_Index_Term $term
  484. * @param Zend_Search_Lucene_Index_DocsFilter|null $docsFilter
  485. * @return array
  486. * @throws Zend_Search_Lucene_Exception
  487. */
  488. public function termDocs(Zend_Search_Lucene_Index_Term $term, $docsFilter = null)
  489. {
  490. if ($docsFilter != null) {
  491. require_once 'Zend/Search/Lucene/Exception.php';
  492. throw new Zend_Search_Lucene_Exception('Document filters could not used with multi-searcher');
  493. }
  494. $docsList = array();
  495. $indexShift = 0;
  496. foreach ($this->_indices as $index) {
  497. $docs = $index->termDocs($term);
  498. if ($indexShift != 0) {
  499. foreach ($docs as $id => $docId) {
  500. $docs[$id] += $indexShift;
  501. }
  502. }
  503. $indexShift += $index->count();
  504. $docsList[] = $docs;
  505. }
  506. return call_user_func_array('array_merge', $docsList);
  507. }
  508. /**
  509. * Returns documents filter for all documents containing term.
  510. *
  511. * It performs the same operation as termDocs, but return result as
  512. * Zend_Search_Lucene_Index_DocsFilter object
  513. *
  514. * @param Zend_Search_Lucene_Index_Term $term
  515. * @param Zend_Search_Lucene_Index_DocsFilter|null $docsFilter
  516. * @return Zend_Search_Lucene_Index_DocsFilter
  517. * @throws Zend_Search_Lucene_Exception
  518. */
  519. public function termDocsFilter(Zend_Search_Lucene_Index_Term $term, $docsFilter = null)
  520. {
  521. require_once 'Zend/Search/Lucene/Exception.php';
  522. throw new Zend_Search_Lucene_Exception('Document filters could not used with multi-searcher');
  523. }
  524. /**
  525. * Returns an array of all term freqs.
  526. * Return array structure: array( docId => freq, ...)
  527. *
  528. * @param Zend_Search_Lucene_Index_Term $term
  529. * @param Zend_Search_Lucene_Index_DocsFilter|null $docsFilter
  530. * @return integer
  531. * @throws Zend_Search_Lucene_Exception
  532. */
  533. public function termFreqs(Zend_Search_Lucene_Index_Term $term, $docsFilter = null)
  534. {
  535. if ($docsFilter != null) {
  536. require_once 'Zend/Search/Lucene/Exception.php';
  537. throw new Zend_Search_Lucene_Exception('Document filters could not used with multi-searcher');
  538. }
  539. $freqsList = array();
  540. $indexShift = 0;
  541. foreach ($this->_indices as $index) {
  542. $freqs = $index->termFreqs($term);
  543. if ($indexShift != 0) {
  544. $freqsShifted = array();
  545. foreach ($freqs as $docId => $freq) {
  546. $freqsShifted[$docId + $indexShift] = $freq;
  547. }
  548. $freqs = $freqsShifted;
  549. }
  550. $indexShift += $index->count();
  551. $freqsList[] = $freqs;
  552. }
  553. return call_user_func_array('array_merge', $freqsList);
  554. }
  555. /**
  556. * Returns an array of all term positions in the documents.
  557. * Return array structure: array( docId => array( pos1, pos2, ...), ...)
  558. *
  559. * @param Zend_Search_Lucene_Index_Term $term
  560. * @param Zend_Search_Lucene_Index_DocsFilter|null $docsFilter
  561. * @return array
  562. * @throws Zend_Search_Lucene_Exception
  563. */
  564. public function termPositions(Zend_Search_Lucene_Index_Term $term, $docsFilter = null)
  565. {
  566. if ($docsFilter != null) {
  567. require_once 'Zend/Search/Lucene/Exception.php';
  568. throw new Zend_Search_Lucene_Exception('Document filters could not used with multi-searcher');
  569. }
  570. $termPositionsList = array();
  571. $indexShift = 0;
  572. foreach ($this->_indices as $index) {
  573. $termPositions = $index->termPositions($term);
  574. if ($indexShift != 0) {
  575. $termPositionsShifted = array();
  576. foreach ($termPositions as $docId => $positions) {
  577. $termPositions[$docId + $indexShift] = $positions;
  578. }
  579. $termPositions = $termPositionsShifted;
  580. }
  581. $indexShift += $index->count();
  582. $termPositionsList[] = $termPositions;
  583. }
  584. return call_user_func_array('array_merge', $termPositions);
  585. }
  586. /**
  587. * Returns the number of documents in this index containing the $term.
  588. *
  589. * @param Zend_Search_Lucene_Index_Term $term
  590. * @return integer
  591. */
  592. public function docFreq(Zend_Search_Lucene_Index_Term $term)
  593. {
  594. $docFreq = 0;
  595. foreach ($this->_indices as $index) {
  596. $docFreq += $index->docFreq($term);
  597. }
  598. return $docFreq;
  599. }
  600. /**
  601. * Retrive similarity used by index reader
  602. *
  603. * @return Zend_Search_Lucene_Search_Similarity
  604. * @throws Zend_Search_Lucene_Exception
  605. */
  606. public function getSimilarity()
  607. {
  608. if (count($this->_indices) == 0) {
  609. require_once 'Zend/Search/Lucene/Exception.php';
  610. throw new Zend_Search_Lucene_Exception('Indices list is empty');
  611. }
  612. $similarity = reset($this->_indices)->getSimilarity();
  613. foreach ($this->_indices as $index) {
  614. if ($index->getSimilarity() !== $similarity) {
  615. require_once 'Zend/Search/Lucene/Exception.php';
  616. throw new Zend_Search_Lucene_Exception('Indices have different similarity.');
  617. }
  618. }
  619. return $similarity;
  620. }
  621. /**
  622. * Returns a normalization factor for "field, document" pair.
  623. *
  624. * @param integer $id
  625. * @param string $fieldName
  626. * @return float
  627. */
  628. public function norm($id, $fieldName)
  629. {
  630. foreach ($this->_indices as $index) {
  631. $indexCount = $index->count();
  632. if ($indexCount > $id) {
  633. return $index->norm($id, $fieldName);
  634. }
  635. $id -= $indexCount;
  636. }
  637. return null;
  638. }
  639. /**
  640. * Returns true if any documents have been deleted from this index.
  641. *
  642. * @return boolean
  643. */
  644. public function hasDeletions()
  645. {
  646. foreach ($this->_indices as $index) {
  647. if ($index->hasDeletions()) {
  648. return true;
  649. }
  650. }
  651. return false;
  652. }
  653. /**
  654. * Deletes a document from the index.
  655. * $id is an internal document id
  656. *
  657. * @param integer|Zend_Search_Lucene_Search_QueryHit $id
  658. * @throws Zend_Search_Lucene_Exception
  659. */
  660. public function delete($id)
  661. {
  662. foreach ($this->_indices as $index) {
  663. $indexCount = $index->count();
  664. if ($indexCount > $id) {
  665. $index->delete($id);
  666. return;
  667. }
  668. $id -= $indexCount;
  669. }
  670. require_once 'Zend/Search/Lucene/Exception.php';
  671. throw new Zend_Search_Lucene_Exception('Document id is out of the range.');
  672. }
  673. /**
  674. * Callback used to choose target index for new documents
  675. *
  676. * Function/method signature:
  677. * Zend_Search_Lucene_Interface callbackFunction(Zend_Search_Lucene_Document $document, array $indices);
  678. *
  679. * null means "default documents distributing algorithm"
  680. *
  681. * @var callback
  682. */
  683. protected $_documentDistributorCallBack = null;
  684. /**
  685. * Set callback for choosing target index.
  686. *
  687. * @param callback $callback
  688. */
  689. public function setDocumentDistributorCallback($callback)
  690. {
  691. if ($callback !== null && !is_callable($callback))
  692. $this->_documentDistributorCallBack = $callback;
  693. }
  694. /**
  695. * Get callback for choosing target index.
  696. *
  697. * @return callback
  698. */
  699. public function getDocumentDistributorCallback()
  700. {
  701. return $this->_documentDistributorCallBack;
  702. }
  703. /**
  704. * Adds a document to this index.
  705. *
  706. * @param Zend_Search_Lucene_Document $document
  707. * @throws Zend_Search_Lucene_Exception
  708. */
  709. public function addDocument(Zend_Search_Lucene_Document $document)
  710. {
  711. if ($this->_documentDistributorCallBack !== null) {
  712. $index = call_user_func($this->_documentDistributorCallBack, $document, $this->_indices);
  713. } else {
  714. $index = $this->_indices[ array_rand($this->_indices) ];
  715. }
  716. $index->addDocument($document);
  717. }
  718. /**
  719. * Commit changes resulting from delete() or undeleteAll() operations.
  720. */
  721. public function commit()
  722. {
  723. foreach ($this->_indices as $index) {
  724. $index->commit();
  725. }
  726. }
  727. /**
  728. * Optimize index.
  729. *
  730. * Merges all segments into one
  731. */
  732. public function optimize()
  733. {
  734. foreach ($this->_indices as $index) {
  735. $index->_optimise();
  736. }
  737. }
  738. /**
  739. * Returns an array of all terms in this index.
  740. *
  741. * @return array
  742. */
  743. public function terms()
  744. {
  745. $termsList = array();
  746. foreach ($this->_indices as $index) {
  747. $termsList[] = $index->terms();
  748. }
  749. return array_unique(call_user_func_array('array_merge', $termsList));
  750. }
  751. /**
  752. * Terms stream priority queue object
  753. *
  754. * @var Zend_Search_Lucene_TermStreamsPriorityQueue
  755. */
  756. private $_termsStream = null;
  757. /**
  758. * Reset terms stream.
  759. */
  760. public function resetTermsStream()
  761. {
  762. if ($this->_termsStream === null) {
  763. $this->_termsStream = new Zend_Search_Lucene_TermStreamsPriorityQueue($this->_indices);
  764. } else {
  765. $this->_termsStream->resetTermsStream();
  766. }
  767. }
  768. /**
  769. * Skip terms stream up to specified term preffix.
  770. *
  771. * Prefix contains fully specified field info and portion of searched term
  772. *
  773. * @param Zend_Search_Lucene_Index_Term $prefix
  774. */
  775. public function skipTo(Zend_Search_Lucene_Index_Term $prefix)
  776. {
  777. $this->_termsStream->skipTo($prefix);
  778. }
  779. /**
  780. * Scans terms dictionary and returns next term
  781. *
  782. * @return Zend_Search_Lucene_Index_Term|null
  783. */
  784. public function nextTerm()
  785. {
  786. return $this->_termsStream->nextTerm();
  787. }
  788. /**
  789. * Returns term in current position
  790. *
  791. * @return Zend_Search_Lucene_Index_Term|null
  792. */
  793. public function currentTerm()
  794. {
  795. return $this->_termsStream->currentTerm();
  796. }
  797. /**
  798. * Close terms stream
  799. *
  800. * Should be used for resources clean up if stream is not read up to the end
  801. */
  802. public function closeTermsStream()
  803. {
  804. $this->_termsStream->closeTermsStream();
  805. $this->_termsStream = null;
  806. }
  807. /**
  808. * Undeletes all documents currently marked as deleted in this index.
  809. */
  810. public function undeleteAll()
  811. {
  812. foreach ($this->_indices as $index) {
  813. $index->undeleteAll();
  814. }
  815. }
  816. /**
  817. * Add reference to the index object
  818. *
  819. * @internal
  820. */
  821. public function addReference()
  822. {
  823. // Do nothing, since it's never referenced by indices
  824. }
  825. /**
  826. * Remove reference from the index object
  827. *
  828. * When reference count becomes zero, index is closed and resources are cleaned up
  829. *
  830. * @internal
  831. */
  832. public function removeReference()
  833. {
  834. // Do nothing, since it's never referenced by indices
  835. }
  836. }