File indexing completed on 2024-05-12 06:02:58

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 }