File indexing completed on 2025-01-19 05:21:27
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Search_Lucene 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 0023 /** User land classes and interfaces turned on by Zend/Search/Lucene.php file inclusion. */ 0024 /** @todo Section should be removed with ZF 2.0 release as obsolete */ 0025 0026 /** Zend_Search_Lucene_Document_Html */ 0027 // require_once 'Zend/Search/Lucene/Document/Html.php'; 0028 0029 /** Zend_Search_Lucene_Document_Docx */ 0030 // require_once 'Zend/Search/Lucene/Document/Docx.php'; 0031 0032 /** Zend_Search_Lucene_Document_Pptx */ 0033 // require_once 'Zend/Search/Lucene/Document/Pptx.php'; 0034 0035 /** Zend_Search_Lucene_Document_Xlsx */ 0036 // require_once 'Zend/Search/Lucene/Document/Xlsx.php'; 0037 0038 /** Zend_Search_Lucene_Search_QueryParser */ 0039 // require_once 'Zend/Search/Lucene/Search/QueryParser.php'; 0040 0041 /** Zend_Search_Lucene_Search_QueryHit */ 0042 // require_once 'Zend/Search/Lucene/Search/QueryHit.php'; 0043 0044 /** Zend_Search_Lucene_Analysis_Analyzer */ 0045 // require_once 'Zend/Search/Lucene/Analysis/Analyzer.php'; 0046 0047 /** Zend_Search_Lucene_Search_Query_Term */ 0048 // require_once 'Zend/Search/Lucene/Search/Query/Term.php'; 0049 0050 /** Zend_Search_Lucene_Search_Query_Phrase */ 0051 // require_once 'Zend/Search/Lucene/Search/Query/Phrase.php'; 0052 0053 /** Zend_Search_Lucene_Search_Query_MultiTerm */ 0054 // require_once 'Zend/Search/Lucene/Search/Query/MultiTerm.php'; 0055 0056 /** Zend_Search_Lucene_Search_Query_Wildcard */ 0057 // require_once 'Zend/Search/Lucene/Search/Query/Wildcard.php'; 0058 0059 /** Zend_Search_Lucene_Search_Query_Range */ 0060 // require_once 'Zend/Search/Lucene/Search/Query/Range.php'; 0061 0062 /** Zend_Search_Lucene_Search_Query_Fuzzy */ 0063 // require_once 'Zend/Search/Lucene/Search/Query/Fuzzy.php'; 0064 0065 /** Zend_Search_Lucene_Search_Query_Boolean */ 0066 // require_once 'Zend/Search/Lucene/Search/Query/Boolean.php'; 0067 0068 /** Zend_Search_Lucene_Search_Query_Empty */ 0069 // require_once 'Zend/Search/Lucene/Search/Query/Empty.php'; 0070 0071 /** Zend_Search_Lucene_Search_Query_Insignificant */ 0072 // require_once 'Zend/Search/Lucene/Search/Query/Insignificant.php'; 0073 0074 0075 0076 0077 /** Internally used classes */ 0078 0079 /** Zend_Search_Lucene_Interface */ 0080 // require_once 'Zend/Search/Lucene/Interface.php'; 0081 0082 /** Zend_Search_Lucene_Index_SegmentInfo */ 0083 // require_once 'Zend/Search/Lucene/Index/SegmentInfo.php'; 0084 0085 /** Zend_Search_Lucene_LockManager */ 0086 // require_once 'Zend/Search/Lucene/LockManager.php'; 0087 0088 0089 /** 0090 * @category Zend 0091 * @package Zend_Search_Lucene 0092 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0093 * @license http://framework.zend.com/license/new-bsd New BSD License 0094 */ 0095 class Zend_Search_Lucene implements Zend_Search_Lucene_Interface 0096 { 0097 /** 0098 * Default field name for search 0099 * 0100 * Null means search through all fields 0101 * 0102 * @var string 0103 */ 0104 private static $_defaultSearchField = null; 0105 0106 /** 0107 * Result set limit 0108 * 0109 * 0 means no limit 0110 * 0111 * @var integer 0112 */ 0113 private static $_resultSetLimit = 0; 0114 0115 /** 0116 * Terms per query limit 0117 * 0118 * 0 means no limit 0119 * 0120 * @var integer 0121 */ 0122 private static $_termsPerQueryLimit = 1024; 0123 0124 /** 0125 * File system adapter. 0126 * 0127 * @var Zend_Search_Lucene_Storage_Directory 0128 */ 0129 private $_directory = null; 0130 0131 /** 0132 * File system adapter closing option 0133 * 0134 * @var boolean 0135 */ 0136 private $_closeDirOnExit = true; 0137 0138 /** 0139 * Writer for this index, not instantiated unless required. 0140 * 0141 * @var Zend_Search_Lucene_Index_Writer 0142 */ 0143 private $_writer = null; 0144 0145 /** 0146 * Array of Zend_Search_Lucene_Index_SegmentInfo objects for current version of index. 0147 * 0148 * @var array Zend_Search_Lucene_Index_SegmentInfo 0149 */ 0150 private $_segmentInfos = array(); 0151 0152 /** 0153 * Number of documents in this index. 0154 * 0155 * @var integer 0156 */ 0157 private $_docCount = 0; 0158 0159 /** 0160 * Flag for index changes 0161 * 0162 * @var boolean 0163 */ 0164 private $_hasChanges = false; 0165 0166 0167 /** 0168 * Signal, that index is already closed, changes are fixed and resources are cleaned up 0169 * 0170 * @var boolean 0171 */ 0172 private $_closed = false; 0173 0174 /** 0175 * Number of references to the index object 0176 * 0177 * @var integer 0178 */ 0179 private $_refCount = 0; 0180 0181 /** 0182 * Current segment generation 0183 * 0184 * @var integer 0185 */ 0186 private $_generation; 0187 0188 const FORMAT_PRE_2_1 = 0; 0189 const FORMAT_2_1 = 1; 0190 const FORMAT_2_3 = 2; 0191 0192 0193 /** 0194 * Index format version 0195 * 0196 * @var integer 0197 */ 0198 private $_formatVersion; 0199 0200 /** 0201 * Create index 0202 * 0203 * @param mixed $directory 0204 * @return Zend_Search_Lucene_Interface 0205 */ 0206 public static function create($directory) 0207 { 0208 /** Zend_Search_Lucene_Proxy */ 0209 // require_once 'Zend/Search/Lucene/Proxy.php'; 0210 0211 return new Zend_Search_Lucene_Proxy(new Zend_Search_Lucene($directory, true)); 0212 } 0213 0214 /** 0215 * Open index 0216 * 0217 * @param mixed $directory 0218 * @return Zend_Search_Lucene_Interface 0219 */ 0220 public static function open($directory) 0221 { 0222 /** Zend_Search_Lucene_Proxy */ 0223 // require_once 'Zend/Search/Lucene/Proxy.php'; 0224 0225 return new Zend_Search_Lucene_Proxy(new Zend_Search_Lucene($directory, false)); 0226 } 0227 0228 /** Generation retrieving counter */ 0229 const GENERATION_RETRIEVE_COUNT = 10; 0230 0231 /** Pause between generation retrieving attempts in milliseconds */ 0232 const GENERATION_RETRIEVE_PAUSE = 50; 0233 0234 /** 0235 * Get current generation number 0236 * 0237 * Returns generation number 0238 * 0 means pre-2.1 index format 0239 * -1 means there are no segments files. 0240 * 0241 * @param Zend_Search_Lucene_Storage_Directory $directory 0242 * @return integer 0243 * @throws Zend_Search_Lucene_Exception 0244 */ 0245 public static function getActualGeneration(Zend_Search_Lucene_Storage_Directory $directory) 0246 { 0247 /** 0248 * Zend_Search_Lucene uses segments.gen file to retrieve current generation number 0249 * 0250 * Apache Lucene index format documentation mentions this method only as a fallback method 0251 * 0252 * Nevertheless we use it according to the performance considerations 0253 * 0254 * @todo check if we can use some modification of Apache Lucene generation determination algorithm 0255 * without performance problems 0256 */ 0257 0258 // require_once 'Zend/Search/Lucene/Exception.php'; 0259 try { 0260 for ($count = 0; $count < self::GENERATION_RETRIEVE_COUNT; $count++) { 0261 // Try to get generation file 0262 $genFile = $directory->getFileObject('segments.gen', false); 0263 0264 $format = $genFile->readInt(); 0265 if ($format != (int)0xFFFFFFFE) { 0266 throw new Zend_Search_Lucene_Exception('Wrong segments.gen file format'); 0267 } 0268 0269 $gen1 = $genFile->readLong(); 0270 $gen2 = $genFile->readLong(); 0271 0272 if ($gen1 == $gen2) { 0273 return $gen1; 0274 } 0275 0276 usleep(self::GENERATION_RETRIEVE_PAUSE * 1000); 0277 } 0278 0279 // All passes are failed 0280 throw new Zend_Search_Lucene_Exception('Index is under processing now'); 0281 } catch (Zend_Search_Lucene_Exception $e) { 0282 if (strpos($e->getMessage(), 'is not readable') !== false) { 0283 try { 0284 // Try to open old style segments file 0285 $segmentsFile = $directory->getFileObject('segments', false); 0286 0287 // It's pre-2.1 index 0288 return 0; 0289 } catch (Zend_Search_Lucene_Exception $e) { 0290 if (strpos($e->getMessage(), 'is not readable') !== false) { 0291 return -1; 0292 } else { 0293 throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); 0294 } 0295 } 0296 } else { 0297 throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); 0298 } 0299 } 0300 0301 return -1; 0302 } 0303 0304 /** 0305 * Get generation number associated with this index instance 0306 * 0307 * The same generation number in pair with document number or query string 0308 * guarantees to give the same result while index retrieving. 0309 * So it may be used for search result caching. 0310 * 0311 * @return integer 0312 */ 0313 public function getGeneration() 0314 { 0315 return $this->_generation; 0316 } 0317 0318 0319 /** 0320 * Get segments file name 0321 * 0322 * @param integer $generation 0323 * @return string 0324 */ 0325 public static function getSegmentFileName($generation) 0326 { 0327 if ($generation == 0) { 0328 return 'segments'; 0329 } 0330 0331 return 'segments_' . base_convert($generation, 10, 36); 0332 } 0333 0334 /** 0335 * Get index format version 0336 * 0337 * @return integer 0338 */ 0339 public function getFormatVersion() 0340 { 0341 return $this->_formatVersion; 0342 } 0343 0344 /** 0345 * Set index format version. 0346 * Index is converted to this format at the nearest upfdate time 0347 * 0348 * @param int $formatVersion 0349 * @throws Zend_Search_Lucene_Exception 0350 */ 0351 public function setFormatVersion($formatVersion) 0352 { 0353 if ($formatVersion != self::FORMAT_PRE_2_1 && 0354 $formatVersion != self::FORMAT_2_1 && 0355 $formatVersion != self::FORMAT_2_3) { 0356 // require_once 'Zend/Search/Lucene/Exception.php'; 0357 throw new Zend_Search_Lucene_Exception('Unsupported index format'); 0358 } 0359 0360 $this->_formatVersion = $formatVersion; 0361 } 0362 0363 /** 0364 * Read segments file for pre-2.1 Lucene index format 0365 * 0366 * @throws Zend_Search_Lucene_Exception 0367 */ 0368 private function _readPre21SegmentsFile() 0369 { 0370 $segmentsFile = $this->_directory->getFileObject('segments'); 0371 0372 $format = $segmentsFile->readInt(); 0373 0374 if ($format != (int)0xFFFFFFFF) { 0375 // require_once 'Zend/Search/Lucene/Exception.php'; 0376 throw new Zend_Search_Lucene_Exception('Wrong segments file format'); 0377 } 0378 0379 // read version 0380 $segmentsFile->readLong(); 0381 0382 // read segment name counter 0383 $segmentsFile->readInt(); 0384 0385 $segments = $segmentsFile->readInt(); 0386 0387 $this->_docCount = 0; 0388 0389 // read segmentInfos 0390 for ($count = 0; $count < $segments; $count++) { 0391 $segName = $segmentsFile->readString(); 0392 $segSize = $segmentsFile->readInt(); 0393 $this->_docCount += $segSize; 0394 0395 $this->_segmentInfos[$segName] = 0396 new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, 0397 $segName, 0398 $segSize); 0399 } 0400 0401 // Use 2.1 as a target version. Index will be reorganized at update time. 0402 $this->_formatVersion = self::FORMAT_2_1; 0403 } 0404 0405 /** 0406 * Read segments file 0407 * 0408 * @throws Zend_Search_Lucene_Exception 0409 */ 0410 private function _readSegmentsFile() 0411 { 0412 $segmentsFile = $this->_directory->getFileObject(self::getSegmentFileName($this->_generation)); 0413 0414 $format = $segmentsFile->readInt(); 0415 0416 if ($format == (int)0xFFFFFFFC) { 0417 $this->_formatVersion = self::FORMAT_2_3; 0418 } else if ($format == (int)0xFFFFFFFD) { 0419 $this->_formatVersion = self::FORMAT_2_1; 0420 } else { 0421 // require_once 'Zend/Search/Lucene/Exception.php'; 0422 throw new Zend_Search_Lucene_Exception('Unsupported segments file format'); 0423 } 0424 0425 // read version 0426 $segmentsFile->readLong(); 0427 0428 // read segment name counter 0429 $segmentsFile->readInt(); 0430 0431 $segments = $segmentsFile->readInt(); 0432 0433 $this->_docCount = 0; 0434 0435 // read segmentInfos 0436 for ($count = 0; $count < $segments; $count++) { 0437 $segName = $segmentsFile->readString(); 0438 $segSize = $segmentsFile->readInt(); 0439 0440 // 2.1+ specific properties 0441 $delGen = $segmentsFile->readLong(); 0442 0443 if ($this->_formatVersion == self::FORMAT_2_3) { 0444 $docStoreOffset = $segmentsFile->readInt(); 0445 0446 if ($docStoreOffset != (int)0xFFFFFFFF) { 0447 $docStoreSegment = $segmentsFile->readString(); 0448 $docStoreIsCompoundFile = $segmentsFile->readByte(); 0449 0450 $docStoreOptions = array('offset' => $docStoreOffset, 0451 'segment' => $docStoreSegment, 0452 'isCompound' => ($docStoreIsCompoundFile == 1)); 0453 } else { 0454 $docStoreOptions = null; 0455 } 0456 } else { 0457 $docStoreOptions = null; 0458 } 0459 0460 $hasSingleNormFile = $segmentsFile->readByte(); 0461 $numField = $segmentsFile->readInt(); 0462 0463 $normGens = array(); 0464 if ($numField != (int)0xFFFFFFFF) { 0465 for ($count1 = 0; $count1 < $numField; $count1++) { 0466 $normGens[] = $segmentsFile->readLong(); 0467 } 0468 0469 // require_once 'Zend/Search/Lucene/Exception.php'; 0470 throw new Zend_Search_Lucene_Exception('Separate norm files are not supported. Optimize index to use it with Zend_Search_Lucene.'); 0471 } 0472 0473 $isCompoundByte = $segmentsFile->readByte(); 0474 0475 if ($isCompoundByte == 0xFF) { 0476 // The segment is not a compound file 0477 $isCompound = false; 0478 } else if ($isCompoundByte == 0x00) { 0479 // The status is unknown 0480 $isCompound = null; 0481 } else if ($isCompoundByte == 0x01) { 0482 // The segment is a compound file 0483 $isCompound = true; 0484 } 0485 0486 $this->_docCount += $segSize; 0487 0488 $this->_segmentInfos[$segName] = 0489 new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, 0490 $segName, 0491 $segSize, 0492 $delGen, 0493 $docStoreOptions, 0494 $hasSingleNormFile, 0495 $isCompound); 0496 } 0497 } 0498 0499 /** 0500 * Opens the index. 0501 * 0502 * IndexReader constructor needs Directory as a parameter. It should be 0503 * a string with a path to the index folder or a Directory object. 0504 * 0505 * @param Zend_Search_Lucene_Storage_Directory_Filesystem|string $directory 0506 * @throws Zend_Search_Lucene_Exception 0507 */ 0508 public function __construct($directory = null, $create = false) 0509 { 0510 if ($directory === null) { 0511 // require_once 'Zend/Search/Lucene/Exception.php'; 0512 throw new Zend_Search_Exception('No index directory specified'); 0513 } 0514 0515 if (is_string($directory)) { 0516 // require_once 'Zend/Search/Lucene/Storage/Directory/Filesystem.php'; 0517 $this->_directory = new Zend_Search_Lucene_Storage_Directory_Filesystem($directory); 0518 $this->_closeDirOnExit = true; 0519 } else { 0520 $this->_directory = $directory; 0521 $this->_closeDirOnExit = false; 0522 } 0523 0524 $this->_segmentInfos = array(); 0525 0526 // Mark index as "under processing" to prevent other processes from premature index cleaning 0527 Zend_Search_Lucene_LockManager::obtainReadLock($this->_directory); 0528 0529 $this->_generation = self::getActualGeneration($this->_directory); 0530 0531 if ($create) { 0532 // require_once 'Zend/Search/Lucene/Exception.php'; 0533 try { 0534 Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory); 0535 } catch (Zend_Search_Lucene_Exception $e) { 0536 Zend_Search_Lucene_LockManager::releaseReadLock($this->_directory); 0537 0538 if (strpos($e->getMessage(), 'Can\'t obtain exclusive index lock') === false) { 0539 throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); 0540 } else { 0541 throw new Zend_Search_Lucene_Exception('Can\'t create index. It\'s under processing now', 0, $e); 0542 } 0543 } 0544 0545 if ($this->_generation == -1) { 0546 // Directory doesn't contain existing index, start from 1 0547 $this->_generation = 1; 0548 $nameCounter = 0; 0549 } else { 0550 // Directory contains existing index 0551 $segmentsFile = $this->_directory->getFileObject(self::getSegmentFileName($this->_generation)); 0552 $segmentsFile->seek(12); // 12 = 4 (int, file format marker) + 8 (long, index version) 0553 0554 $nameCounter = $segmentsFile->readInt(); 0555 $this->_generation++; 0556 } 0557 0558 // require_once 'Zend/Search/Lucene/Index/Writer.php'; 0559 Zend_Search_Lucene_Index_Writer::createIndex($this->_directory, $this->_generation, $nameCounter); 0560 0561 Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); 0562 } 0563 0564 if ($this->_generation == -1) { 0565 // require_once 'Zend/Search/Lucene/Exception.php'; 0566 throw new Zend_Search_Lucene_Exception('Index doesn\'t exists in the specified directory.'); 0567 } else if ($this->_generation == 0) { 0568 $this->_readPre21SegmentsFile(); 0569 } else { 0570 $this->_readSegmentsFile(); 0571 } 0572 } 0573 0574 /** 0575 * Close current index and free resources 0576 */ 0577 private function _close() 0578 { 0579 if ($this->_closed) { 0580 // index is already closed and resources are cleaned up 0581 return; 0582 } 0583 0584 $this->commit(); 0585 0586 // Release "under processing" flag 0587 Zend_Search_Lucene_LockManager::releaseReadLock($this->_directory); 0588 0589 if ($this->_closeDirOnExit) { 0590 $this->_directory->close(); 0591 } 0592 0593 $this->_directory = null; 0594 $this->_writer = null; 0595 $this->_segmentInfos = null; 0596 0597 $this->_closed = true; 0598 } 0599 0600 /** 0601 * Add reference to the index object 0602 * 0603 * @internal 0604 */ 0605 public function addReference() 0606 { 0607 $this->_refCount++; 0608 } 0609 0610 /** 0611 * Remove reference from the index object 0612 * 0613 * When reference count becomes zero, index is closed and resources are cleaned up 0614 * 0615 * @internal 0616 */ 0617 public function removeReference() 0618 { 0619 $this->_refCount--; 0620 0621 if ($this->_refCount == 0) { 0622 $this->_close(); 0623 } 0624 } 0625 0626 /** 0627 * Object destructor 0628 */ 0629 public function __destruct() 0630 { 0631 $this->_close(); 0632 } 0633 0634 /** 0635 * Returns an instance of Zend_Search_Lucene_Index_Writer for the index 0636 * 0637 * @return Zend_Search_Lucene_Index_Writer 0638 */ 0639 private function _getIndexWriter() 0640 { 0641 if ($this->_writer === null) { 0642 // require_once 'Zend/Search/Lucene/Index/Writer.php'; 0643 $this->_writer = new Zend_Search_Lucene_Index_Writer($this->_directory, 0644 $this->_segmentInfos, 0645 $this->_formatVersion); 0646 } 0647 0648 return $this->_writer; 0649 } 0650 0651 0652 /** 0653 * Returns the Zend_Search_Lucene_Storage_Directory instance for this index. 0654 * 0655 * @return Zend_Search_Lucene_Storage_Directory 0656 */ 0657 public function getDirectory() 0658 { 0659 return $this->_directory; 0660 } 0661 0662 0663 /** 0664 * Returns the total number of documents in this index (including deleted documents). 0665 * 0666 * @return integer 0667 */ 0668 public function count() 0669 { 0670 return $this->_docCount; 0671 } 0672 0673 /** 0674 * Returns one greater than the largest possible document number. 0675 * This may be used to, e.g., determine how big to allocate a structure which will have 0676 * an element for every document number in an index. 0677 * 0678 * @return integer 0679 */ 0680 public function maxDoc() 0681 { 0682 return $this->count(); 0683 } 0684 0685 /** 0686 * Returns the total number of non-deleted documents in this index. 0687 * 0688 * @return integer 0689 */ 0690 public function numDocs() 0691 { 0692 $numDocs = 0; 0693 0694 foreach ($this->_segmentInfos as $segmentInfo) { 0695 $numDocs += $segmentInfo->numDocs(); 0696 } 0697 0698 return $numDocs; 0699 } 0700 0701 /** 0702 * Checks, that document is deleted 0703 * 0704 * @param integer $id 0705 * @return boolean 0706 * @throws Zend_Search_Lucene_Exception Exception is thrown if $id is out of the range 0707 */ 0708 public function isDeleted($id) 0709 { 0710 $this->commit(); 0711 0712 if ($id >= $this->_docCount) { 0713 // require_once 'Zend/Search/Lucene/Exception.php'; 0714 throw new Zend_Search_Lucene_Exception('Document id is out of the range.'); 0715 } 0716 0717 $segmentStartId = 0; 0718 foreach ($this->_segmentInfos as $segmentInfo) { 0719 if ($segmentStartId + $segmentInfo->count() > $id) { 0720 break; 0721 } 0722 0723 $segmentStartId += $segmentInfo->count(); 0724 } 0725 0726 return $segmentInfo->isDeleted($id - $segmentStartId); 0727 } 0728 0729 /** 0730 * Set default search field. 0731 * 0732 * Null means, that search is performed through all fields by default 0733 * 0734 * Default value is null 0735 * 0736 * @param string $fieldName 0737 */ 0738 public static function setDefaultSearchField($fieldName) 0739 { 0740 self::$_defaultSearchField = $fieldName; 0741 } 0742 0743 /** 0744 * Get default search field. 0745 * 0746 * Null means, that search is performed through all fields by default 0747 * 0748 * @return string 0749 */ 0750 public static function getDefaultSearchField() 0751 { 0752 return self::$_defaultSearchField; 0753 } 0754 0755 /** 0756 * Set result set limit. 0757 * 0758 * 0 (default) means no limit 0759 * 0760 * @param integer $limit 0761 */ 0762 public static function setResultSetLimit($limit) 0763 { 0764 self::$_resultSetLimit = $limit; 0765 } 0766 0767 /** 0768 * Get result set limit. 0769 * 0770 * 0 means no limit 0771 * 0772 * @return integer 0773 */ 0774 public static function getResultSetLimit() 0775 { 0776 return self::$_resultSetLimit; 0777 } 0778 0779 /** 0780 * Set terms per query limit. 0781 * 0782 * 0 means no limit 0783 * 0784 * @param integer $limit 0785 */ 0786 public static function setTermsPerQueryLimit($limit) 0787 { 0788 self::$_termsPerQueryLimit = $limit; 0789 } 0790 0791 /** 0792 * Get result set limit. 0793 * 0794 * 0 (default) means no limit 0795 * 0796 * @return integer 0797 */ 0798 public static function getTermsPerQueryLimit() 0799 { 0800 return self::$_termsPerQueryLimit; 0801 } 0802 0803 /** 0804 * Retrieve index maxBufferedDocs option 0805 * 0806 * maxBufferedDocs is a minimal number of documents required before 0807 * the buffered in-memory documents are written into a new Segment 0808 * 0809 * Default value is 10 0810 * 0811 * @return integer 0812 */ 0813 public function getMaxBufferedDocs() 0814 { 0815 return $this->_getIndexWriter()->maxBufferedDocs; 0816 } 0817 0818 /** 0819 * Set index maxBufferedDocs option 0820 * 0821 * maxBufferedDocs is a minimal number of documents required before 0822 * the buffered in-memory documents are written into a new Segment 0823 * 0824 * Default value is 10 0825 * 0826 * @param integer $maxBufferedDocs 0827 */ 0828 public function setMaxBufferedDocs($maxBufferedDocs) 0829 { 0830 $this->_getIndexWriter()->maxBufferedDocs = $maxBufferedDocs; 0831 } 0832 0833 /** 0834 * Retrieve index maxMergeDocs option 0835 * 0836 * maxMergeDocs is a largest number of documents ever merged by addDocument(). 0837 * Small values (e.g., less than 10,000) are best for interactive indexing, 0838 * as this limits the length of pauses while indexing to a few seconds. 0839 * Larger values are best for batched indexing and speedier searches. 0840 * 0841 * Default value is PHP_INT_MAX 0842 * 0843 * @return integer 0844 */ 0845 public function getMaxMergeDocs() 0846 { 0847 return $this->_getIndexWriter()->maxMergeDocs; 0848 } 0849 0850 /** 0851 * Set index maxMergeDocs option 0852 * 0853 * maxMergeDocs is a largest number of documents ever merged by addDocument(). 0854 * Small values (e.g., less than 10,000) are best for interactive indexing, 0855 * as this limits the length of pauses while indexing to a few seconds. 0856 * Larger values are best for batched indexing and speedier searches. 0857 * 0858 * Default value is PHP_INT_MAX 0859 * 0860 * @param integer $maxMergeDocs 0861 */ 0862 public function setMaxMergeDocs($maxMergeDocs) 0863 { 0864 $this->_getIndexWriter()->maxMergeDocs = $maxMergeDocs; 0865 } 0866 0867 /** 0868 * Retrieve index mergeFactor option 0869 * 0870 * mergeFactor determines how often segment indices are merged by addDocument(). 0871 * With smaller values, less RAM is used while indexing, 0872 * and searches on unoptimized indices are faster, 0873 * but indexing speed is slower. 0874 * With larger values, more RAM is used during indexing, 0875 * and while searches on unoptimized indices are slower, 0876 * indexing is faster. 0877 * Thus larger values (> 10) are best for batch index creation, 0878 * and smaller values (< 10) for indices that are interactively maintained. 0879 * 0880 * Default value is 10 0881 * 0882 * @return integer 0883 */ 0884 public function getMergeFactor() 0885 { 0886 return $this->_getIndexWriter()->mergeFactor; 0887 } 0888 0889 /** 0890 * Set index mergeFactor option 0891 * 0892 * mergeFactor determines how often segment indices are merged by addDocument(). 0893 * With smaller values, less RAM is used while indexing, 0894 * and searches on unoptimized indices are faster, 0895 * but indexing speed is slower. 0896 * With larger values, more RAM is used during indexing, 0897 * and while searches on unoptimized indices are slower, 0898 * indexing is faster. 0899 * Thus larger values (> 10) are best for batch index creation, 0900 * and smaller values (< 10) for indices that are interactively maintained. 0901 * 0902 * Default value is 10 0903 * 0904 * @param integer $maxMergeDocs 0905 */ 0906 public function setMergeFactor($mergeFactor) 0907 { 0908 $this->_getIndexWriter()->mergeFactor = $mergeFactor; 0909 } 0910 0911 /** 0912 * Performs a query against the index and returns an array 0913 * of Zend_Search_Lucene_Search_QueryHit objects. 0914 * Input is a string or Zend_Search_Lucene_Search_Query. 0915 * 0916 * @param Zend_Search_Lucene_Search_QueryParser|string $query 0917 * @return array Zend_Search_Lucene_Search_QueryHit 0918 * @throws Zend_Search_Lucene_Exception 0919 */ 0920 public function find($query) 0921 { 0922 if (is_string($query)) { 0923 // require_once 'Zend/Search/Lucene/Search/QueryParser.php'; 0924 0925 $query = Zend_Search_Lucene_Search_QueryParser::parse($query); 0926 } 0927 0928 if (!$query instanceof Zend_Search_Lucene_Search_Query) { 0929 // require_once 'Zend/Search/Lucene/Exception.php'; 0930 throw new Zend_Search_Lucene_Exception('Query must be a string or Zend_Search_Lucene_Search_Query object'); 0931 } 0932 0933 $this->commit(); 0934 0935 $hits = array(); 0936 $scores = array(); 0937 $ids = array(); 0938 0939 $query = $query->rewrite($this)->optimize($this); 0940 0941 $query->execute($this); 0942 0943 $topScore = 0; 0944 0945 /** Zend_Search_Lucene_Search_QueryHit */ 0946 // require_once 'Zend/Search/Lucene/Search/QueryHit.php'; 0947 0948 foreach ($query->matchedDocs() as $id => $num) { 0949 $docScore = $query->score($id, $this); 0950 if( $docScore != 0 ) { 0951 $hit = new Zend_Search_Lucene_Search_QueryHit($this); 0952 $hit->id = $id; 0953 $hit->score = $docScore; 0954 0955 $hits[] = $hit; 0956 $ids[] = $id; 0957 $scores[] = $docScore; 0958 0959 if ($docScore > $topScore) { 0960 $topScore = $docScore; 0961 } 0962 } 0963 0964 if (self::$_resultSetLimit != 0 && count($hits) >= self::$_resultSetLimit) { 0965 break; 0966 } 0967 } 0968 0969 if (count($hits) == 0) { 0970 // skip sorting, which may cause a error on empty index 0971 return array(); 0972 } 0973 0974 if ($topScore > 1) { 0975 foreach ($hits as $hit) { 0976 $hit->score /= $topScore; 0977 } 0978 } 0979 0980 if (func_num_args() == 1) { 0981 // sort by scores 0982 array_multisort($scores, SORT_DESC, SORT_NUMERIC, 0983 $ids, SORT_ASC, SORT_NUMERIC, 0984 $hits); 0985 } else { 0986 // sort by given field names 0987 0988 $argList = func_get_args(); 0989 $fieldNames = $this->getFieldNames(); 0990 $sortArgs = array(); 0991 0992 // PHP 5.3 now expects all arguments to array_multisort be passed by 0993 // reference (if it's invoked through call_user_func_array()); 0994 // since constants can't be passed by reference, create some placeholder variables. 0995 $sortReg = SORT_REGULAR; 0996 $sortAsc = SORT_ASC; 0997 $sortNum = SORT_NUMERIC; 0998 0999 $sortFieldValues = array(); 1000 1001 // require_once 'Zend/Search/Lucene/Exception.php'; 1002 for ($count = 1; $count < count($argList); $count++) { 1003 $fieldName = $argList[$count]; 1004 1005 if (!is_string($fieldName)) { 1006 throw new Zend_Search_Lucene_Exception('Field name must be a string.'); 1007 } 1008 1009 if (strtolower($fieldName) == 'score') { 1010 $sortArgs[] = &$scores; 1011 } else { 1012 if (!in_array($fieldName, $fieldNames)) { 1013 throw new Zend_Search_Lucene_Exception('Wrong field name.'); 1014 } 1015 1016 if (!isset($sortFieldValues[$fieldName])) { 1017 $valuesArray = array(); 1018 foreach ($hits as $hit) { 1019 try { 1020 $value = $hit->getDocument()->getFieldValue($fieldName); 1021 } catch (Zend_Search_Lucene_Exception $e) { 1022 if (strpos($e->getMessage(), 'not found') === false) { 1023 throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); 1024 } else { 1025 $value = null; 1026 } 1027 } 1028 1029 $valuesArray[] = $value; 1030 } 1031 1032 // Collect loaded values in $sortFieldValues 1033 // Required for PHP 5.3 which translates references into values when source 1034 // variable is destroyed 1035 $sortFieldValues[$fieldName] = $valuesArray; 1036 } 1037 1038 $sortArgs[] = &$sortFieldValues[$fieldName]; 1039 } 1040 1041 if ($count + 1 < count($argList) && is_integer($argList[$count+1])) { 1042 $count++; 1043 $sortArgs[] = &$argList[$count]; 1044 1045 if ($count + 1 < count($argList) && is_integer($argList[$count+1])) { 1046 $count++; 1047 $sortArgs[] = &$argList[$count]; 1048 } else { 1049 if ($argList[$count] == SORT_ASC || $argList[$count] == SORT_DESC) { 1050 $sortArgs[] = &$sortReg; 1051 } else { 1052 $sortArgs[] = &$sortAsc; 1053 } 1054 } 1055 } else { 1056 $sortArgs[] = &$sortAsc; 1057 $sortArgs[] = &$sortReg; 1058 } 1059 } 1060 1061 // Sort by id's if values are equal 1062 $sortArgs[] = &$ids; 1063 $sortArgs[] = &$sortAsc; 1064 $sortArgs[] = &$sortNum; 1065 1066 // Array to be sorted 1067 $sortArgs[] = &$hits; 1068 1069 // Do sort 1070 call_user_func_array('array_multisort', $sortArgs); 1071 } 1072 1073 return $hits; 1074 } 1075 1076 1077 /** 1078 * Returns a list of all unique field names that exist in this index. 1079 * 1080 * @param boolean $indexed 1081 * @return array 1082 */ 1083 public function getFieldNames($indexed = false) 1084 { 1085 $result = array(); 1086 foreach( $this->_segmentInfos as $segmentInfo ) { 1087 $result = array_merge($result, $segmentInfo->getFields($indexed)); 1088 } 1089 return $result; 1090 } 1091 1092 1093 /** 1094 * Returns a Zend_Search_Lucene_Document object for the document 1095 * number $id in this index. 1096 * 1097 * @param integer|Zend_Search_Lucene_Search_QueryHit $id 1098 * @return Zend_Search_Lucene_Document 1099 * @throws Zend_Search_Lucene_Exception Exception is thrown if $id is out of the range 1100 */ 1101 public function getDocument($id) 1102 { 1103 if ($id instanceof Zend_Search_Lucene_Search_QueryHit) { 1104 /* @var $id Zend_Search_Lucene_Search_QueryHit */ 1105 $id = $id->id; 1106 } 1107 1108 if ($id >= $this->_docCount) { 1109 // require_once 'Zend/Search/Lucene/Exception.php'; 1110 throw new Zend_Search_Lucene_Exception('Document id is out of the range.'); 1111 } 1112 1113 $segmentStartId = 0; 1114 foreach ($this->_segmentInfos as $segmentInfo) { 1115 if ($segmentStartId + $segmentInfo->count() > $id) { 1116 break; 1117 } 1118 1119 $segmentStartId += $segmentInfo->count(); 1120 } 1121 1122 $fdxFile = $segmentInfo->openCompoundFile('.fdx'); 1123 $fdxFile->seek(($id-$segmentStartId)*8, SEEK_CUR); 1124 $fieldValuesPosition = $fdxFile->readLong(); 1125 1126 $fdtFile = $segmentInfo->openCompoundFile('.fdt'); 1127 $fdtFile->seek($fieldValuesPosition, SEEK_CUR); 1128 $fieldCount = $fdtFile->readVInt(); 1129 1130 $doc = new Zend_Search_Lucene_Document(); 1131 for ($count = 0; $count < $fieldCount; $count++) { 1132 $fieldNum = $fdtFile->readVInt(); 1133 $bits = $fdtFile->readByte(); 1134 1135 $fieldInfo = $segmentInfo->getField($fieldNum); 1136 1137 if (!($bits & 2)) { // Text data 1138 $field = new Zend_Search_Lucene_Field($fieldInfo->name, 1139 $fdtFile->readString(), 1140 'UTF-8', 1141 true, 1142 $fieldInfo->isIndexed, 1143 $bits & 1 ); 1144 } else { // Binary data 1145 $field = new Zend_Search_Lucene_Field($fieldInfo->name, 1146 $fdtFile->readBinary(), 1147 '', 1148 true, 1149 $fieldInfo->isIndexed, 1150 $bits & 1, 1151 true ); 1152 } 1153 1154 $doc->addField($field); 1155 } 1156 1157 return $doc; 1158 } 1159 1160 1161 /** 1162 * Returns true if index contain documents with specified term. 1163 * 1164 * Is used for query optimization. 1165 * 1166 * @param Zend_Search_Lucene_Index_Term $term 1167 * @return boolean 1168 */ 1169 public function hasTerm(Zend_Search_Lucene_Index_Term $term) 1170 { 1171 foreach ($this->_segmentInfos as $segInfo) { 1172 if ($segInfo->getTermInfo($term) !== null) { 1173 return true; 1174 } 1175 } 1176 1177 return false; 1178 } 1179 1180 /** 1181 * Returns IDs of all documents containing term. 1182 * 1183 * @param Zend_Search_Lucene_Index_Term $term 1184 * @param Zend_Search_Lucene_Index_DocsFilter|null $docsFilter 1185 * @return array 1186 */ 1187 public function termDocs(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) 1188 { 1189 $subResults = array(); 1190 $segmentStartDocId = 0; 1191 1192 foreach ($this->_segmentInfos as $segmentInfo) { 1193 $subResults[] = $segmentInfo->termDocs($term, $segmentStartDocId, $docsFilter); 1194 1195 $segmentStartDocId += $segmentInfo->count(); 1196 } 1197 1198 if (count($subResults) == 0) { 1199 return array(); 1200 } else if (count($subResults) == 1) { 1201 // Index is optimized (only one segment) 1202 // Do not perform array reindexing 1203 return reset($subResults); 1204 } else { 1205 $result = call_user_func_array('array_merge', $subResults); 1206 } 1207 1208 return $result; 1209 } 1210 1211 /** 1212 * Returns documents filter for all documents containing term. 1213 * 1214 * It performs the same operation as termDocs, but return result as 1215 * Zend_Search_Lucene_Index_DocsFilter object 1216 * 1217 * @param Zend_Search_Lucene_Index_Term $term 1218 * @param Zend_Search_Lucene_Index_DocsFilter|null $docsFilter 1219 * @return Zend_Search_Lucene_Index_DocsFilter 1220 */ 1221 public function termDocsFilter(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) 1222 { 1223 $segmentStartDocId = 0; 1224 $result = new Zend_Search_Lucene_Index_DocsFilter(); 1225 1226 foreach ($this->_segmentInfos as $segmentInfo) { 1227 $subResults[] = $segmentInfo->termDocs($term, $segmentStartDocId, $docsFilter); 1228 1229 $segmentStartDocId += $segmentInfo->count(); 1230 } 1231 1232 if (count($subResults) == 0) { 1233 return array(); 1234 } else if (count($subResults) == 1) { 1235 // Index is optimized (only one segment) 1236 // Do not perform array reindexing 1237 return reset($subResults); 1238 } else { 1239 $result = call_user_func_array('array_merge', $subResults); 1240 } 1241 1242 return $result; 1243 } 1244 1245 1246 /** 1247 * Returns an array of all term freqs. 1248 * Result array structure: array(docId => freq, ...) 1249 * 1250 * @param Zend_Search_Lucene_Index_Term $term 1251 * @param Zend_Search_Lucene_Index_DocsFilter|null $docsFilter 1252 * @return integer 1253 */ 1254 public function termFreqs(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) 1255 { 1256 $result = array(); 1257 $segmentStartDocId = 0; 1258 foreach ($this->_segmentInfos as $segmentInfo) { 1259 $result += $segmentInfo->termFreqs($term, $segmentStartDocId, $docsFilter); 1260 1261 $segmentStartDocId += $segmentInfo->count(); 1262 } 1263 1264 return $result; 1265 } 1266 1267 /** 1268 * Returns an array of all term positions in the documents. 1269 * Result array structure: array(docId => array(pos1, pos2, ...), ...) 1270 * 1271 * @param Zend_Search_Lucene_Index_Term $term 1272 * @param Zend_Search_Lucene_Index_DocsFilter|null $docsFilter 1273 * @return array 1274 */ 1275 public function termPositions(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) 1276 { 1277 $result = array(); 1278 $segmentStartDocId = 0; 1279 foreach ($this->_segmentInfos as $segmentInfo) { 1280 $result += $segmentInfo->termPositions($term, $segmentStartDocId, $docsFilter); 1281 1282 $segmentStartDocId += $segmentInfo->count(); 1283 } 1284 1285 return $result; 1286 } 1287 1288 1289 /** 1290 * Returns the number of documents in this index containing the $term. 1291 * 1292 * @param Zend_Search_Lucene_Index_Term $term 1293 * @return integer 1294 */ 1295 public function docFreq(Zend_Search_Lucene_Index_Term $term) 1296 { 1297 $result = 0; 1298 foreach ($this->_segmentInfos as $segInfo) { 1299 $termInfo = $segInfo->getTermInfo($term); 1300 if ($termInfo !== null) { 1301 $result += $termInfo->docFreq; 1302 } 1303 } 1304 1305 return $result; 1306 } 1307 1308 1309 /** 1310 * Retrive similarity used by index reader 1311 * 1312 * @return Zend_Search_Lucene_Search_Similarity 1313 */ 1314 public function getSimilarity() 1315 { 1316 /** Zend_Search_Lucene_Search_Similarity */ 1317 // require_once 'Zend/Search/Lucene/Search/Similarity.php'; 1318 1319 return Zend_Search_Lucene_Search_Similarity::getDefault(); 1320 } 1321 1322 1323 /** 1324 * Returns a normalization factor for "field, document" pair. 1325 * 1326 * @param integer $id 1327 * @param string $fieldName 1328 * @return float 1329 */ 1330 public function norm($id, $fieldName) 1331 { 1332 if ($id >= $this->_docCount) { 1333 return null; 1334 } 1335 1336 $segmentStartId = 0; 1337 foreach ($this->_segmentInfos as $segInfo) { 1338 if ($segmentStartId + $segInfo->count() > $id) { 1339 break; 1340 } 1341 1342 $segmentStartId += $segInfo->count(); 1343 } 1344 1345 if ($segInfo->isDeleted($id - $segmentStartId)) { 1346 return 0; 1347 } 1348 1349 return $segInfo->norm($id - $segmentStartId, $fieldName); 1350 } 1351 1352 /** 1353 * Returns true if any documents have been deleted from this index. 1354 * 1355 * @return boolean 1356 */ 1357 public function hasDeletions() 1358 { 1359 foreach ($this->_segmentInfos as $segmentInfo) { 1360 if ($segmentInfo->hasDeletions()) { 1361 return true; 1362 } 1363 } 1364 1365 return false; 1366 } 1367 1368 1369 /** 1370 * Deletes a document from the index. 1371 * $id is an internal document id 1372 * 1373 * @param integer|Zend_Search_Lucene_Search_QueryHit $id 1374 * @throws Zend_Search_Lucene_Exception 1375 */ 1376 public function delete($id) 1377 { 1378 if ($id instanceof Zend_Search_Lucene_Search_QueryHit) { 1379 /* @var $id Zend_Search_Lucene_Search_QueryHit */ 1380 $id = $id->id; 1381 } 1382 1383 if ($id >= $this->_docCount) { 1384 // require_once 'Zend/Search/Lucene/Exception.php'; 1385 throw new Zend_Search_Lucene_Exception('Document id is out of the range.'); 1386 } 1387 1388 $segmentStartId = 0; 1389 foreach ($this->_segmentInfos as $segmentInfo) { 1390 if ($segmentStartId + $segmentInfo->count() > $id) { 1391 break; 1392 } 1393 1394 $segmentStartId += $segmentInfo->count(); 1395 } 1396 $segmentInfo->delete($id - $segmentStartId); 1397 1398 $this->_hasChanges = true; 1399 } 1400 1401 1402 1403 /** 1404 * Adds a document to this index. 1405 * 1406 * @param Zend_Search_Lucene_Document $document 1407 */ 1408 public function addDocument(Zend_Search_Lucene_Document $document) 1409 { 1410 $this->_getIndexWriter()->addDocument($document); 1411 $this->_docCount++; 1412 1413 $this->_hasChanges = true; 1414 } 1415 1416 1417 /** 1418 * Update document counter 1419 */ 1420 private function _updateDocCount() 1421 { 1422 $this->_docCount = 0; 1423 foreach ($this->_segmentInfos as $segInfo) { 1424 $this->_docCount += $segInfo->count(); 1425 } 1426 } 1427 1428 /** 1429 * Commit changes resulting from delete() or undeleteAll() operations. 1430 * 1431 * @todo undeleteAll processing. 1432 */ 1433 public function commit() 1434 { 1435 if ($this->_hasChanges) { 1436 $this->_getIndexWriter()->commit(); 1437 1438 $this->_updateDocCount(); 1439 1440 $this->_hasChanges = false; 1441 } 1442 } 1443 1444 1445 /** 1446 * Optimize index. 1447 * 1448 * Merges all segments into one 1449 */ 1450 public function optimize() 1451 { 1452 // Commit changes if any changes have been made 1453 $this->commit(); 1454 1455 if (count($this->_segmentInfos) > 1 || $this->hasDeletions()) { 1456 $this->_getIndexWriter()->optimize(); 1457 $this->_updateDocCount(); 1458 } 1459 } 1460 1461 1462 /** 1463 * Returns an array of all terms in this index. 1464 * 1465 * @return array 1466 */ 1467 public function terms() 1468 { 1469 $result = array(); 1470 1471 /** Zend_Search_Lucene_Index_TermsPriorityQueue */ 1472 // require_once 'Zend/Search/Lucene/Index/TermsPriorityQueue.php'; 1473 1474 $segmentInfoQueue = new Zend_Search_Lucene_Index_TermsPriorityQueue(); 1475 1476 foreach ($this->_segmentInfos as $segmentInfo) { 1477 $segmentInfo->resetTermsStream(); 1478 1479 // Skip "empty" segments 1480 if ($segmentInfo->currentTerm() !== null) { 1481 $segmentInfoQueue->put($segmentInfo); 1482 } 1483 } 1484 1485 while (($segmentInfo = $segmentInfoQueue->pop()) !== null) { 1486 if ($segmentInfoQueue->top() === null || 1487 $segmentInfoQueue->top()->currentTerm()->key() != 1488 $segmentInfo->currentTerm()->key()) { 1489 // We got new term 1490 $result[] = $segmentInfo->currentTerm(); 1491 } 1492 1493 if ($segmentInfo->nextTerm() !== null) { 1494 // Put segment back into the priority queue 1495 $segmentInfoQueue->put($segmentInfo); 1496 } 1497 } 1498 1499 return $result; 1500 } 1501 1502 1503 /** 1504 * Terms stream priority queue object 1505 * 1506 * @var Zend_Search_Lucene_TermStreamsPriorityQueue 1507 */ 1508 private $_termsStream = null; 1509 1510 /** 1511 * Reset terms stream. 1512 */ 1513 public function resetTermsStream() 1514 { 1515 if ($this->_termsStream === null) { 1516 /** Zend_Search_Lucene_TermStreamsPriorityQueue */ 1517 // require_once 'Zend/Search/Lucene/TermStreamsPriorityQueue.php'; 1518 1519 $this->_termsStream = new Zend_Search_Lucene_TermStreamsPriorityQueue($this->_segmentInfos); 1520 } else { 1521 $this->_termsStream->resetTermsStream(); 1522 } 1523 } 1524 1525 /** 1526 * Skip terms stream up to the specified term preffix. 1527 * 1528 * Prefix contains fully specified field info and portion of searched term 1529 * 1530 * @param Zend_Search_Lucene_Index_Term $prefix 1531 */ 1532 public function skipTo(Zend_Search_Lucene_Index_Term $prefix) 1533 { 1534 $this->_termsStream->skipTo($prefix); 1535 } 1536 1537 /** 1538 * Scans terms dictionary and returns next term 1539 * 1540 * @return Zend_Search_Lucene_Index_Term|null 1541 */ 1542 public function nextTerm() 1543 { 1544 return $this->_termsStream->nextTerm(); 1545 } 1546 1547 /** 1548 * Returns term in current position 1549 * 1550 * @return Zend_Search_Lucene_Index_Term|null 1551 */ 1552 public function currentTerm() 1553 { 1554 return $this->_termsStream->currentTerm(); 1555 } 1556 1557 /** 1558 * Close terms stream 1559 * 1560 * Should be used for resources clean up if stream is not read up to the end 1561 */ 1562 public function closeTermsStream() 1563 { 1564 $this->_termsStream->closeTermsStream(); 1565 $this->_termsStream = null; 1566 } 1567 1568 1569 /************************************************************************* 1570 @todo UNIMPLEMENTED 1571 *************************************************************************/ 1572 /** 1573 * Undeletes all documents currently marked as deleted in this index. 1574 * 1575 * @todo Implementation 1576 */ 1577 public function undeleteAll() 1578 {} 1579 }