<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Search_Lucene
 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: Zend_Search_Lucene.php 4331 2011-03-16 03:34:08Z kx $
 */

class Zend_Search_Lucene_Analysis_Token { private $_termText; private $_startOffset; private $_endOffset; private $_positionIncrement; public function __construct($text, $start, $end) { $this->_termText = $text; $this->_startOffset = $start; $this->_endOffset = $end; $this->_positionIncrement = 1; } public function setPositionIncrement($positionIncrement) { $this->_positionIncrement = $positionIncrement; } public function getPositionIncrement() { return $this->_positionIncrement; } public function getTermText() { return $this->_termText; } public function getStartOffset() { return $this->_startOffset; } public function getEndOffset() { return $this->_endOffset; } } 
abstract class Zend_Search_Lucene_Analysis_TokenFilter { abstract public function normalize(Zend_Search_Lucene_Analysis_Token $srcToken); } 
abstract class Zend_Search_Lucene_Analysis_Analyzer_Common extends Zend_Search_Lucene_Analysis_Analyzer { private $_filters = array(); public function addFilter(Zend_Search_Lucene_Analysis_TokenFilter $filter) { $this->_filters[] = $filter; } public function normalize(Zend_Search_Lucene_Analysis_Token $token) { foreach ($this->_filters as $filter) { $token = $filter->normalize($token); if ($token === null) { return null; } } return $token; } } 
class Zend_Exception extends Exception { private $_previous = null; public function __construct($msg = '', $code = 0, Exception $previous = null) { if (version_compare(PHP_VERSION, '5.3.0', '<')) { parent::__construct($msg, (int) $code); $this->_previous = $previous; } else { parent::__construct($msg, (int) $code, $previous); } } public function __call($method, array $args) { if ('getprevious' == strtolower($method)) { return $this->_getPrevious(); } return null; } public function __toString() { if (version_compare(PHP_VERSION, '5.3.0', '<')) { if (null !== ($e = $this->getPrevious())) { return $e->__toString() . "\n\nNext " . parent::__toString(); } } return parent::__toString(); } protected function _getPrevious() { return $this->_previous; } } 
class Zend_Search_Exception extends Zend_Exception {} 
class Zend_Search_Lucene_Exception extends Zend_Search_Exception {} 
class Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8 extends Zend_Search_Lucene_Analysis_Analyzer_Common { private $_position; private $_bytePosition; public function __construct() { if (@preg_match('/\pL/u', 'a') != 1) {  throw new Zend_Search_Lucene_Exception('Utf8 analyzer needs PCRE unicode support to be enabled.'); } } public function reset() { $this->_position = 0; $this->_bytePosition = 0; } public function nextToken() { if ($this->_input === null) { return null; } do { if (! preg_match('/[\p{L}]+/u', $this->_input, $match, PREG_OFFSET_CAPTURE, $this->_bytePosition)) { return null; } $matchedWord = $match[0][0]; $binStartPos = $match[0][1]; $startPos = $this->_position + iconv_strlen(substr($this->_input, $this->_bytePosition, $binStartPos - $this->_bytePosition), 'UTF-8'); $endPos = $startPos + iconv_strlen($matchedWord, 'UTF-8'); $this->_bytePosition = $binStartPos + strlen($matchedWord); $this->_position = $endPos; $token = $this->normalize(new Zend_Search_Lucene_Analysis_Token($matchedWord, $startPos, $endPos)); } while ($token === null); return $token; } } 
class Zend_Search_Lucene_Analysis_TokenFilter_LowerCaseUtf8 extends Zend_Search_Lucene_Analysis_TokenFilter { public function __construct() { if (!function_exists('mb_strtolower')) {  throw new Zend_Search_Lucene_Exception('Utf8 compatible lower case filter needs mbstring extension to be enabled.'); } } public function normalize(Zend_Search_Lucene_Analysis_Token $srcToken) { $newToken = new Zend_Search_Lucene_Analysis_Token( mb_strtolower($srcToken->getTermText(), 'UTF-8'), $srcToken->getStartOffset(), $srcToken->getEndOffset()); $newToken->setPositionIncrement($srcToken->getPositionIncrement()); return $newToken; } } 
class Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive extends Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8 { public function __construct() { parent::__construct(); $this->addFilter(new Zend_Search_Lucene_Analysis_TokenFilter_LowerCaseUtf8()); } } 
class Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num extends Zend_Search_Lucene_Analysis_Analyzer_Common { private $_position; private $_bytePosition; public function __construct() { if (@preg_match('/\pL/u', 'a') != 1) {  throw new Zend_Search_Lucene_Exception('Utf8Num analyzer needs PCRE unicode support to be enabled.'); } } public function reset() { $this->_position = 0; $this->_bytePosition = 0; } public function nextToken() { if ($this->_input === null) { return null; } do { if (! preg_match('/[\p{L}\p{N}]+/u', $this->_input, $match, PREG_OFFSET_CAPTURE, $this->_bytePosition)) { return null; } $matchedWord = $match[0][0]; $binStartPos = $match[0][1]; $startPos = $this->_position + iconv_strlen(substr($this->_input, $this->_bytePosition, $binStartPos - $this->_bytePosition), 'UTF-8'); $endPos = $startPos + iconv_strlen($matchedWord, 'UTF-8'); $this->_bytePosition = $binStartPos + strlen($matchedWord); $this->_position = $endPos; $token = $this->normalize(new Zend_Search_Lucene_Analysis_Token($matchedWord, $startPos, $endPos)); } while ($token === null); return $token; } } 
class Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive extends Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num { public function __construct() { parent::__construct(); $this->addFilter(new Zend_Search_Lucene_Analysis_TokenFilter_LowerCaseUtf8()); } } 
abstract class Zend_Search_Lucene_Analysis_Analyzer { private static $_defaultImpl; protected $_input = null; protected $_encoding = ''; public function tokenize($data, $encoding = '') { $this->setInput($data, $encoding); $tokenList = array(); while (($nextToken = $this->nextToken()) !== null) { $tokenList[] = $nextToken; } return $tokenList; } public function setInput($data, $encoding = '') { $this->_input = $data; $this->_encoding = $encoding; $this->reset(); } abstract public function reset(); abstract public function nextToken(); public static function setDefault(Zend_Search_Lucene_Analysis_Analyzer $analyzer) { self::$_defaultImpl = $analyzer; } public static function getDefault() {  if (!self::$_defaultImpl instanceof Zend_Search_Lucene_Analysis_Analyzer) { self::$_defaultImpl = new Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive(); } return self::$_defaultImpl; } } 
class Zend_Search_Lucene_Search_QueryToken { const TT_WORD = 0; const TT_PHRASE = 1; const TT_FIELD = 2; const TT_FIELD_INDICATOR = 3; const TT_REQUIRED = 4; const TT_PROHIBITED = 5; const TT_FUZZY_PROX_MARK = 6; const TT_BOOSTING_MARK = 7; const TT_RANGE_INCL_START = 8; const TT_RANGE_INCL_END = 9; const TT_RANGE_EXCL_START = 10; const TT_RANGE_EXCL_END = 11; const TT_SUBQUERY_START = 12; const TT_SUBQUERY_END = 13; const TT_AND_LEXEME = 14; const TT_OR_LEXEME = 15; const TT_NOT_LEXEME = 16; const TT_TO_LEXEME = 17; const TT_NUMBER = 18; public static function getTypes() { return array( self::TT_WORD, self::TT_PHRASE, self::TT_FIELD, self::TT_FIELD_INDICATOR, self::TT_REQUIRED, self::TT_PROHIBITED, self::TT_FUZZY_PROX_MARK, self::TT_BOOSTING_MARK, self::TT_RANGE_INCL_START, self::TT_RANGE_INCL_END, self::TT_RANGE_EXCL_START, self::TT_RANGE_EXCL_END, self::TT_SUBQUERY_START, self::TT_SUBQUERY_END, self::TT_AND_LEXEME, self::TT_OR_LEXEME, self::TT_NOT_LEXEME, self::TT_TO_LEXEME, self::TT_NUMBER ); } const TC_WORD = 0; const TC_PHRASE = 1; const TC_NUMBER = 2; const TC_SYNTAX_ELEMENT = 3; public $type; public $text; public $position; public function __construct($tokenCategory, $tokenText, $position) { $this->text = $tokenText; $this->position = $position + 1; switch ($tokenCategory) { case self::TC_WORD: if ( strtolower($tokenText) == 'and') { $this->type = self::TT_AND_LEXEME; } else if (strtolower($tokenText) == 'or') { $this->type = self::TT_OR_LEXEME; } else if (strtolower($tokenText) == 'not') { $this->type = self::TT_NOT_LEXEME; } else if (strtolower($tokenText) == 'to') { $this->type = self::TT_TO_LEXEME; } else { $this->type = self::TT_WORD; } break; case self::TC_PHRASE: $this->type = self::TT_PHRASE; break; case self::TC_NUMBER: $this->type = self::TT_NUMBER; break; case self::TC_SYNTAX_ELEMENT: switch ($tokenText) { case ':': $this->type = self::TT_FIELD_INDICATOR; break; case '+': $this->type = self::TT_REQUIRED; break; case '-': $this->type = self::TT_PROHIBITED; break; case '~': $this->type = self::TT_FUZZY_PROX_MARK; break; case '^': $this->type = self::TT_BOOSTING_MARK; break; case '[': $this->type = self::TT_RANGE_INCL_START; break; case ']': $this->type = self::TT_RANGE_INCL_END; break; case '{': $this->type = self::TT_RANGE_EXCL_START; break; case '}': $this->type = self::TT_RANGE_EXCL_END; break; case '(': $this->type = self::TT_SUBQUERY_START; break; case ')': $this->type = self::TT_SUBQUERY_END; break; case '!': $this->type = self::TT_NOT_LEXEME; break; case '&&': $this->type = self::TT_AND_LEXEME; break; case '||': $this->type = self::TT_OR_LEXEME; break; default:  throw new Zend_Search_Lucene_Exception('Unrecognized query syntax lexeme: \'' . $tokenText . '\''); } break; case self::TC_NUMBER: $this->type = self::TT_NUMBER; default:  throw new Zend_Search_Lucene_Exception('Unrecognized lexeme type: \'' . $tokenCategory . '\''); } } } 
class Zend_Search_Lucene_FSMAction { private $_object; private $_method; public function __construct($object, $method) { $this->_object = $object; $this->_method = $method; } public function doAction() { $methodName = $this->_method; $this->_object->$methodName(); } } 
abstract class Zend_Search_Lucene_FSM { private $_states = array(); private $_currentState = null; private $_inputAphabet = array(); private $_rules = array(); private $_entryActions = array(); private $_exitActions = array(); private $_inputActions = array(); private $_transitionActions = array(); public function __construct($states = array(), $inputAphabet = array(), $rules = array()) { $this->addStates($states); $this->addInputSymbols($inputAphabet); $this->addRules($rules); } public function addStates($states) { foreach ($states as $state) { $this->addState($state); } } public function addState($state) { $this->_states[$state] = $state; if ($this->_currentState === null) { $this->_currentState = $state; } } public function setState($state) { if (!isset($this->_states[$state])) {  throw new Zend_Search_Exception('State \'' . $state . '\' is not on of the possible FSM states.'); } $this->_currentState = $state; } public function getState() { return $this->_currentState; } public function addInputSymbols($inputAphabet) { foreach ($inputAphabet as $inputSymbol) { $this->addInputSymbol($inputSymbol); } } public function addInputSymbol($inputSymbol) { $this->_inputAphabet[$inputSymbol] = $inputSymbol; } public function addRules($rules) { foreach ($rules as $rule) { $this->addrule($rule[0], $rule[1], $rule[2], isset($rule[3])?$rule[3]:null); } } public function addRule($sourceState, $input, $targetState, $inputAction = null) { if (!isset($this->_states[$sourceState])) {  throw new Zend_Search_Exception('Undefined source state (' . $sourceState . ').'); } if (!isset($this->_states[$targetState])) {  throw new Zend_Search_Exception('Undefined target state (' . $targetState . ').'); } if (!isset($this->_inputAphabet[$input])) {  throw new Zend_Search_Exception('Undefined input symbol (' . $input . ').'); } if (!isset($this->_rules[$sourceState])) { $this->_rules[$sourceState] = array(); } if (isset($this->_rules[$sourceState][$input])) {  throw new Zend_Search_Exception('Rule for {state,input} pair (' . $sourceState . ', '. $input . ') is already defined.'); } $this->_rules[$sourceState][$input] = $targetState; if ($inputAction !== null) { $this->addInputAction($sourceState, $input, $inputAction); } } public function addEntryAction($state, Zend_Search_Lucene_FSMAction $action) { if (!isset($this->_states[$state])) {  throw new Zend_Search_Exception('Undefined state (' . $state. ').'); } if (!isset($this->_entryActions[$state])) { $this->_entryActions[$state] = array(); } $this->_entryActions[$state][] = $action; } public function addExitAction($state, Zend_Search_Lucene_FSMAction $action) { if (!isset($this->_states[$state])) {  throw new Zend_Search_Exception('Undefined state (' . $state. ').'); } if (!isset($this->_exitActions[$state])) { $this->_exitActions[$state] = array(); } $this->_exitActions[$state][] = $action; } public function addInputAction($state, $inputSymbol, Zend_Search_Lucene_FSMAction $action) { if (!isset($this->_states[$state])) {  throw new Zend_Search_Exception('Undefined state (' . $state. ').'); } if (!isset($this->_inputAphabet[$inputSymbol])) {  throw new Zend_Search_Exception('Undefined input symbol (' . $inputSymbol. ').'); } if (!isset($this->_inputActions[$state])) { $this->_inputActions[$state] = array(); } if (!isset($this->_inputActions[$state][$inputSymbol])) { $this->_inputActions[$state][$inputSymbol] = array(); } $this->_inputActions[$state][$inputSymbol][] = $action; } public function addTransitionAction($sourceState, $targetState, Zend_Search_Lucene_FSMAction $action) { if (!isset($this->_states[$sourceState])) {  throw new Zend_Search_Exception('Undefined source state (' . $sourceState. ').'); } if (!isset($this->_states[$targetState])) {  throw new Zend_Search_Exception('Undefined source state (' . $targetState. ').'); } if (!isset($this->_transitionActions[$sourceState])) { $this->_transitionActions[$sourceState] = array(); } if (!isset($this->_transitionActions[$sourceState][$targetState])) { $this->_transitionActions[$sourceState][$targetState] = array(); } $this->_transitionActions[$sourceState][$targetState][] = $action; } public function process($input) { if (!isset($this->_rules[$this->_currentState])) {  throw new Zend_Search_Exception('There is no any rule for current state (' . $this->_currentState . ').'); } if (!isset($this->_rules[$this->_currentState][$input])) {  throw new Zend_Search_Exception('There is no any rule for {current state, input} pair (' . $this->_currentState . ', ' . $input . ').'); } $sourceState = $this->_currentState; $targetState = $this->_rules[$this->_currentState][$input]; if ($sourceState != $targetState && isset($this->_exitActions[$sourceState])) { foreach ($this->_exitActions[$sourceState] as $action) { $action->doAction(); } } if (isset($this->_inputActions[$sourceState]) && isset($this->_inputActions[$sourceState][$input])) { foreach ($this->_inputActions[$sourceState][$input] as $action) { $action->doAction(); } } $this->_currentState = $targetState; if (isset($this->_transitionActions[$sourceState]) && isset($this->_transitionActions[$sourceState][$targetState])) { foreach ($this->_transitionActions[$sourceState][$targetState] as $action) { $action->doAction(); } } if ($sourceState != $targetState && isset($this->_entryActions[$targetState])) { foreach ($this->_entryActions[$targetState] as $action) { $action->doAction(); } } } public function reset() { if (count($this->_states) == 0) {  throw new Zend_Search_Exception('There is no any state defined for FSM.'); } $this->_currentState = $this->_states[0]; } } 
class Zend_Search_Lucene_Search_QueryParserException extends Zend_Search_Lucene_Exception {} 
class Zend_Search_Lucene_Search_QueryLexer extends Zend_Search_Lucene_FSM { const ST_WHITE_SPACE = 0; const ST_SYNT_LEXEME = 1; const ST_LEXEME = 2; const ST_QUOTED_LEXEME = 3; const ST_ESCAPED_CHAR = 4; const ST_ESCAPED_QCHAR = 5; const ST_LEXEME_MODIFIER = 6; const ST_NUMBER = 7; const ST_MANTISSA = 8; const ST_ERROR = 9; const IN_WHITE_SPACE = 0; const IN_SYNT_CHAR = 1; const IN_LEXEME_MODIFIER = 2; const IN_ESCAPE_CHAR = 3; const IN_QUOTE = 4; const IN_DECIMAL_POINT = 5; const IN_ASCII_DIGIT = 6; const IN_CHAR = 7; const IN_MUTABLE_CHAR = 8; const QUERY_WHITE_SPACE_CHARS = " \n\r\t"; const QUERY_SYNT_CHARS = ':()[]{}!|&'; const QUERY_MUTABLE_CHARS = '+-'; const QUERY_DOUBLECHARLEXEME_CHARS = '|&'; const QUERY_LEXEMEMODIFIER_CHARS = '~^'; const QUERY_ASCIIDIGITS_CHARS = '0123456789'; private $_lexemes; private $_queryString; private $_queryStringPosition; private $_currentLexeme; public function __construct() { parent::__construct( array(self::ST_WHITE_SPACE, self::ST_SYNT_LEXEME, self::ST_LEXEME, self::ST_QUOTED_LEXEME, self::ST_ESCAPED_CHAR, self::ST_ESCAPED_QCHAR, self::ST_LEXEME_MODIFIER, self::ST_NUMBER, self::ST_MANTISSA, self::ST_ERROR), array(self::IN_WHITE_SPACE, self::IN_SYNT_CHAR, self::IN_MUTABLE_CHAR, self::IN_LEXEME_MODIFIER, self::IN_ESCAPE_CHAR, self::IN_QUOTE, self::IN_DECIMAL_POINT, self::IN_ASCII_DIGIT, self::IN_CHAR)); $lexemeModifierErrorAction = new Zend_Search_Lucene_FSMAction($this, 'lexModifierErrException'); $quoteWithinLexemeErrorAction = new Zend_Search_Lucene_FSMAction($this, 'quoteWithinLexemeErrException'); $wrongNumberErrorAction = new Zend_Search_Lucene_FSMAction($this, 'wrongNumberErrException'); $this->addRules(array( array(self::ST_WHITE_SPACE, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), array(self::ST_WHITE_SPACE, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), array(self::ST_WHITE_SPACE, self::IN_MUTABLE_CHAR, self::ST_SYNT_LEXEME), array(self::ST_WHITE_SPACE, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), array(self::ST_WHITE_SPACE, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_CHAR), array(self::ST_WHITE_SPACE, self::IN_QUOTE, self::ST_QUOTED_LEXEME), array(self::ST_WHITE_SPACE, self::IN_DECIMAL_POINT, self::ST_LEXEME), array(self::ST_WHITE_SPACE, self::IN_ASCII_DIGIT, self::ST_LEXEME), array(self::ST_WHITE_SPACE, self::IN_CHAR, self::ST_LEXEME) )); $this->addRules(array( array(self::ST_SYNT_LEXEME, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), array(self::ST_SYNT_LEXEME, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), array(self::ST_SYNT_LEXEME, self::IN_MUTABLE_CHAR, self::ST_SYNT_LEXEME), array(self::ST_SYNT_LEXEME, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), array(self::ST_SYNT_LEXEME, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_CHAR), array(self::ST_SYNT_LEXEME, self::IN_QUOTE, self::ST_QUOTED_LEXEME), array(self::ST_SYNT_LEXEME, self::IN_DECIMAL_POINT, self::ST_LEXEME), array(self::ST_SYNT_LEXEME, self::IN_ASCII_DIGIT, self::ST_LEXEME), array(self::ST_SYNT_LEXEME, self::IN_CHAR, self::ST_LEXEME) )); $this->addRules(array( array(self::ST_LEXEME, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), array(self::ST_LEXEME, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), array(self::ST_LEXEME, self::IN_MUTABLE_CHAR, self::ST_LEXEME), array(self::ST_LEXEME, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), array(self::ST_LEXEME, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_CHAR), array(self::ST_LEXEME, self::IN_QUOTE, self::ST_ERROR, $quoteWithinLexemeErrorAction), array(self::ST_LEXEME, self::IN_DECIMAL_POINT, self::ST_LEXEME), array(self::ST_LEXEME, self::IN_ASCII_DIGIT, self::ST_LEXEME), array(self::ST_LEXEME, self::IN_CHAR, self::ST_LEXEME) )); $this->addRules(array( array(self::ST_QUOTED_LEXEME, self::IN_WHITE_SPACE, self::ST_QUOTED_LEXEME), array(self::ST_QUOTED_LEXEME, self::IN_SYNT_CHAR, self::ST_QUOTED_LEXEME), array(self::ST_QUOTED_LEXEME, self::IN_MUTABLE_CHAR, self::ST_QUOTED_LEXEME), array(self::ST_QUOTED_LEXEME, self::IN_LEXEME_MODIFIER, self::ST_QUOTED_LEXEME), array(self::ST_QUOTED_LEXEME, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_QCHAR), array(self::ST_QUOTED_LEXEME, self::IN_QUOTE, self::ST_WHITE_SPACE), array(self::ST_QUOTED_LEXEME, self::IN_DECIMAL_POINT, self::ST_QUOTED_LEXEME), array(self::ST_QUOTED_LEXEME, self::IN_ASCII_DIGIT, self::ST_QUOTED_LEXEME), array(self::ST_QUOTED_LEXEME, self::IN_CHAR, self::ST_QUOTED_LEXEME) )); $this->addRules(array( array(self::ST_ESCAPED_CHAR, self::IN_WHITE_SPACE, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_SYNT_CHAR, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_MUTABLE_CHAR, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_LEXEME_MODIFIER, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_ESCAPE_CHAR, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_QUOTE, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_DECIMAL_POINT, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_ASCII_DIGIT, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_CHAR, self::ST_LEXEME) )); $this->addRules(array( array(self::ST_ESCAPED_QCHAR, self::IN_WHITE_SPACE, self::ST_QUOTED_LEXEME), array(self::ST_ESCAPED_QCHAR, self::IN_SYNT_CHAR, self::ST_QUOTED_LEXEME), array(self::ST_ESCAPED_QCHAR, self::IN_MUTABLE_CHAR, self::ST_QUOTED_LEXEME), array(self::ST_ESCAPED_QCHAR, self::IN_LEXEME_MODIFIER, self::ST_QUOTED_LEXEME), array(self::ST_ESCAPED_QCHAR, self::IN_ESCAPE_CHAR, self::ST_QUOTED_LEXEME), array(self::ST_ESCAPED_QCHAR, self::IN_QUOTE, self::ST_QUOTED_LEXEME), array(self::ST_ESCAPED_QCHAR, self::IN_DECIMAL_POINT, self::ST_QUOTED_LEXEME), array(self::ST_ESCAPED_QCHAR, self::IN_ASCII_DIGIT, self::ST_QUOTED_LEXEME), array(self::ST_ESCAPED_QCHAR, self::IN_CHAR, self::ST_QUOTED_LEXEME) )); $this->addRules(array( array(self::ST_LEXEME_MODIFIER, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), array(self::ST_LEXEME_MODIFIER, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), array(self::ST_LEXEME_MODIFIER, self::IN_MUTABLE_CHAR, self::ST_SYNT_LEXEME), array(self::ST_LEXEME_MODIFIER, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), array(self::ST_LEXEME_MODIFIER, self::IN_ESCAPE_CHAR, self::ST_ERROR, $lexemeModifierErrorAction), array(self::ST_LEXEME_MODIFIER, self::IN_QUOTE, self::ST_ERROR, $lexemeModifierErrorAction), array(self::ST_LEXEME_MODIFIER, self::IN_DECIMAL_POINT, self::ST_MANTISSA), array(self::ST_LEXEME_MODIFIER, self::IN_ASCII_DIGIT, self::ST_NUMBER), array(self::ST_LEXEME_MODIFIER, self::IN_CHAR, self::ST_ERROR, $lexemeModifierErrorAction), )); $this->addRules(array( array(self::ST_NUMBER, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), array(self::ST_NUMBER, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), array(self::ST_NUMBER, self::IN_MUTABLE_CHAR, self::ST_SYNT_LEXEME), array(self::ST_NUMBER, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), array(self::ST_NUMBER, self::IN_ESCAPE_CHAR, self::ST_ERROR, $wrongNumberErrorAction), array(self::ST_NUMBER, self::IN_QUOTE, self::ST_ERROR, $wrongNumberErrorAction), array(self::ST_NUMBER, self::IN_DECIMAL_POINT, self::ST_MANTISSA), array(self::ST_NUMBER, self::IN_ASCII_DIGIT, self::ST_NUMBER), array(self::ST_NUMBER, self::IN_CHAR, self::ST_ERROR, $wrongNumberErrorAction), )); $this->addRules(array( array(self::ST_MANTISSA, self::IN_WHITE_SPACE, self::ST_WHITE_SPACE), array(self::ST_MANTISSA, self::IN_SYNT_CHAR, self::ST_SYNT_LEXEME), array(self::ST_MANTISSA, self::IN_MUTABLE_CHAR, self::ST_SYNT_LEXEME), array(self::ST_MANTISSA, self::IN_LEXEME_MODIFIER, self::ST_LEXEME_MODIFIER), array(self::ST_MANTISSA, self::IN_ESCAPE_CHAR, self::ST_ERROR, $wrongNumberErrorAction), array(self::ST_MANTISSA, self::IN_QUOTE, self::ST_ERROR, $wrongNumberErrorAction), array(self::ST_MANTISSA, self::IN_DECIMAL_POINT, self::ST_ERROR, $wrongNumberErrorAction), array(self::ST_MANTISSA, self::IN_ASCII_DIGIT, self::ST_MANTISSA), array(self::ST_MANTISSA, self::IN_CHAR, self::ST_ERROR, $wrongNumberErrorAction), )); $syntaxLexemeAction = new Zend_Search_Lucene_FSMAction($this, 'addQuerySyntaxLexeme'); $lexemeModifierAction = new Zend_Search_Lucene_FSMAction($this, 'addLexemeModifier'); $addLexemeAction = new Zend_Search_Lucene_FSMAction($this, 'addLexeme'); $addQuotedLexemeAction = new Zend_Search_Lucene_FSMAction($this, 'addQuotedLexeme'); $addNumberLexemeAction = new Zend_Search_Lucene_FSMAction($this, 'addNumberLexeme'); $addLexemeCharAction = new Zend_Search_Lucene_FSMAction($this, 'addLexemeChar'); $this->addEntryAction(self::ST_SYNT_LEXEME, $syntaxLexemeAction); $this->addTransitionAction(self::ST_SYNT_LEXEME, self::ST_SYNT_LEXEME, $syntaxLexemeAction); $this->addEntryAction(self::ST_LEXEME, $addLexemeCharAction); $this->addTransitionAction(self::ST_LEXEME, self::ST_LEXEME, $addLexemeCharAction); $this->addTransitionAction(self::ST_LEXEME, self::ST_WHITE_SPACE, $addLexemeAction); $this->addTransitionAction(self::ST_LEXEME, self::ST_SYNT_LEXEME, $addLexemeAction); $this->addTransitionAction(self::ST_LEXEME, self::ST_QUOTED_LEXEME, $addLexemeAction); $this->addTransitionAction(self::ST_LEXEME, self::ST_LEXEME_MODIFIER, $addLexemeAction); $this->addTransitionAction(self::ST_LEXEME, self::ST_NUMBER, $addLexemeAction); $this->addTransitionAction(self::ST_LEXEME, self::ST_MANTISSA, $addLexemeAction); $this->addTransitionAction(self::ST_QUOTED_LEXEME, self::ST_QUOTED_LEXEME, $addLexemeCharAction); $this->addTransitionAction(self::ST_ESCAPED_QCHAR, self::ST_QUOTED_LEXEME, $addLexemeCharAction); $this->addTransitionAction(self::ST_QUOTED_LEXEME, self::ST_WHITE_SPACE, $addQuotedLexemeAction); $this->addEntryAction(self::ST_LEXEME_MODIFIER, $lexemeModifierAction); $this->addEntryAction(self::ST_NUMBER, $addLexemeCharAction); $this->addEntryAction(self::ST_MANTISSA, $addLexemeCharAction); $this->addTransitionAction(self::ST_NUMBER, self::ST_NUMBER, $addLexemeCharAction); $this->addTransitionAction(self::ST_MANTISSA, self::ST_MANTISSA, $addLexemeCharAction); $this->addTransitionAction(self::ST_NUMBER, self::ST_WHITE_SPACE, $addNumberLexemeAction); $this->addTransitionAction(self::ST_NUMBER, self::ST_SYNT_LEXEME, $addNumberLexemeAction); $this->addTransitionAction(self::ST_NUMBER, self::ST_LEXEME_MODIFIER, $addNumberLexemeAction); $this->addTransitionAction(self::ST_MANTISSA, self::ST_WHITE_SPACE, $addNumberLexemeAction); $this->addTransitionAction(self::ST_MANTISSA, self::ST_SYNT_LEXEME, $addNumberLexemeAction); $this->addTransitionAction(self::ST_MANTISSA, self::ST_LEXEME_MODIFIER, $addNumberLexemeAction); } private function _translateInput($char) { if (strpos(self::QUERY_WHITE_SPACE_CHARS, $char) !== false) { return self::IN_WHITE_SPACE; } else if (strpos(self::QUERY_SYNT_CHARS, $char) !== false) { return self::IN_SYNT_CHAR; } else if (strpos(self::QUERY_MUTABLE_CHARS, $char) !== false) { return self::IN_MUTABLE_CHAR; } else if (strpos(self::QUERY_LEXEMEMODIFIER_CHARS, $char) !== false) { return self::IN_LEXEME_MODIFIER; } else if (strpos(self::QUERY_ASCIIDIGITS_CHARS, $char) !== false) { return self::IN_ASCII_DIGIT; } else if ($char === '"' ) { return self::IN_QUOTE; } else if ($char === '.' ) { return self::IN_DECIMAL_POINT; } else if ($char === '\\') { return self::IN_ESCAPE_CHAR; } else { return self::IN_CHAR; } } public function tokenize($inputString, $encoding) { $this->reset(); $this->_lexemes = array(); $this->_queryString = array(); if (PHP_OS == 'AIX' && $encoding == '') { $encoding = 'ISO8859-1'; } $strLength = iconv_strlen($inputString, $encoding); $inputString .= ' '; for ($count = 0; $count < $strLength; $count++) { $this->_queryString[$count] = iconv_substr($inputString, $count, 1, $encoding); } for ($this->_queryStringPosition = 0; $this->_queryStringPosition < count($this->_queryString); $this->_queryStringPosition++) { $this->process($this->_translateInput($this->_queryString[$this->_queryStringPosition])); } $this->process(self::IN_WHITE_SPACE); if ($this->getState() != self::ST_WHITE_SPACE) {  throw new Zend_Search_Lucene_Search_QueryParserException('Unexpected end of query'); } $this->_queryString = null; return $this->_lexemes; } public function addQuerySyntaxLexeme() { $lexeme = $this->_queryString[$this->_queryStringPosition]; if (strpos(self::QUERY_DOUBLECHARLEXEME_CHARS, $lexeme) !== false) { $this->_queryStringPosition++; if ($this->_queryStringPosition == count($this->_queryString) || $this->_queryString[$this->_queryStringPosition] != $lexeme) {  throw new Zend_Search_Lucene_Search_QueryParserException('Two chars lexeme expected. ' . $this->_positionMsg()); } $lexeme .= $lexeme; } $token = new Zend_Search_Lucene_Search_QueryToken( Zend_Search_Lucene_Search_QueryToken::TC_SYNTAX_ELEMENT, $lexeme, $this->_queryStringPosition); if ($token->type == Zend_Search_Lucene_Search_QueryToken::TT_FIELD_INDICATOR) { $token = array_pop($this->_lexemes); if ($token === null || $token->type != Zend_Search_Lucene_Search_QueryToken::TT_WORD) {  throw new Zend_Search_Lucene_Search_QueryParserException('Field mark \':\' must follow field name. ' . $this->_positionMsg()); } $token->type = Zend_Search_Lucene_Search_QueryToken::TT_FIELD; } $this->_lexemes[] = $token; } public function addLexemeModifier() { $this->_lexemes[] = new Zend_Search_Lucene_Search_QueryToken( Zend_Search_Lucene_Search_QueryToken::TC_SYNTAX_ELEMENT, $this->_queryString[$this->_queryStringPosition], $this->_queryStringPosition); } public function addLexeme() { $this->_lexemes[] = new Zend_Search_Lucene_Search_QueryToken( Zend_Search_Lucene_Search_QueryToken::TC_WORD, $this->_currentLexeme, $this->_queryStringPosition - 1); $this->_currentLexeme = ''; } public function addQuotedLexeme() { $this->_lexemes[] = new Zend_Search_Lucene_Search_QueryToken( Zend_Search_Lucene_Search_QueryToken::TC_PHRASE, $this->_currentLexeme, $this->_queryStringPosition); $this->_currentLexeme = ''; } public function addNumberLexeme() { $this->_lexemes[] = new Zend_Search_Lucene_Search_QueryToken( Zend_Search_Lucene_Search_QueryToken::TC_NUMBER, $this->_currentLexeme, $this->_queryStringPosition - 1); $this->_currentLexeme = ''; } public function addLexemeChar() { $this->_currentLexeme .= $this->_queryString[$this->_queryStringPosition]; } private function _positionMsg() { return 'Position is ' . $this->_queryStringPosition . '.'; } public function lexModifierErrException() {  throw new Zend_Search_Lucene_Search_QueryParserException('Lexeme modifier character can be followed only by number, white space or query syntax element. ' . $this->_positionMsg()); } public function quoteWithinLexemeErrException() {  throw new Zend_Search_Lucene_Search_QueryParserException('Quote within lexeme must be escaped by \'\\\' char. ' . $this->_positionMsg()); } public function wrongNumberErrException() {  throw new Zend_Search_Lucene_Search_QueryParserException('Wrong number syntax.' . $this->_positionMsg()); } } 
interface Zend_Search_Lucene_Search_Highlighter_Interface { public function setDocument(Zend_Search_Lucene_Document_Html $document); public function getDocument(); public function highlight($words); } 
class Zend_Search_Lucene_Search_Highlighter_Default implements Zend_Search_Lucene_Search_Highlighter_Interface { protected $_highlightColors = array('#66ffff', '#ff66ff', '#ffff66', '#ff8888', '#88ff88', '#8888ff', '#88dddd', '#dd88dd', '#dddd88', '#aaddff', '#aaffdd', '#ddaaff', '#ddffaa', '#ffaadd', '#ffddaa'); protected $_currentColorIndex = 0; protected $_doc; public function setDocument(Zend_Search_Lucene_Document_Html $document) { $this->_doc = $document; } public function getDocument() { return $this->_doc; } public function highlight($words) { $color = $this->_highlightColors[$this->_currentColorIndex]; $this->_currentColorIndex = ($this->_currentColorIndex + 1) % count($this->_highlightColors); $this->_doc->highlight($words, $color); } } 
abstract class Zend_Search_Lucene_Search_Query { private $_boost = 1; protected $_weight = null; private $_currentColorIndex = 0; public function getBoost() { return $this->_boost; } public function setBoost($boost) { $this->_boost = $boost; } abstract public function score($docId, Zend_Search_Lucene_Interface $reader); abstract public function matchedDocs(); abstract public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null); abstract public function createWeight(Zend_Search_Lucene_Interface $reader); protected function _initWeight(Zend_Search_Lucene_Interface $reader) { if ($this->_weight !== null) { return $this->_weight; } $this->createWeight($reader); $sum = $this->_weight->sumOfSquaredWeights(); $queryNorm = $reader->getSimilarity()->queryNorm($sum); $this->_weight->normalize($queryNorm); } abstract public function rewrite(Zend_Search_Lucene_Interface $index); abstract public function optimize(Zend_Search_Lucene_Interface $index); public function reset() { $this->_weight = null; } abstract public function __toString(); abstract public function getQueryTerms(); abstract protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter); public function highlightMatches($inputHTML, $defaultEncoding = '', $highlighter = null) { if ($highlighter === null) {  $highlighter = new Zend_Search_Lucene_Search_Highlighter_Default(); }  $doc = Zend_Search_Lucene_Document_Html::loadHTML($inputHTML, false, $defaultEncoding); $highlighter->setDocument($doc); $this->_highlightMatches($highlighter); return $doc->getHTML(); } public function htmlFragmentHighlightMatches($inputHtmlFragment, $encoding = 'UTF-8', $highlighter = null) { if ($highlighter === null) {  $highlighter = new Zend_Search_Lucene_Search_Highlighter_Default(); } $inputHTML = '<html><head><META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=UTF-8"/></head><body>' . iconv($encoding, 'UTF-8//IGNORE', $inputHtmlFragment) . '</body></html>';  $doc = Zend_Search_Lucene_Document_Html::loadHTML($inputHTML); $highlighter->setDocument($doc); $this->_highlightMatches($highlighter); return $doc->getHtmlBody(); } } 
abstract class Zend_Search_Lucene_Search_Weight { protected $_queryNorm; protected $_value; public function getValue() { return $this->_value; } abstract public function sumOfSquaredWeights(); abstract public function normalize($norm); } 
class Zend_Search_Lucene_Search_Weight_Empty extends Zend_Search_Lucene_Search_Weight { public function sumOfSquaredWeights() { return 1; } public function normalize($queryNorm) { } } 
class Zend_Search_Lucene_Search_Query_Insignificant extends Zend_Search_Lucene_Search_Query { public function rewrite(Zend_Search_Lucene_Interface $index) { return $this; } public function optimize(Zend_Search_Lucene_Interface $index) { return $this; } public function createWeight(Zend_Search_Lucene_Interface $reader) {  return new Zend_Search_Lucene_Search_Weight_Empty(); } public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null) { } public function matchedDocs() { return array(); } public function score($docId, Zend_Search_Lucene_Interface $reader) { return 0; } public function getQueryTerms() { return array(); } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { } public function __toString() { return '<InsignificantQuery>'; } } 
class Zend_Search_Lucene_Search_Query_Empty extends Zend_Search_Lucene_Search_Query { public function rewrite(Zend_Search_Lucene_Interface $index) { return $this; } public function optimize(Zend_Search_Lucene_Interface $index) { return $this; } public function createWeight(Zend_Search_Lucene_Interface $reader) {  return new Zend_Search_Lucene_Search_Weight_Empty(); } public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null) { } public function matchedDocs() { return array(); } public function score($docId, Zend_Search_Lucene_Interface $reader) { return 0; } public function getQueryTerms() { return array(); } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { } public function __toString() { return '<EmptyQuery>'; } } 
class Zend_Search_Lucene_Index_Term { public $field; public $text; public function __construct($text, $field = null) { $this->field = ($field === null)? Zend_Search_Lucene::getDefaultSearchField() : $field; $this->text = $text; } public function key() { return $this->field . chr(0) . $this->text; } public static function getPrefix($str, $length) { $prefixBytes = 0; $prefixChars = 0; while ($prefixBytes < strlen($str) && $prefixChars < $length) { $charBytes = 1; if ((ord($str[$prefixBytes]) & 0xC0) == 0xC0) { $charBytes++; if (ord($str[$prefixBytes]) & 0x20 ) { $charBytes++; if (ord($str[$prefixBytes]) & 0x10 ) { $charBytes++; } } } if ($prefixBytes + $charBytes > strlen($str)) { break; } $prefixChars++; $prefixBytes += $charBytes; } return substr($str, 0, $prefixBytes); } public static function getLength($str) { $bytes = 0; $chars = 0; while ($bytes < strlen($str)) { $charBytes = 1; if ((ord($str[$bytes]) & 0xC0) == 0xC0) { $charBytes++; if (ord($str[$bytes]) & 0x20 ) { $charBytes++; if (ord($str[$bytes]) & 0x10 ) { $charBytes++; } } } if ($bytes + $charBytes > strlen($str)) { break; } $chars++; $bytes += $charBytes; } return $chars; } } 
class Zend_Search_Lucene_Search_Weight_Term extends Zend_Search_Lucene_Search_Weight { private $_reader; private $_term; private $_query; private $_idf; private $_queryWeight; public function __construct(Zend_Search_Lucene_Index_Term $term, Zend_Search_Lucene_Search_Query $query, Zend_Search_Lucene_Interface $reader) { $this->_term = $term; $this->_query = $query; $this->_reader = $reader; } public function sumOfSquaredWeights() { $this->_idf = $this->_reader->getSimilarity()->idf($this->_term, $this->_reader); $this->_queryWeight = $this->_idf * $this->_query->getBoost(); return $this->_queryWeight * $this->_queryWeight; } public function normalize($queryNorm) { $this->_queryNorm = $queryNorm; $this->_queryWeight *= $queryNorm; $this->_value = $this->_queryWeight * $this->_idf; } } 
class Zend_Search_Lucene_Search_Query_Term extends Zend_Search_Lucene_Search_Query { private $_term; private $_docVector = null; private $_termFreqs; public function __construct(Zend_Search_Lucene_Index_Term $term) { $this->_term = $term; } public function rewrite(Zend_Search_Lucene_Interface $index) { if ($this->_term->field != null) { return $this; } else {  $query = new Zend_Search_Lucene_Search_Query_MultiTerm(); $query->setBoost($this->getBoost());  foreach ($index->getFieldNames(true) as $fieldName) { $term = new Zend_Search_Lucene_Index_Term($this->_term->text, $fieldName); $query->addTerm($term); } return $query->rewrite($index); } } public function optimize(Zend_Search_Lucene_Interface $index) { if (!$index->hasTerm($this->_term)) {  return new Zend_Search_Lucene_Search_Query_Empty(); } return $this; } public function createWeight(Zend_Search_Lucene_Interface $reader) {  $this->_weight = new Zend_Search_Lucene_Search_Weight_Term($this->_term, $this, $reader); return $this->_weight; } public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null) { $this->_docVector = array_flip($reader->termDocs($this->_term, $docsFilter)); $this->_termFreqs = $reader->termFreqs($this->_term, $docsFilter); $this->_initWeight($reader); } public function matchedDocs() { return $this->_docVector; } public function score($docId, Zend_Search_Lucene_Interface $reader) { if (isset($this->_docVector[$docId])) { return $reader->getSimilarity()->tf($this->_termFreqs[$docId]) * $this->_weight->getValue() * $reader->norm($docId, $this->_term->field) * $this->getBoost(); } else { return 0; } } public function getQueryTerms() { return array($this->_term); } public function getTerm() { return $this->_term; } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { $highlighter->highlight($this->_term->text); } public function __toString() { if ($this->_term->field !== null) { $query = $this->_term->field . ':'; } else { $query = ''; } $query .= $this->_term->text; if ($this->getBoost() != 1) { $query = $query . '^' . round($this->getBoost(), 4); } return $query; } } 
class Zend_Search_Lucene_Search_Weight_MultiTerm extends Zend_Search_Lucene_Search_Weight { private $_reader; private $_query; private $_weights; public function __construct(Zend_Search_Lucene_Search_Query $query, Zend_Search_Lucene_Interface $reader) { $this->_query = $query; $this->_reader = $reader; $this->_weights = array(); $signs = $query->getSigns(); foreach ($query->getTerms() as $id => $term) { if ($signs === null || $signs[$id] === null || $signs[$id]) {  $this->_weights[$id] = new Zend_Search_Lucene_Search_Weight_Term($term, $query, $reader); $query->setWeight($id, $this->_weights[$id]); } } } public function getValue() { return $this->_query->getBoost(); } public function sumOfSquaredWeights() { $sum = 0; foreach ($this->_weights as $weight) { $sum += $weight->sumOfSquaredWeights(); } $sum *= $this->_query->getBoost() * $this->_query->getBoost(); if ($sum == 0) { $sum = 1.0; } return $sum; } public function normalize($queryNorm) { $queryNorm *= $this->_query->getBoost(); foreach ($this->_weights as $weight) { $weight->normalize($queryNorm); } } } 
class Zend_Search_Lucene_Index_DocsFilter { public $segmentFilters = array(); } 
class Zend_Search_Lucene_Search_Query_MultiTerm extends Zend_Search_Lucene_Search_Query { private $_terms = array(); private $_signs; private $_resVector = null; private $_termsFreqs = array(); private $_coord = null; private $_weights = array(); public function __construct($terms = null, $signs = null) { if (is_array($terms)) {  if (count($terms) > Zend_Search_Lucene::getTermsPerQueryLimit()) { throw new Zend_Search_Lucene_Exception('Terms per query limit is reached.'); } $this->_terms = $terms; $this->_signs = null; if (is_array($signs)) { foreach ($signs as $sign ) { if ($sign !== true) { $this->_signs = $signs; break; } } } } } public function addTerm(Zend_Search_Lucene_Index_Term $term, $sign = null) { if ($sign !== true || $this->_signs !== null) { if ($this->_signs === null) { $this->_signs = array(); foreach ($this->_terms as $prevTerm) { $this->_signs[] = true; } } $this->_signs[] = $sign; } $this->_terms[] = $term; } public function rewrite(Zend_Search_Lucene_Interface $index) { if (count($this->_terms) == 0) {  return new Zend_Search_Lucene_Search_Query_Empty(); } $allQualified = true; foreach ($this->_terms as $term) { if ($term->field === null) { $allQualified = false; break; } } if ($allQualified) { return $this; } else {  $query = new Zend_Search_Lucene_Search_Query_Boolean(); $query->setBoost($this->getBoost());  foreach ($this->_terms as $termId => $term) { $subquery = new Zend_Search_Lucene_Search_Query_Term($term); $query->addSubquery($subquery->rewrite($index), ($this->_signs === null)? true : $this->_signs[$termId]); } return $query; } } public function optimize(Zend_Search_Lucene_Interface $index) { $terms = $this->_terms; $signs = $this->_signs; foreach ($terms as $id => $term) { if (!$index->hasTerm($term)) { if ($signs === null || $signs[$id] === true) {  return new Zend_Search_Lucene_Search_Query_Empty(); } else { unset($terms[$id]); unset($signs[$id]); } } } $allProhibited = true; if ($signs === null) { $allProhibited = false; } else { foreach ($signs as $sign) { if ($sign !== false) { $allProhibited = false; break; } } } if ($allProhibited) {  return new Zend_Search_Lucene_Search_Query_Empty(); } if (count($terms) == 1) {  $optimizedQuery = new Zend_Search_Lucene_Search_Query_Term(reset($terms)); $optimizedQuery->setBoost($this->getBoost()); return $optimizedQuery; } if (count($terms) == 0) {  return new Zend_Search_Lucene_Search_Query_Empty(); } $optimizedQuery = new Zend_Search_Lucene_Search_Query_MultiTerm($terms, $signs); $optimizedQuery->setBoost($this->getBoost()); return $optimizedQuery; } public function getTerms() { return $this->_terms; } public function getSigns() { return $this->_signs; } public function setWeight($num, $weight) { $this->_weights[$num] = $weight; } public function createWeight(Zend_Search_Lucene_Interface $reader) {  $this->_weight = new Zend_Search_Lucene_Search_Weight_MultiTerm($this, $reader); return $this->_weight; } private function _calculateConjunctionResult(Zend_Search_Lucene_Interface $reader) { $this->_resVector = null; if (count($this->_terms) == 0) { $this->_resVector = array(); } $docFreqs = array(); $ids = array(); foreach ($this->_terms as $id => $term) { $docFreqs[] = $reader->docFreq($term); $ids[] = $id; } array_multisort($docFreqs, SORT_ASC, SORT_NUMERIC, $ids, SORT_ASC, SORT_NUMERIC, $this->_terms);  $docsFilter = new Zend_Search_Lucene_Index_DocsFilter(); foreach ($this->_terms as $termId => $term) { $termDocs = $reader->termDocs($term, $docsFilter); } $this->_resVector = array_flip($termDocs); foreach ($this->_terms as $termId => $term) { $this->_termsFreqs[$termId] = $reader->termFreqs($term, $docsFilter); } } private function _calculateNonConjunctionResult(Zend_Search_Lucene_Interface $reader) { $requiredVectors = array(); $requiredVectorsSizes = array(); $requiredVectorsIds = array(); $optional = array(); $prohibited = array(); foreach ($this->_terms as $termId => $term) { $termDocs = array_flip($reader->termDocs($term)); if ($this->_signs[$termId] === true) { $requiredVectors[] = $termDocs; $requiredVectorsSizes[] = count($termDocs); $requiredVectorsIds[] = $termId; } elseif ($this->_signs[$termId] === false) { $prohibited += $termDocs; } else { $optional += $termDocs; } $this->_termsFreqs[$termId] = $reader->termFreqs($term); } array_multisort($requiredVectorsSizes, SORT_ASC, SORT_NUMERIC, $requiredVectorsIds, SORT_ASC, SORT_NUMERIC, $requiredVectors); $required = null; foreach ($requiredVectors as $nextResVector) { if($required === null) { $required = $nextResVector; } else { $updatedVector = array(); foreach ($required as $id => $value) { if (isset($nextResVector[$id])) { $updatedVector[$id] = $value; } } $required = $updatedVector; } if (count($required) == 0) { break; } } if ($required !== null) { $this->_resVector = $required; } else { $this->_resVector = $optional; } if (count($prohibited) != 0) { if (count($this->_resVector) < count($prohibited)) { $updatedVector = $this->_resVector; foreach ($this->_resVector as $id => $value) { if (isset($prohibited[$id])) { unset($updatedVector[$id]); } } $this->_resVector = $updatedVector; } else { $updatedVector = $this->_resVector; foreach ($prohibited as $id => $value) { unset($updatedVector[$id]); } $this->_resVector = $updatedVector; } } ksort($this->_resVector, SORT_NUMERIC); } public function _conjunctionScore($docId, Zend_Search_Lucene_Interface $reader) { if ($this->_coord === null) { $this->_coord = $reader->getSimilarity()->coord(count($this->_terms), count($this->_terms) ); } $score = 0.0; foreach ($this->_terms as $termId => $term) { $score += $reader->getSimilarity()->tf($this->_termsFreqs[$termId][$docId]) * $this->_weights[$termId]->getValue() * $reader->norm($docId, $term->field); } return $score * $this->_coord * $this->getBoost(); } public function _nonConjunctionScore($docId, $reader) { if ($this->_coord === null) { $this->_coord = array(); $maxCoord = 0; foreach ($this->_signs as $sign) { if ($sign !== false ) { $maxCoord++; } } for ($count = 0; $count <= $maxCoord; $count++) { $this->_coord[$count] = $reader->getSimilarity()->coord($count, $maxCoord); } } $score = 0.0; $matchedTerms = 0; foreach ($this->_terms as $termId=>$term) { if ($this->_signs[$termId] !== false && isset($this->_termsFreqs[$termId][$docId]) ) { $matchedTerms++; $score += $reader->getSimilarity()->tf($this->_termsFreqs[$termId][$docId]) * $this->_weights[$termId]->getValue() * $reader->norm($docId, $term->field); } } return $score * $this->_coord[$matchedTerms] * $this->getBoost(); } public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null) { if ($this->_signs === null) { $this->_calculateConjunctionResult($reader); } else { $this->_calculateNonConjunctionResult($reader); } $this->_initWeight($reader); } public function matchedDocs() { return $this->_resVector; } public function score($docId, Zend_Search_Lucene_Interface $reader) { if (isset($this->_resVector[$docId])) { if ($this->_signs === null) { return $this->_conjunctionScore($docId, $reader); } else { return $this->_nonConjunctionScore($docId, $reader); } } else { return 0; } } public function getQueryTerms() { if ($this->_signs === null) { return $this->_terms; } $terms = array(); foreach ($this->_signs as $id => $sign) { if ($sign !== false) { $terms[] = $this->_terms[$id]; } } return $terms; } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { $words = array(); if ($this->_signs === null) { foreach ($this->_terms as $term) { $words[] = $term->text; } } else { foreach ($this->_signs as $id => $sign) { if ($sign !== false) { $words[] = $this->_terms[$id]->text; } } } $highlighter->highlight($words); } public function __toString() { $query = ''; foreach ($this->_terms as $id => $term) { if ($id != 0) { $query .= ' '; } if ($this->_signs === null || $this->_signs[$id] === true) { $query .= '+'; } else if ($this->_signs[$id] === false) { $query .= '-'; } if ($term->field !== null) { $query .= $term->field . ':'; } $query .= $term->text; } if ($this->getBoost() != 1) { $query = '(' . $query . ')^' . round($this->getBoost(), 4); } return $query; } } 
class Zend_Search_Lucene_Search_Weight_Boolean extends Zend_Search_Lucene_Search_Weight { private $_reader; private $_query; private $_weights; public function __construct(Zend_Search_Lucene_Search_Query $query, Zend_Search_Lucene_Interface $reader) { $this->_query = $query; $this->_reader = $reader; $this->_weights = array(); $signs = $query->getSigns(); foreach ($query->getSubqueries() as $num => $subquery) { if ($signs === null || $signs[$num] === null || $signs[$num]) { $this->_weights[$num] = $subquery->createWeight($reader); } } } public function getValue() { return $this->_query->getBoost(); } public function sumOfSquaredWeights() { $sum = 0; foreach ($this->_weights as $weight) { $sum += $weight->sumOfSquaredWeights(); } $sum *= $this->_query->getBoost() * $this->_query->getBoost(); if ($sum == 0) { $sum = 1.0; } return $sum; } public function normalize($queryNorm) { $queryNorm *= $this->_query->getBoost(); foreach ($this->_weights as $weight) { $weight->normalize($queryNorm); } } } 
class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_Query { private $_subqueries = array(); private $_signs = array(); private $_resVector = null; private $_coord = null; public function __construct($subqueries = null, $signs = null) { if (is_array($subqueries)) { $this->_subqueries = $subqueries; $this->_signs = null; if (is_array($signs)) { foreach ($signs as $sign ) { if ($sign !== true) { $this->_signs = $signs; break; } } } } } public function addSubquery(Zend_Search_Lucene_Search_Query $subquery, $sign=null) { if ($sign !== true || $this->_signs !== null) { if ($this->_signs === null) { $this->_signs = array(); foreach ($this->_subqueries as $prevSubquery) { $this->_signs[] = true; } } $this->_signs[] = $sign; } $this->_subqueries[] = $subquery; } public function rewrite(Zend_Search_Lucene_Interface $index) { $query = new Zend_Search_Lucene_Search_Query_Boolean(); $query->setBoost($this->getBoost()); foreach ($this->_subqueries as $subqueryId => $subquery) { $query->addSubquery($subquery->rewrite($index), ($this->_signs === null)? true : $this->_signs[$subqueryId]); } return $query; } public function optimize(Zend_Search_Lucene_Interface $index) { $subqueries = array(); $signs = array(); foreach ($this->_subqueries as $id => $subquery) { $subqueries[] = $subquery->optimize($index); $signs[] = ($this->_signs === null)? true : $this->_signs[$id]; } foreach ($subqueries as $id => $subquery) { if ($subquery instanceof Zend_Search_Lucene_Search_Query_Insignificant) { unset($subqueries[$id]); unset($signs[$id]); } } if (count($subqueries) == 0) {  return new Zend_Search_Lucene_Search_Query_Insignificant(); } $allProhibited = true; foreach ($signs as $sign) { if ($sign !== false) { $allProhibited = false; break; } } if ($allProhibited) {  return new Zend_Search_Lucene_Search_Query_Insignificant(); } foreach ($subqueries as $id => $subquery) { if ($subquery instanceof Zend_Search_Lucene_Search_Query_Empty) { if ($signs[$id] === true) {  return new Zend_Search_Lucene_Search_Query_Empty(); } else { unset($subqueries[$id]); unset($signs[$id]); } } } if (count($subqueries) == 0) {  return new Zend_Search_Lucene_Search_Query_Empty(); } $allProhibited = true; foreach ($signs as $sign) { if ($sign !== false) { $allProhibited = false; break; } } if ($allProhibited) {  return new Zend_Search_Lucene_Search_Query_Empty(); } if (count($subqueries) == 1) { if ($this->getBoost() == 1) { return reset($subqueries); } $optimizedQuery = clone reset($subqueries); $optimizedQuery->setBoost($optimizedQuery->getBoost()*$this->getBoost()); return $optimizedQuery; } $optimizedQuery = new Zend_Search_Lucene_Search_Query_Boolean($subqueries, $signs); $optimizedQuery->setBoost($this->getBoost()); $terms = array(); $tsigns = array(); $boostFactors = array(); foreach ($subqueries as $id => $subquery) { if ($subquery instanceof Zend_Search_Lucene_Search_Query_Term) { $terms[] = $subquery->getTerm(); $tsigns[] = $signs[$id]; $boostFactors[] = $subquery->getBoost(); unset($subqueries[$id]); unset($signs[$id]); } else if ($subquery instanceof Zend_Search_Lucene_Search_Query_MultiTerm) { $subTerms = $subquery->getTerms(); $subSigns = $subquery->getSigns(); if ($signs[$id] === true) { $hasRequired = false; $hasProhibited = false; if ($subSigns === null) { $hasRequired = true; } else { foreach ($subSigns as $sign) { if ($sign === true) { $hasRequired = true; } else if ($sign === false) { $hasProhibited = true; break; } } } if ($hasProhibited || !$hasRequired) { continue; } foreach ($subTerms as $termId => $term) { $terms[] = $term; $tsigns[] = ($subSigns === null)? true : $subSigns[$termId]; $boostFactors[] = $subquery->getBoost(); } unset($subqueries[$id]); unset($signs[$id]); } else { $onlyOptional = true; if ($subSigns === null) { $onlyOptional = false; } else { foreach ($subSigns as $sign) { if ($sign !== null) { $onlyOptional = false; break; } } } if (!$onlyOptional) { continue; } foreach ($subTerms as $termId => $term) { $terms[] = $term; $tsigns[] = ($signs[$id] === null)? null : false ; $boostFactors[] = $subquery->getBoost(); } unset($subqueries[$id]); unset($signs[$id]); } } } if (count($terms) == 0 ) { return $optimizedQuery; } if (count($subqueries) == 0 && count(array_unique($boostFactors)) == 1) {  $optimizedQuery = new Zend_Search_Lucene_Search_Query_MultiTerm($terms, $tsigns); $optimizedQuery->setBoost(reset($boostFactors)*$this->getBoost()); return $optimizedQuery; } $prohibitedTerms = array(); foreach ($terms as $id => $term) { if ($tsigns[$id] === false) { $prohibitedTerms[] = $term; unset($terms[$id]); unset($tsigns[$id]); unset($boostFactors[$id]); } } if (count($terms) == 1) {  $clause = new Zend_Search_Lucene_Search_Query_Term(reset($terms)); $clause->setBoost(reset($boostFactors)); $subqueries[] = $clause; $signs[] = reset($tsigns); $terms = array(); } else if (count($terms) > 1 && count(array_unique($boostFactors)) == 1) {  $clause = new Zend_Search_Lucene_Search_Query_MultiTerm($terms, $tsigns); $clause->setBoost(reset($boostFactors)); $subqueries[] = $clause; $signs[] = (in_array(true, $tsigns))? true : null; $terms = array(); } if (count($prohibitedTerms) == 1) {  $subqueries[] = new Zend_Search_Lucene_Search_Query_Term(reset($prohibitedTerms)); $signs[] = false; $prohibitedTerms = array(); } else if (count($prohibitedTerms) > 1) { $prohibitedSigns = array(); foreach ($prohibitedTerms as $id => $term) { $prohibitedSigns[$id] = null; }  $subqueries[] = new Zend_Search_Lucene_Search_Query_MultiTerm($prohibitedTerms, $prohibitedSigns); $signs[] = false; $prohibitedTerms = array(); } if (count($terms) == 0 && count($prohibitedTerms) == 0) { $optimizedQuery = new Zend_Search_Lucene_Search_Query_Boolean($subqueries, $signs); $optimizedQuery->setBoost($this->getBoost()); } return $optimizedQuery; } public function getSubqueries() { return $this->_subqueries; } public function getSigns() { return $this->_signs; } public function createWeight(Zend_Search_Lucene_Interface $reader) {  $this->_weight = new Zend_Search_Lucene_Search_Weight_Boolean($this, $reader); return $this->_weight; } private function _calculateConjunctionResult() { $this->_resVector = null; if (count($this->_subqueries) == 0) { $this->_resVector = array(); } $resVectors = array(); $resVectorsSizes = array(); $resVectorsIds = array(); foreach ($this->_subqueries as $subqueryId => $subquery) { $resVectors[] = $subquery->matchedDocs(); $resVectorsSizes[] = count(end($resVectors)); $resVectorsIds[] = $subqueryId; } array_multisort($resVectorsSizes, SORT_ASC, SORT_NUMERIC, $resVectorsIds, SORT_ASC, SORT_NUMERIC, $resVectors); foreach ($resVectors as $nextResVector) { if($this->_resVector === null) { $this->_resVector = $nextResVector; } else { $updatedVector = array(); foreach ($this->_resVector as $id => $value) { if (isset($nextResVector[$id])) { $updatedVector[$id] = $value; } } $this->_resVector = $updatedVector; } if (count($this->_resVector) == 0) { break; } } } private function _calculateNonConjunctionResult() { $requiredVectors = array(); $requiredVectorsSizes = array(); $requiredVectorsIds = array(); $optional = array(); foreach ($this->_subqueries as $subqueryId => $subquery) { if ($this->_signs[$subqueryId] === true) { $requiredVectors[] = $subquery->matchedDocs(); $requiredVectorsSizes[] = count(end($requiredVectors)); $requiredVectorsIds[] = $subqueryId; } elseif ($this->_signs[$subqueryId] === false) { } else { $optional += $subquery->matchedDocs(); } } array_multisort($requiredVectorsSizes, SORT_ASC, SORT_NUMERIC, $requiredVectorsIds, SORT_ASC, SORT_NUMERIC, $requiredVectors); $required = null; foreach ($requiredVectors as $nextResVector) { if($required === null) { $required = $nextResVector; } else { $updatedVector = array(); foreach ($required as $id => $value) { if (isset($nextResVector[$id])) { $updatedVector[$id] = $value; } } $required = $updatedVector; } if (count($required) == 0) { break; } } if ($required !== null) { $this->_resVector = &$required; } else { $this->_resVector = &$optional; } ksort($this->_resVector, SORT_NUMERIC); } public function _conjunctionScore($docId, Zend_Search_Lucene_Interface $reader) { if ($this->_coord === null) { $this->_coord = $reader->getSimilarity()->coord(count($this->_subqueries), count($this->_subqueries) ); } $score = 0; foreach ($this->_subqueries as $subquery) { $subscore = $subquery->score($docId, $reader); if ($subscore == 0) { return 0; } $score += $subquery->score($docId, $reader) * $this->_coord; } return $score * $this->_coord * $this->getBoost(); } public function _nonConjunctionScore($docId, Zend_Search_Lucene_Interface $reader) { if ($this->_coord === null) { $this->_coord = array(); $maxCoord = 0; foreach ($this->_signs as $sign) { if ($sign !== false ) { $maxCoord++; } } for ($count = 0; $count <= $maxCoord; $count++) { $this->_coord[$count] = $reader->getSimilarity()->coord($count, $maxCoord); } } $score = 0; $matchedSubqueries = 0; foreach ($this->_subqueries as $subqueryId => $subquery) { $subscore = $subquery->score($docId, $reader); if ($this->_signs[$subqueryId] === false && $subscore != 0) { return 0; } if ($this->_signs[$subqueryId] === true && $subscore == 0) { return 0; } if ($subscore != 0) { $matchedSubqueries++; $score += $subscore; } } return $score * $this->_coord[$matchedSubqueries] * $this->getBoost(); } public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null) { $this->_initWeight($reader); if ($docsFilter === null) {  $docsFilter = new Zend_Search_Lucene_Index_DocsFilter(); } foreach ($this->_subqueries as $subqueryId => $subquery) { if ($this->_signs == null || $this->_signs[$subqueryId] === true) { $subquery->execute($reader, $docsFilter); } else { $subquery->execute($reader); } } if ($this->_signs === null) { $this->_calculateConjunctionResult(); } else { $this->_calculateNonConjunctionResult(); } } public function matchedDocs() { return $this->_resVector; } public function score($docId, Zend_Search_Lucene_Interface $reader) { if (isset($this->_resVector[$docId])) { if ($this->_signs === null) { return $this->_conjunctionScore($docId, $reader); } else { return $this->_nonConjunctionScore($docId, $reader); } } else { return 0; } } public function getQueryTerms() { $terms = array(); foreach ($this->_subqueries as $id => $subquery) { if ($this->_signs === null || $this->_signs[$id] !== false) { $terms = array_merge($terms, $subquery->getQueryTerms()); } } return $terms; } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { foreach ($this->_subqueries as $id => $subquery) { if ($this->_signs === null || $this->_signs[$id] !== false) { $subquery->_highlightMatches($highlighter); } } } public function __toString() { $query = ''; foreach ($this->_subqueries as $id => $subquery) { if ($id != 0) { $query .= ' '; } if ($this->_signs === null || $this->_signs[$id] === true) { $query .= '+'; } else if ($this->_signs[$id] === false) { $query .= '-'; } $query .= '(' . $subquery->__toString() . ')'; } if ($this->getBoost() != 1) { $query = '(' . $query . ')^' . round($this->getBoost(), 4); } return $query; } } 
class Zend_Search_Lucene_Search_BooleanExpressionRecognizer extends Zend_Search_Lucene_FSM { const ST_START = 0; const ST_LITERAL = 1; const ST_NOT_OPERATOR = 2; const ST_AND_OPERATOR = 3; const ST_OR_OPERATOR = 4; const IN_LITERAL = 0; const IN_NOT_OPERATOR = 1; const IN_AND_OPERATOR = 2; const IN_OR_OPERATOR = 3; private $_negativeLiteral = false; private $_literal; private $_conjunctions = array(); private $_currentConjunction = array(); public function __construct() { parent::__construct( array(self::ST_START, self::ST_LITERAL, self::ST_NOT_OPERATOR, self::ST_AND_OPERATOR, self::ST_OR_OPERATOR), array(self::IN_LITERAL, self::IN_NOT_OPERATOR, self::IN_AND_OPERATOR, self::IN_OR_OPERATOR)); $emptyOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'emptyOperatorAction'); $emptyNotOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'emptyNotOperatorAction'); $this->addRules(array( array(self::ST_START, self::IN_LITERAL, self::ST_LITERAL), array(self::ST_START, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR), array(self::ST_LITERAL, self::IN_AND_OPERATOR, self::ST_AND_OPERATOR), array(self::ST_LITERAL, self::IN_OR_OPERATOR, self::ST_OR_OPERATOR), array(self::ST_LITERAL, self::IN_LITERAL, self::ST_LITERAL, $emptyOperatorAction), array(self::ST_LITERAL, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR, $emptyNotOperatorAction), array(self::ST_NOT_OPERATOR, self::IN_LITERAL, self::ST_LITERAL), array(self::ST_AND_OPERATOR, self::IN_LITERAL, self::ST_LITERAL), array(self::ST_AND_OPERATOR, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR), array(self::ST_OR_OPERATOR, self::IN_LITERAL, self::ST_LITERAL), array(self::ST_OR_OPERATOR, self::IN_NOT_OPERATOR, self::ST_NOT_OPERATOR), )); $notOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'notOperatorAction'); $orOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'orOperatorAction'); $literalAction = new Zend_Search_Lucene_FSMAction($this, 'literalAction'); $this->addEntryAction(self::ST_NOT_OPERATOR, $notOperatorAction); $this->addEntryAction(self::ST_OR_OPERATOR, $orOperatorAction); $this->addEntryAction(self::ST_LITERAL, $literalAction); } public function processOperator($operator) { $this->process($operator); } public function processLiteral($literal) { $this->_literal = $literal; $this->process(self::IN_LITERAL); } public function finishExpression() { if ($this->getState() != self::ST_LITERAL) {  throw new Zend_Search_Lucene_Exception('Literal expected.'); } $this->_conjunctions[] = $this->_currentConjunction; return $this->_conjunctions; } public function emptyOperatorAction() {  if (Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() == Zend_Search_Lucene_Search_QueryParser::B_AND) { } else { $this->orOperatorAction(); } $this->literalAction(); } public function emptyNotOperatorAction() {  if (Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() == Zend_Search_Lucene_Search_QueryParser::B_AND) { } else { $this->orOperatorAction(); } $this->notOperatorAction(); } public function notOperatorAction() { $this->_negativeLiteral = true; } public function orOperatorAction() { $this->_conjunctions[] = $this->_currentConjunction; $this->_currentConjunction = array(); } public function literalAction() { $this->_currentConjunction[] = array($this->_literal, !$this->_negativeLiteral); $this->_negativeLiteral = false; } } 
class Zend_Search_Lucene_Search_QueryParserContext { private $_defaultField; private $_nextEntryField = null; private $_nextEntrySign = null; const GM_SIGNS = 0; const GM_BOOLEAN = 1; private $_mode = null; private $_signs = array(); private $_entries = array(); private $_encoding; public function __construct($encoding, $defaultField = null) { $this->_encoding = $encoding; $this->_defaultField = $defaultField; } public function getField() { return ($this->_nextEntryField !== null) ? $this->_nextEntryField : $this->_defaultField; } public function setNextEntryField($field) { $this->_nextEntryField = $field; } public function setNextEntrySign($sign) { if ($this->_mode === self::GM_BOOLEAN) {  throw new Zend_Search_Lucene_Search_QueryParserException('It\'s not allowed to mix boolean and signs styles in the same subquery.'); } $this->_mode = self::GM_SIGNS; if ($sign == Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED) { $this->_nextEntrySign = true; } else if ($sign == Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED) { $this->_nextEntrySign = false; } else {  throw new Zend_Search_Lucene_Exception('Unrecognized sign type.'); } } public function addEntry(Zend_Search_Lucene_Search_QueryEntry $entry) { if ($this->_mode !== self::GM_BOOLEAN) { $this->_signs[] = $this->_nextEntrySign; } $this->_entries[] = $entry; $this->_nextEntryField = null; $this->_nextEntrySign = null; } public function processFuzzyProximityModifier($parameter = null) { if ($this->_nextEntryField !== null || $this->_nextEntrySign !== null) {  throw new Zend_Search_Lucene_Search_QueryParserException('\'~\' modifier must follow word or phrase.'); } $lastEntry = array_pop($this->_entries); if (!$lastEntry instanceof Zend_Search_Lucene_Search_QueryEntry) {  throw new Zend_Search_Lucene_Search_QueryParserException('\'~\' modifier must follow word or phrase.'); } $lastEntry->processFuzzyProximityModifier($parameter); $this->_entries[] = $lastEntry; } public function boost($boostFactor) { if ($this->_nextEntryField !== null || $this->_nextEntrySign !== null) {  throw new Zend_Search_Lucene_Search_QueryParserException('\'^\' modifier must follow word, phrase or subquery.'); } $lastEntry = array_pop($this->_entries); if (!$lastEntry instanceof Zend_Search_Lucene_Search_QueryEntry) {  throw new Zend_Search_Lucene_Search_QueryParserException('\'^\' modifier must follow word, phrase or subquery.'); } $lastEntry->boost($boostFactor); $this->_entries[] = $lastEntry; } public function addLogicalOperator($operator) { if ($this->_mode === self::GM_SIGNS) {  throw new Zend_Search_Lucene_Search_QueryParserException('It\'s not allowed to mix boolean and signs styles in the same subquery.'); } $this->_mode = self::GM_BOOLEAN; $this->_entries[] = $operator; } public function _signStyleExpressionQuery() {  $query = new Zend_Search_Lucene_Search_Query_Boolean();  if (Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() == Zend_Search_Lucene_Search_QueryParser::B_AND) { $defaultSign = true; } else { $defaultSign = null; } foreach ($this->_entries as $entryId => $entry) { $sign = ($this->_signs[$entryId] !== null) ? $this->_signs[$entryId] : $defaultSign; $query->addSubquery($entry->getQuery($this->_encoding), $sign); } return $query; } private function _booleanExpressionQuery() {  $expressionRecognizer = new Zend_Search_Lucene_Search_BooleanExpressionRecognizer();  try { foreach ($this->_entries as $entry) { if ($entry instanceof Zend_Search_Lucene_Search_QueryEntry) { $expressionRecognizer->processLiteral($entry); } else { switch ($entry) { case Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME: $expressionRecognizer->processOperator(Zend_Search_Lucene_Search_BooleanExpressionRecognizer::IN_AND_OPERATOR); break; case Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME: $expressionRecognizer->processOperator(Zend_Search_Lucene_Search_BooleanExpressionRecognizer::IN_OR_OPERATOR); break; case Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME: $expressionRecognizer->processOperator(Zend_Search_Lucene_Search_BooleanExpressionRecognizer::IN_NOT_OPERATOR); break; default: throw new Zend_Search_Lucene('Boolean expression error. Unknown operator type.'); } } } $conjuctions = $expressionRecognizer->finishExpression(); } catch (Zend_Search_Exception $e) {  throw new Zend_Search_Lucene_Search_QueryParserException('Boolean expression error.', 0, $e); } foreach ($conjuctions as $conjuctionId => $conjuction) { $nonNegativeEntryFound = false; foreach ($conjuction as $conjuctionEntry) { if ($conjuctionEntry[1]) { $nonNegativeEntryFound = true; break; } } if (!$nonNegativeEntryFound) { unset($conjuctions[$conjuctionId]); } } $subqueries = array(); foreach ($conjuctions as $conjuction) { if (count($conjuction) == 1) { $subqueries[] = $conjuction[0][0]->getQuery($this->_encoding); } else {  $subquery = new Zend_Search_Lucene_Search_Query_Boolean(); foreach ($conjuction as $conjuctionEntry) { $subquery->addSubquery($conjuctionEntry[0]->getQuery($this->_encoding), $conjuctionEntry[1]); } $subqueries[] = $subquery; } } if (count($subqueries) == 0) {  return new Zend_Search_Lucene_Search_Query_Insignificant(); } if (count($subqueries) == 1) { return $subqueries[0]; }  $query = new Zend_Search_Lucene_Search_Query_Boolean(); foreach ($subqueries as $subquery) { $query->addSubquery($subquery); } return $query; } public function getQuery() { if ($this->_mode === self::GM_BOOLEAN) { return $this->_booleanExpressionQuery(); } else { return $this->_signStyleExpressionQuery(); } } } 
abstract class Zend_Search_Lucene_Search_QueryEntry { protected $_boost = 1.0; abstract public function processFuzzyProximityModifier($parameter = null); abstract public function getQuery($encoding); public function boost($boostFactor) { $this->_boost *= $boostFactor; } } 
class Zend_Search_Lucene_Search_Query_Fuzzy extends Zend_Search_Lucene_Search_Query { const DEFAULT_MIN_SIMILARITY = 0.5; const MAX_CLAUSE_COUNT = 1024; private $_maxDistances = array(); private $_term; private $_minimumSimilarity; private $_prefixLength; private $_matches = null; private $_scores = null; private $_termKeys = null; private static $_defaultPrefixLength = 3; public function __construct(Zend_Search_Lucene_Index_Term $term, $minimumSimilarity = self::DEFAULT_MIN_SIMILARITY, $prefixLength = null) { if ($minimumSimilarity < 0) {  throw new Zend_Search_Lucene_Exception('minimumSimilarity cannot be less than 0'); } if ($minimumSimilarity >= 1) {  throw new Zend_Search_Lucene_Exception('minimumSimilarity cannot be greater than or equal to 1'); } if ($prefixLength < 0) {  throw new Zend_Search_Lucene_Exception('prefixLength cannot be less than 0'); } $this->_term = $term; $this->_minimumSimilarity = $minimumSimilarity; $this->_prefixLength = ($prefixLength !== null)? $prefixLength : self::$_defaultPrefixLength; } public static function getDefaultPrefixLength() { return self::$_defaultPrefixLength; } public static function setDefaultPrefixLength($defaultPrefixLength) { self::$_defaultPrefixLength = $defaultPrefixLength; } private function _calculateMaxDistance($prefixLength, $termLength, $length) { $this->_maxDistances[$length] = (int) ((1 - $this->_minimumSimilarity)*(min($termLength, $length) + $prefixLength)); return $this->_maxDistances[$length]; } public function rewrite(Zend_Search_Lucene_Interface $index) { $this->_matches = array(); $this->_scores = array(); $this->_termKeys = array(); if ($this->_term->field === null) { $fields = $index->getFieldNames(true ); } else { $fields = array($this->_term->field); }  $prefix = Zend_Search_Lucene_Index_Term::getPrefix($this->_term->text, $this->_prefixLength); $prefixByteLength = strlen($prefix); $prefixUtf8Length = Zend_Search_Lucene_Index_Term::getLength($prefix); $termLength = Zend_Search_Lucene_Index_Term::getLength($this->_term->text); $termRest = substr($this->_term->text, $prefixByteLength); $termRestLength = strlen($termRest); $scaleFactor = 1/(1 - $this->_minimumSimilarity);  $maxTerms = Zend_Search_Lucene::getTermsPerQueryLimit(); foreach ($fields as $field) { $index->resetTermsStream();  if ($prefix != '') { $index->skipTo(new Zend_Search_Lucene_Index_Term($prefix, $field)); while ($index->currentTerm() !== null && $index->currentTerm()->field == $field && substr($index->currentTerm()->text, 0, $prefixByteLength) == $prefix) { $target = substr($index->currentTerm()->text, $prefixByteLength); $maxDistance = isset($this->_maxDistances[strlen($target)])? $this->_maxDistances[strlen($target)] : $this->_calculateMaxDistance($prefixUtf8Length, $termRestLength, strlen($target)); if ($termRestLength == 0) { $similarity = (($prefixUtf8Length == 0)? 0 : 1 - strlen($target)/$prefixUtf8Length); } else if (strlen($target) == 0) { $similarity = (($prefixUtf8Length == 0)? 0 : 1 - $termRestLength/$prefixUtf8Length); } else if ($maxDistance < abs($termRestLength - strlen($target))){ $similarity = 0; } else { $similarity = 1 - levenshtein($termRest, $target)/($prefixUtf8Length + min($termRestLength, strlen($target))); } if ($similarity > $this->_minimumSimilarity) { $this->_matches[] = $index->currentTerm(); $this->_termKeys[] = $index->currentTerm()->key(); $this->_scores[] = ($similarity - $this->_minimumSimilarity)*$scaleFactor; if ($maxTerms != 0 && count($this->_matches) > $maxTerms) {  throw new Zend_Search_Lucene_Exception('Terms per query limit is reached.'); } } $index->nextTerm(); } } else { $index->skipTo(new Zend_Search_Lucene_Index_Term('', $field)); while ($index->currentTerm() !== null && $index->currentTerm()->field == $field) { $target = $index->currentTerm()->text; $maxDistance = isset($this->_maxDistances[strlen($target)])? $this->_maxDistances[strlen($target)] : $this->_calculateMaxDistance(0, $termRestLength, strlen($target)); if ($maxDistance < abs($termRestLength - strlen($target))){ $similarity = 0; } else { $similarity = 1 - levenshtein($termRest, $target)/min($termRestLength, strlen($target)); } if ($similarity > $this->_minimumSimilarity) { $this->_matches[] = $index->currentTerm(); $this->_termKeys[] = $index->currentTerm()->key(); $this->_scores[] = ($similarity - $this->_minimumSimilarity)*$scaleFactor; if ($maxTerms != 0 && count($this->_matches) > $maxTerms) {  throw new Zend_Search_Lucene_Exception('Terms per query limit is reached.'); } } $index->nextTerm(); } } $index->closeTermsStream(); } if (count($this->_matches) == 0) {  return new Zend_Search_Lucene_Search_Query_Empty(); } else if (count($this->_matches) == 1) {  return new Zend_Search_Lucene_Search_Query_Term(reset($this->_matches)); } else {  $rewrittenQuery = new Zend_Search_Lucene_Search_Query_Boolean(); array_multisort($this->_scores, SORT_DESC, SORT_NUMERIC, $this->_termKeys, SORT_ASC, SORT_STRING, $this->_matches); $termCount = 0;  foreach ($this->_matches as $id => $matchedTerm) { $subquery = new Zend_Search_Lucene_Search_Query_Term($matchedTerm); $subquery->setBoost($this->_scores[$id]); $rewrittenQuery->addSubquery($subquery); $termCount++; if ($termCount >= self::MAX_CLAUSE_COUNT) { break; } } return $rewrittenQuery; } } public function optimize(Zend_Search_Lucene_Interface $index) {  throw new Zend_Search_Lucene_Exception('Fuzzy query should not be directly used for search. Use $query->rewrite($index)'); } public function getQueryTerms() { if ($this->_matches === null) {  throw new Zend_Search_Lucene_Exception('Search or rewrite operations have to be performed before.'); } return $this->_matches; } public function createWeight(Zend_Search_Lucene_Interface $reader) {  throw new Zend_Search_Lucene_Exception('Fuzzy query should not be directly used for search. Use $query->rewrite($index)'); } public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null) {  throw new Zend_Search_Lucene_Exception('Fuzzy query should not be directly used for search. Use $query->rewrite($index)'); } public function matchedDocs() {  throw new Zend_Search_Lucene_Exception('Fuzzy query should not be directly used for search. Use $query->rewrite($index)'); } public function score($docId, Zend_Search_Lucene_Interface $reader) {  throw new Zend_Search_Lucene_Exception('Fuzzy query should not be directly used for search. Use $query->rewrite($index)'); } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { $words = array();  $prefix = Zend_Search_Lucene_Index_Term::getPrefix($this->_term->text, $this->_prefixLength); $prefixByteLength = strlen($prefix); $prefixUtf8Length = Zend_Search_Lucene_Index_Term::getLength($prefix); $termLength = Zend_Search_Lucene_Index_Term::getLength($this->_term->text); $termRest = substr($this->_term->text, $prefixByteLength); $termRestLength = strlen($termRest); $scaleFactor = 1/(1 - $this->_minimumSimilarity); $docBody = $highlighter->getDocument()->getFieldUtf8Value('body');  $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($docBody, 'UTF-8'); foreach ($tokens as $token) { $termText = $token->getTermText(); if (substr($termText, 0, $prefixByteLength) == $prefix) { $target = substr($termText, $prefixByteLength); $maxDistance = isset($this->_maxDistances[strlen($target)])? $this->_maxDistances[strlen($target)] : $this->_calculateMaxDistance($prefixUtf8Length, $termRestLength, strlen($target)); if ($termRestLength == 0) { $similarity = (($prefixUtf8Length == 0)? 0 : 1 - strlen($target)/$prefixUtf8Length); } else if (strlen($target) == 0) { $similarity = (($prefixUtf8Length == 0)? 0 : 1 - $termRestLength/$prefixUtf8Length); } else if ($maxDistance < abs($termRestLength - strlen($target))){ $similarity = 0; } else { $similarity = 1 - levenshtein($termRest, $target)/($prefixUtf8Length + min($termRestLength, strlen($target))); } if ($similarity > $this->_minimumSimilarity) { $words[] = $termText; } } } $highlighter->highlight($words); } public function __toString() { return (($this->_term->field === null)? '' : $this->_term->field . ':') . $this->_term->text . '~' . (($this->_minimumSimilarity != self::DEFAULT_MIN_SIMILARITY)? round($this->_minimumSimilarity, 4) : '') . (($this->getBoost() != 1)? '^' . round($this->getBoost(), 4) : ''); } } 
abstract class Zend_Search_Lucene_Search_Query_Preprocessing extends Zend_Search_Lucene_Search_Query { protected $_matches = null; public function optimize(Zend_Search_Lucene_Interface $index) {  throw new Zend_Search_Lucene_Exception('This query is not intended to be executed.'); } public function createWeight(Zend_Search_Lucene_Interface $reader) {  throw new Zend_Search_Lucene_Exception('This query is not intended to be executed.'); } public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null) {  throw new Zend_Search_Lucene_Exception('This query is not intended to be executed.'); } public function matchedDocs() {  throw new Zend_Search_Lucene_Exception('This query is not intended to be executed.'); } public function score($docId, Zend_Search_Lucene_Interface $reader) {  throw new Zend_Search_Lucene_Exception('This query is not intended to be executed.'); } public function getQueryTerms() {  throw new Zend_Search_Lucene_Exception('Rewrite operation has to be done before retrieving query terms.'); } } 
class Zend_Search_Lucene_Search_Query_Preprocessing_Fuzzy extends Zend_Search_Lucene_Search_Query_Preprocessing { private $_word; private $_encoding; private $_field; private $_minimumSimilarity; public function __construct($word, $encoding, $fieldName, $minimumSimilarity) { $this->_word = $word; $this->_encoding = $encoding; $this->_field = $fieldName; $this->_minimumSimilarity = $minimumSimilarity; } public function rewrite(Zend_Search_Lucene_Interface $index) { if ($this->_field === null) {  $query = new Zend_Search_Lucene_Search_Query_Boolean(); $hasInsignificantSubqueries = false;  if (Zend_Search_Lucene::getDefaultSearchField() === null) { $searchFields = $index->getFieldNames(true); } else { $searchFields = array(Zend_Search_Lucene::getDefaultSearchField()); }  foreach ($searchFields as $fieldName) { $subquery = new Zend_Search_Lucene_Search_Query_Preprocessing_Fuzzy($this->_word, $this->_encoding, $fieldName, $this->_minimumSimilarity); $rewrittenSubquery = $subquery->rewrite($index); if ( !($rewrittenSubquery instanceof Zend_Search_Lucene_Search_Query_Insignificant || $rewrittenSubquery instanceof Zend_Search_Lucene_Search_Query_Empty) ) { $query->addSubquery($rewrittenSubquery); } if ($rewrittenSubquery instanceof Zend_Search_Lucene_Search_Query_Insignificant) { $hasInsignificantSubqueries = true; } } $subqueries = $query->getSubqueries(); if (count($subqueries) == 0) { $this->_matches = array(); if ($hasInsignificantSubqueries) {  return new Zend_Search_Lucene_Search_Query_Insignificant(); } else {  return new Zend_Search_Lucene_Search_Query_Empty(); } } if (count($subqueries) == 1) { $query = reset($subqueries); } $query->setBoost($this->getBoost()); $this->_matches = $query->getQueryTerms(); return $query; }  $term = new Zend_Search_Lucene_Index_Term($this->_word, $this->_field); if ($index->hasTerm($term)) {  $query = new Zend_Search_Lucene_Search_Query_Fuzzy($term, $this->_minimumSimilarity); $query->setBoost($this->getBoost()); $rewrittenQuery = $query->rewrite($index); $this->_matches = $query->getQueryTerms(); return $rewrittenQuery; } if (@preg_match('/\pL/u', 'a') == 1) { $subPatterns = preg_split('/[*?]/u', iconv($this->_encoding, 'UTF-8', $this->_word)); } else { $subPatterns = preg_split('/[*?]/', $this->_word); } if (count($subPatterns) > 1) {  throw new Zend_Search_Lucene_Search_QueryParserException('Fuzzy search doesn\'t support wildcards (except within Keyword fields).'); }  $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_word, $this->_encoding); if (count($tokens) == 0) { $this->_matches = array();  return new Zend_Search_Lucene_Search_Query_Insignificant(); } if (count($tokens) == 1) {  $term = new Zend_Search_Lucene_Index_Term($tokens[0]->getTermText(), $this->_field);  $query = new Zend_Search_Lucene_Search_Query_Fuzzy($term, $this->_minimumSimilarity); $query->setBoost($this->getBoost()); $rewrittenQuery = $query->rewrite($index); $this->_matches = $query->getQueryTerms(); return $rewrittenQuery; }  throw new Zend_Search_Lucene_Search_QueryParserException('Fuzzy search is supported only for non-multiple word terms'); } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { if (@preg_match('/\pL/u', 'a') == 1) { $subPatterns = preg_split('/[*?]/u', iconv($this->_encoding, 'UTF-8', $this->_word)); } else { $subPatterns = preg_split('/[*?]/', $this->_word); } if (count($subPatterns) > 1) { return; }  $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_word, $this->_encoding); if (count($tokens) == 0) { return; } if (count($tokens) == 1) {  $term = new Zend_Search_Lucene_Index_Term($tokens[0]->getTermText(), $this->_field);  $query = new Zend_Search_Lucene_Search_Query_Fuzzy($term, $this->_minimumSimilarity); $query->_highlightMatches($highlighter); return; } } public function __toString() { if ($this->_field !== null) { $query = $this->_field . ':'; } else { $query = ''; } $query .= $this->_word; if ($this->getBoost() != 1) { $query .= '^' . round($this->getBoost(), 4); } return $query; } } 
class Zend_Search_Lucene_Search_Query_Wildcard extends Zend_Search_Lucene_Search_Query { private $_pattern; private $_matches = null; private static $_minPrefixLength = 3; public function __construct(Zend_Search_Lucene_Index_Term $pattern) { $this->_pattern = $pattern; } public static function getMinPrefixLength() { return self::$_minPrefixLength; } public static function setMinPrefixLength($minPrefixLength) { self::$_minPrefixLength = $minPrefixLength; } private static function _getPrefix($word) { $questionMarkPosition = strpos($word, '?'); $astrericPosition = strpos($word, '*'); if ($questionMarkPosition !== false) { if ($astrericPosition !== false) { return substr($word, 0, min($questionMarkPosition, $astrericPosition)); } return substr($word, 0, $questionMarkPosition); } else if ($astrericPosition !== false) { return substr($word, 0, $astrericPosition); } return $word; } public function rewrite(Zend_Search_Lucene_Interface $index) { $this->_matches = array(); if ($this->_pattern->field === null) { $fields = $index->getFieldNames(true ); } else { $fields = array($this->_pattern->field); } $prefix = self::_getPrefix($this->_pattern->text); $prefixLength = strlen($prefix); $matchExpression = '/^' . str_replace(array('\\?', '\\*'), array('.', '.*') , preg_quote($this->_pattern->text, '/')) . '$/'; if ($prefixLength < self::$_minPrefixLength) {  throw new Zend_Search_Lucene_Exception('At least ' . self::$_minPrefixLength . ' non-wildcard characters are required at the beginning of pattern.'); } if (@preg_match('/\pL/u', 'a') == 1) { $matchExpression .= 'u'; } $maxTerms = Zend_Search_Lucene::getTermsPerQueryLimit(); foreach ($fields as $field) { $index->resetTermsStream();  if ($prefix != '') { $index->skipTo(new Zend_Search_Lucene_Index_Term($prefix, $field)); while ($index->currentTerm() !== null && $index->currentTerm()->field == $field && substr($index->currentTerm()->text, 0, $prefixLength) == $prefix) { if (preg_match($matchExpression, $index->currentTerm()->text) === 1) { $this->_matches[] = $index->currentTerm(); if ($maxTerms != 0 && count($this->_matches) > $maxTerms) {  throw new Zend_Search_Lucene_Exception('Terms per query limit is reached.'); } } $index->nextTerm(); } } else { $index->skipTo(new Zend_Search_Lucene_Index_Term('', $field)); while ($index->currentTerm() !== null && $index->currentTerm()->field == $field) { if (preg_match($matchExpression, $index->currentTerm()->text) === 1) { $this->_matches[] = $index->currentTerm(); if ($maxTerms != 0 && count($this->_matches) > $maxTerms) {  throw new Zend_Search_Lucene_Exception('Terms per query limit is reached.'); } } $index->nextTerm(); } } $index->closeTermsStream(); } if (count($this->_matches) == 0) {  return new Zend_Search_Lucene_Search_Query_Empty(); } else if (count($this->_matches) == 1) {  return new Zend_Search_Lucene_Search_Query_Term(reset($this->_matches)); } else {  $rewrittenQuery = new Zend_Search_Lucene_Search_Query_MultiTerm(); foreach ($this->_matches as $matchedTerm) { $rewrittenQuery->addTerm($matchedTerm); } return $rewrittenQuery; } } public function optimize(Zend_Search_Lucene_Interface $index) {  throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); } public function getPattern() { return $this->_pattern; } public function getQueryTerms() { if ($this->_matches === null) {  throw new Zend_Search_Lucene_Exception('Search has to be performed first to get matched terms'); } return $this->_matches; } public function createWeight(Zend_Search_Lucene_Interface $reader) {  throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); } public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null) {  throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); } public function matchedDocs() {  throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); } public function score($docId, Zend_Search_Lucene_Interface $reader) {  throw new Zend_Search_Lucene_Exception('Wildcard query should not be directly used for search. Use $query->rewrite($index)'); } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { $words = array(); $matchExpression = '/^' . str_replace(array('\\?', '\\*'), array('.', '.*') , preg_quote($this->_pattern->text, '/')) . '$/'; if (@preg_match('/\pL/u', 'a') == 1) { $matchExpression .= 'u'; } $docBody = $highlighter->getDocument()->getFieldUtf8Value('body');  $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($docBody, 'UTF-8'); foreach ($tokens as $token) { if (preg_match($matchExpression, $token->getTermText()) === 1) { $words[] = $token->getTermText(); } } $highlighter->highlight($words); } public function __toString() { if ($this->_pattern->field !== null) { $query = $this->_pattern->field . ':'; } else { $query = ''; } $query .= $this->_pattern->text; if ($this->getBoost() != 1) { $query = $query . '^' . round($this->getBoost(), 4); } return $query; } } 
class Zend_Search_Lucene_Search_Query_Preprocessing_Term extends Zend_Search_Lucene_Search_Query_Preprocessing { private $_word; private $_encoding; private $_field; public function __construct($word, $encoding, $fieldName) { $this->_word = $word; $this->_encoding = $encoding; $this->_field = $fieldName; } public function rewrite(Zend_Search_Lucene_Interface $index) { if ($this->_field === null) {  $query = new Zend_Search_Lucene_Search_Query_MultiTerm(); $query->setBoost($this->getBoost()); $hasInsignificantSubqueries = false;  if (Zend_Search_Lucene::getDefaultSearchField() === null) { $searchFields = $index->getFieldNames(true); } else { $searchFields = array(Zend_Search_Lucene::getDefaultSearchField()); }  foreach ($searchFields as $fieldName) { $subquery = new Zend_Search_Lucene_Search_Query_Preprocessing_Term($this->_word, $this->_encoding, $fieldName); $rewrittenSubquery = $subquery->rewrite($index); foreach ($rewrittenSubquery->getQueryTerms() as $term) { $query->addTerm($term); } if ($rewrittenSubquery instanceof Zend_Search_Lucene_Search_Query_Insignificant) { $hasInsignificantSubqueries = true; } } if (count($query->getTerms()) == 0) { $this->_matches = array(); if ($hasInsignificantSubqueries) {  return new Zend_Search_Lucene_Search_Query_Insignificant(); } else {  return new Zend_Search_Lucene_Search_Query_Empty(); } } $this->_matches = $query->getQueryTerms(); return $query; }  $term = new Zend_Search_Lucene_Index_Term($this->_word, $this->_field); if ($index->hasTerm($term)) {  $query = new Zend_Search_Lucene_Search_Query_Term($term); $query->setBoost($this->getBoost()); $this->_matches = $query->getQueryTerms(); return $query; } if (@preg_match('/\pL/u', 'a') == 1) { $word = iconv($this->_encoding, 'UTF-8', $this->_word); $wildcardsPattern = '/[*?]/u'; $subPatternsEncoding = 'UTF-8'; } else { $word = $this->_word; $wildcardsPattern = '/[*?]/'; $subPatternsEncoding = $this->_encoding; } $subPatterns = preg_split($wildcardsPattern, $word, -1, PREG_SPLIT_OFFSET_CAPTURE); if (count($subPatterns) > 1) { $pattern = '';  foreach ($subPatterns as $id => $subPattern) { if ($id != 0) { $pattern .= $word[ $subPattern[1] - 1 ]; } $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($subPattern[0], $subPatternsEncoding); if (count($tokens) > 1) {  throw new Zend_Search_Lucene_Search_QueryParserException('Wildcard search is supported only for non-multiple word terms'); } foreach ($tokens as $token) { $pattern .= $token->getTermText(); } }  $term = new Zend_Search_Lucene_Index_Term($pattern, $this->_field);  $query = new Zend_Search_Lucene_Search_Query_Wildcard($term); $query->setBoost($this->getBoost()); $rewrittenQuery = $query->rewrite($index); $this->_matches = $query->getQueryTerms(); return $rewrittenQuery; }  $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_word, $this->_encoding); if (count($tokens) == 0) { $this->_matches = array();  return new Zend_Search_Lucene_Search_Query_Insignificant(); } if (count($tokens) == 1) {  $term = new Zend_Search_Lucene_Index_Term($tokens[0]->getTermText(), $this->_field);  $query = new Zend_Search_Lucene_Search_Query_Term($term); $query->setBoost($this->getBoost()); $this->_matches = $query->getQueryTerms(); return $query; }  $query = new Zend_Search_Lucene_Search_Query_MultiTerm();  foreach ($tokens as $token) { $term = new Zend_Search_Lucene_Index_Term($token->getTermText(), $this->_field); $query->addTerm($term, true); } $query->setBoost($this->getBoost()); $this->_matches = $query->getQueryTerms(); return $query; } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { if (@preg_match('/\pL/u', 'a') == 1) { $word = iconv($this->_encoding, 'UTF-8', $this->_word); $wildcardsPattern = '/[*?]/u'; $subPatternsEncoding = 'UTF-8'; } else { $word = $this->_word; $wildcardsPattern = '/[*?]/'; $subPatternsEncoding = $this->_encoding; } $subPatterns = preg_split($wildcardsPattern, $word, -1, PREG_SPLIT_OFFSET_CAPTURE); if (count($subPatterns) > 1) { $pattern = '';  foreach ($subPatterns as $id => $subPattern) { if ($id != 0) { $pattern .= $word[ $subPattern[1] - 1 ]; } $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($subPattern[0], $subPatternsEncoding); if (count($tokens) > 1) { return; } foreach ($tokens as $token) { $pattern .= $token->getTermText(); } }  $term = new Zend_Search_Lucene_Index_Term($pattern, $this->_field);  $query = new Zend_Search_Lucene_Search_Query_Wildcard($term); $query->_highlightMatches($highlighter); return; }  $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_word, $this->_encoding); if (count($tokens) == 0) { return; } if (count($tokens) == 1) { $highlighter->highlight($tokens[0]->getTermText()); return; } $words = array(); foreach ($tokens as $token) { $words[] = $token->getTermText(); } $highlighter->highlight($words); } public function __toString() { if ($this->_field !== null) { $query = $this->_field . ':'; } else { $query = ''; } $query .= $this->_word; if ($this->getBoost() != 1) { $query .= '^' . round($this->getBoost(), 4); } return $query; } } 
class Zend_Search_Lucene_Search_QueryEntry_Term extends Zend_Search_Lucene_Search_QueryEntry { private $_term; private $_field; private $_fuzzyQuery = false; private $_similarity = 1.; public function __construct($term, $field) { $this->_term = $term; $this->_field = $field; } public function processFuzzyProximityModifier($parameter = null) { $this->_fuzzyQuery = true; if ($parameter !== null) { $this->_similarity = $parameter; } else {  $this->_similarity = Zend_Search_Lucene_Search_Query_Fuzzy::DEFAULT_MIN_SIMILARITY; } } public function getQuery($encoding) { if ($this->_fuzzyQuery) {  $query = new Zend_Search_Lucene_Search_Query_Preprocessing_Fuzzy($this->_term, $encoding, ($this->_field !== null)? iconv($encoding, 'UTF-8', $this->_field) : null, $this->_similarity ); $query->setBoost($this->_boost); return $query; }  $query = new Zend_Search_Lucene_Search_Query_Preprocessing_Term($this->_term, $encoding, ($this->_field !== null)? iconv($encoding, 'UTF-8', $this->_field) : null ); $query->setBoost($this->_boost); return $query; } } 
class Zend_Search_Lucene_Search_Weight_Phrase extends Zend_Search_Lucene_Search_Weight { private $_reader; private $_query; private $_idf; public function __construct(Zend_Search_Lucene_Search_Query_Phrase $query, Zend_Search_Lucene_Interface $reader) { $this->_query = $query; $this->_reader = $reader; } public function sumOfSquaredWeights() { $this->_idf = $this->_reader->getSimilarity()->idf($this->_query->getTerms(), $this->_reader); $this->_queryWeight = $this->_idf * $this->_query->getBoost(); return $this->_queryWeight * $this->_queryWeight; } public function normalize($queryNorm) { $this->_queryNorm = $queryNorm; $this->_queryWeight *= $queryNorm; $this->_value = $this->_queryWeight * $this->_idf; } } 
class Zend_Search_Lucene_Search_Query_Phrase extends Zend_Search_Lucene_Search_Query { private $_terms; private $_offsets; private $_slop; private $_resVector = null; private $_termsPositions = array(); public function __construct($terms = null, $offsets = null, $field = null) { $this->_slop = 0; if (is_array($terms)) { $this->_terms = array();  foreach ($terms as $termId => $termText) { $this->_terms[$termId] = ($field !== null)? new Zend_Search_Lucene_Index_Term($termText, $field): new Zend_Search_Lucene_Index_Term($termText); } } else if ($terms === null) { $this->_terms = array(); } else {  throw new Zend_Search_Lucene_Exception('terms argument must be array of strings or null'); } if (is_array($offsets)) { if (count($this->_terms) != count($offsets)) {  throw new Zend_Search_Lucene_Exception('terms and offsets arguments must have the same size.'); } $this->_offsets = $offsets; } else if ($offsets === null) { $this->_offsets = array(); foreach ($this->_terms as $termId => $term) { $position = count($this->_offsets); $this->_offsets[$termId] = $position; } } else {  throw new Zend_Search_Lucene_Exception('offsets argument must be array of strings or null'); } } public function setSlop($slop) { $this->_slop = $slop; } public function getSlop() { return $this->_slop; } public function addTerm(Zend_Search_Lucene_Index_Term $term, $position = null) { if ((count($this->_terms) != 0)&&(end($this->_terms)->field != $term->field)) {  throw new Zend_Search_Lucene_Exception('All phrase terms must be in the same field: ' . $term->field . ':' . $term->text); } $this->_terms[] = $term; if ($position !== null) { $this->_offsets[] = $position; } else if (count($this->_offsets) != 0) { $this->_offsets[] = end($this->_offsets) + 1; } else { $this->_offsets[] = 0; } } public function rewrite(Zend_Search_Lucene_Interface $index) { if (count($this->_terms) == 0) {  return new Zend_Search_Lucene_Search_Query_Empty(); } else if ($this->_terms[0]->field !== null) { return $this; } else {  $query = new Zend_Search_Lucene_Search_Query_Boolean(); $query->setBoost($this->getBoost()); foreach ($index->getFieldNames(true) as $fieldName) { $subquery = new Zend_Search_Lucene_Search_Query_Phrase(); $subquery->setSlop($this->getSlop());  foreach ($this->_terms as $termId => $term) { $qualifiedTerm = new Zend_Search_Lucene_Index_Term($term->text, $fieldName); $subquery->addTerm($qualifiedTerm, $this->_offsets[$termId]); } $query->addSubquery($subquery); } return $query; } } public function optimize(Zend_Search_Lucene_Interface $index) { foreach ($this->_terms as $term) { if (!$index->hasTerm($term)) {  return new Zend_Search_Lucene_Search_Query_Empty(); } } if (count($this->_terms) == 1) {  $optimizedQuery = new Zend_Search_Lucene_Search_Query_Term(reset($this->_terms)); $optimizedQuery->setBoost($this->getBoost()); return $optimizedQuery; } if (count($this->_terms) == 0) {  return new Zend_Search_Lucene_Search_Query_Empty(); } return $this; } public function getTerms() { return $this->_terms; } public function setWeight($num, $weight) { $this->_weights[$num] = $weight; } public function createWeight(Zend_Search_Lucene_Interface $reader) {  $this->_weight = new Zend_Search_Lucene_Search_Weight_Phrase($this, $reader); return $this->_weight; } public function _exactPhraseFreq($docId) { $freq = 0; $lowCardTermId = null; foreach ($this->_terms as $termId => $term) { if ($lowCardTermId === null || count($this->_termsPositions[$termId][$docId]) < count($this->_termsPositions[$lowCardTermId][$docId]) ) { $lowCardTermId = $termId; } } foreach ($this->_termsPositions[$lowCardTermId][$docId] as $lowCardPos) { $freq++; foreach ($this->_terms as $termId => $term) { if ($termId != $lowCardTermId) { $expectedPosition = $lowCardPos + ($this->_offsets[$termId] - $this->_offsets[$lowCardTermId]); if (!in_array($expectedPosition, $this->_termsPositions[$termId][$docId])) { $freq--; break; } } } } return $freq; } public function _sloppyPhraseFreq($docId, Zend_Search_Lucene_Interface $reader) { $freq = 0; $phraseQueue = array(); $phraseQueue[0] = array(); $lastTerm = null; foreach ($this->_terms as $termId => $term) { $queueSize = count($phraseQueue); $firstPass = true; foreach ($this->_termsPositions[$termId][$docId] as $termPosition ) { if ($firstPass) { for ($count = 0; $count < $queueSize; $count++) { $phraseQueue[$count][$termId] = $termPosition; } } else { for ($count = 0; $count < $queueSize; $count++) { if ($lastTerm !== null && abs( $termPosition - $phraseQueue[$count][$lastTerm] - ($this->_offsets[$termId] - $this->_offsets[$lastTerm])) > $this->_slop) { continue; } $newPhraseId = count($phraseQueue); $phraseQueue[$newPhraseId] = $phraseQueue[$count]; $phraseQueue[$newPhraseId][$termId] = $termPosition; } } $firstPass = false; } $lastTerm = $termId; } foreach ($phraseQueue as $phrasePos) { $minDistance = null; for ($shift = -$this->_slop; $shift <= $this->_slop; $shift++) { $distance = 0; $start = reset($phrasePos) - reset($this->_offsets) + $shift; foreach ($this->_terms as $termId => $term) { $distance += abs($phrasePos[$termId] - $this->_offsets[$termId] - $start); if($distance > $this->_slop) { break; } } if ($minDistance === null || $distance < $minDistance) { $minDistance = $distance; } } if ($minDistance <= $this->_slop) { $freq += $reader->getSimilarity()->sloppyFreq($minDistance); } } return $freq; } public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null) { $this->_resVector = null; if (count($this->_terms) == 0) { $this->_resVector = array(); } $resVectors = array(); $resVectorsSizes = array(); $resVectorsIds = array(); foreach ($this->_terms as $termId => $term) { $resVectors[] = array_flip($reader->termDocs($term)); $resVectorsSizes[] = count(end($resVectors)); $resVectorsIds[] = $termId; $this->_termsPositions[$termId] = $reader->termPositions($term); } array_multisort($resVectorsSizes, SORT_ASC, SORT_NUMERIC, $resVectorsIds, SORT_ASC, SORT_NUMERIC, $resVectors); foreach ($resVectors as $nextResVector) { if($this->_resVector === null) { $this->_resVector = $nextResVector; } else { $updatedVector = array(); foreach ($this->_resVector as $id => $value) { if (isset($nextResVector[$id])) { $updatedVector[$id] = $value; } } $this->_resVector = $updatedVector; } if (count($this->_resVector) == 0) { break; } } $this->_initWeight($reader); } public function matchedDocs() { return $this->_resVector; } public function score($docId, Zend_Search_Lucene_Interface $reader) { if (isset($this->_resVector[$docId])) { if ($this->_slop == 0) { $freq = $this->_exactPhraseFreq($docId); } else { $freq = $this->_sloppyPhraseFreq($docId, $reader); } if ($freq != 0) { $tf = $reader->getSimilarity()->tf($freq); $weight = $this->_weight->getValue(); $norm = $reader->norm($docId, reset($this->_terms)->field); return $tf * $weight * $norm * $this->getBoost(); } return 0; } else { return 0; } } public function getQueryTerms() { return $this->_terms; } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { $words = array(); foreach ($this->_terms as $term) { $words[] = $term->text; } $highlighter->highlight($words); } public function __toString() { if (isset($this->_terms[0]) && $this->_terms[0]->field !== null) { $query = $this->_terms[0]->field . ':'; } else { $query = ''; } $query .= '"'; foreach ($this->_terms as $id => $term) { if ($id != 0) { $query .= ' '; } $query .= $term->text; } $query .= '"'; if ($this->_slop != 0) { $query .= '~' . $this->_slop; } if ($this->getBoost() != 1) { $query .= '^' . round($this->getBoost(), 4); } return $query; } } 
class Zend_Search_Lucene_Search_Query_Preprocessing_Phrase extends Zend_Search_Lucene_Search_Query_Preprocessing { private $_phrase; private $_phraseEncoding; private $_field; private $_slop; public function __construct($phrase, $phraseEncoding, $fieldName) { $this->_phrase = $phrase; $this->_phraseEncoding = $phraseEncoding; $this->_field = $fieldName; } public function setSlop($slop) { $this->_slop = $slop; } public function getSlop() { return $this->_slop; } public function rewrite(Zend_Search_Lucene_Interface $index) { if ($this->_field === null) {  $query = new Zend_Search_Lucene_Search_Query_Boolean(); $query->setBoost($this->getBoost());  if (Zend_Search_Lucene::getDefaultSearchField() === null) { $searchFields = $index->getFieldNames(true); } else { $searchFields = array(Zend_Search_Lucene::getDefaultSearchField()); } foreach ($searchFields as $fieldName) { $subquery = new Zend_Search_Lucene_Search_Query_Preprocessing_Phrase($this->_phrase, $this->_phraseEncoding, $fieldName); $subquery->setSlop($this->getSlop()); $query->addSubquery($subquery->rewrite($index)); } $this->_matches = $query->getQueryTerms(); return $query; }  $term = new Zend_Search_Lucene_Index_Term($this->_phrase, $this->_field); if ($index->hasTerm($term)) {  $query = new Zend_Search_Lucene_Search_Query_Term($term); $query->setBoost($this->getBoost()); $this->_matches = $query->getQueryTerms(); return $query; }  $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_phrase, $this->_phraseEncoding); if (count($tokens) == 0) { $this->_matches = array();  return new Zend_Search_Lucene_Search_Query_Insignificant(); } if (count($tokens) == 1) {  $term = new Zend_Search_Lucene_Index_Term($tokens[0]->getTermText(), $this->_field);  $query = new Zend_Search_Lucene_Search_Query_Term($term); $query->setBoost($this->getBoost()); $this->_matches = $query->getQueryTerms(); return $query; } $position = -1;  $query = new Zend_Search_Lucene_Search_Query_Phrase();  foreach ($tokens as $token) { $position += $token->getPositionIncrement(); $term = new Zend_Search_Lucene_Index_Term($token->getTermText(), $this->_field); $query->addTerm($term, $position); $query->setSlop($this->getSlop()); } $this->_matches = $query->getQueryTerms(); return $query; } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) {  $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_phrase, $this->_phraseEncoding); if (count($tokens) == 0) { return; } if (count($tokens) == 1) { $highlighter->highlight($tokens[0]->getTermText()); return; } $words = array(); foreach ($tokens as $token) { $words[] = $token->getTermText(); } $highlighter->highlight($words); } public function __toString() { if ($this->_field !== null) { $query = $this->_field . ':'; } else { $query = ''; } $query .= '"' . $this->_phrase . '"'; if ($this->_slop != 0) { $query .= '~' . $this->_slop; } if ($this->getBoost() != 1) { $query .= '^' . round($this->getBoost(), 4); } return $query; } } 
class Zend_Search_Lucene_Search_QueryEntry_Phrase extends Zend_Search_Lucene_Search_QueryEntry { private $_phrase; private $_field; private $_proximityQuery = false; private $_wordsDistance = 0; public function __construct($phrase, $field) { $this->_phrase = $phrase; $this->_field = $field; } public function processFuzzyProximityModifier($parameter = null) { $this->_proximityQuery = true; if ($parameter !== null) { $this->_wordsDistance = $parameter; } } public function getQuery($encoding) {  $query = new Zend_Search_Lucene_Search_Query_Preprocessing_Phrase($this->_phrase, $encoding, ($this->_field !== null)? iconv($encoding, 'UTF-8', $this->_field) : null); if ($this->_proximityQuery) { $query->setSlop($this->_wordsDistance); } $query->setBoost($this->_boost); return $query; } } 
class Zend_Search_Lucene_Search_QueryEntry_Subquery extends Zend_Search_Lucene_Search_QueryEntry { private $_query; public function __construct(Zend_Search_Lucene_Search_Query $query) { $this->_query = $query; } public function processFuzzyProximityModifier($parameter = null) {  throw new Zend_Search_Lucene_Search_QueryParserException('\'~\' sign must follow term or phrase'); } public function getQuery($encoding) { $this->_query->setBoost($this->_boost); return $this->_query; } } 
class Zend_Search_Lucene_Search_Query_Range extends Zend_Search_Lucene_Search_Query { private $_lowerTerm; private $_upperTerm; private $_field; private $_inclusive; private $_matches = null; public function __construct($lowerTerm, $upperTerm, $inclusive) { if ($lowerTerm === null && $upperTerm === null) {  throw new Zend_Search_Lucene_Exception('At least one term must be non-null'); } if ($lowerTerm !== null && $upperTerm !== null && $lowerTerm->field != $upperTerm->field) {  throw new Zend_Search_Lucene_Exception('Both terms must be for the same field'); } $this->_field = ($lowerTerm !== null)? $lowerTerm->field : $upperTerm->field; $this->_lowerTerm = $lowerTerm; $this->_upperTerm = $upperTerm; $this->_inclusive = $inclusive; } public function getField() { return $this->_field; } public function getLowerTerm() { return $this->_lowerTerm; } public function getUpperTerm() { return $this->_upperTerm; } public function isInclusive() { return $this->_inclusive; } public function rewrite(Zend_Search_Lucene_Interface $index) { $this->_matches = array(); if ($this->_field === null) { $fields = $index->getFieldNames(true ); } else { $fields = array($this->_field); }  $maxTerms = Zend_Search_Lucene::getTermsPerQueryLimit(); foreach ($fields as $field) { $index->resetTermsStream();  if ($this->_lowerTerm !== null) { $lowerTerm = new Zend_Search_Lucene_Index_Term($this->_lowerTerm->text, $field); $index->skipTo($lowerTerm); if (!$this->_inclusive && $index->currentTerm() == $lowerTerm) { $index->nextTerm(); } } else { $index->skipTo(new Zend_Search_Lucene_Index_Term('', $field)); } if ($this->_upperTerm !== null) { $upperTerm = new Zend_Search_Lucene_Index_Term($this->_upperTerm->text, $field); while ($index->currentTerm() !== null && $index->currentTerm()->field == $field && strcmp($index->currentTerm()->text, $upperTerm->text) < 0) { $this->_matches[] = $index->currentTerm(); if ($maxTerms != 0 && count($this->_matches) > $maxTerms) {  throw new Zend_Search_Lucene_Exception('Terms per query limit is reached.'); } $index->nextTerm(); } if ($this->_inclusive && $index->currentTerm() == $upperTerm) { $this->_matches[] = $upperTerm; } } else { while ($index->currentTerm() !== null && $index->currentTerm()->field == $field) { $this->_matches[] = $index->currentTerm(); if ($maxTerms != 0 && count($this->_matches) > $maxTerms) {  throw new Zend_Search_Lucene_Exception('Terms per query limit is reached.'); } $index->nextTerm(); } } $index->closeTermsStream(); } if (count($this->_matches) == 0) {  return new Zend_Search_Lucene_Search_Query_Empty(); } else if (count($this->_matches) == 1) {  return new Zend_Search_Lucene_Search_Query_Term(reset($this->_matches)); } else {  $rewrittenQuery = new Zend_Search_Lucene_Search_Query_MultiTerm(); foreach ($this->_matches as $matchedTerm) { $rewrittenQuery->addTerm($matchedTerm); } return $rewrittenQuery; } } public function optimize(Zend_Search_Lucene_Interface $index) {  throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)'); } public function getQueryTerms() { if ($this->_matches === null) {  throw new Zend_Search_Lucene_Exception('Search or rewrite operations have to be performed before.'); } return $this->_matches; } public function createWeight(Zend_Search_Lucene_Interface $reader) {  throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)'); } public function execute(Zend_Search_Lucene_Interface $reader, $docsFilter = null) {  throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)'); } public function matchedDocs() {  throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)'); } public function score($docId, Zend_Search_Lucene_Interface $reader) {  throw new Zend_Search_Lucene_Exception('Range query should not be directly used for search. Use $query->rewrite($index)'); } protected function _highlightMatches(Zend_Search_Lucene_Search_Highlighter_Interface $highlighter) { $words = array(); $docBody = $highlighter->getDocument()->getFieldUtf8Value('body');  $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($docBody, 'UTF-8'); $lowerTermText = ($this->_lowerTerm !== null)? $this->_lowerTerm->text : null; $upperTermText = ($this->_upperTerm !== null)? $this->_upperTerm->text : null; if ($this->_inclusive) { foreach ($tokens as $token) { $termText = $token->getTermText(); if (($lowerTermText == null || $lowerTermText <= $termText) && ($upperTermText == null || $termText <= $upperTermText)) { $words[] = $termText; } } } else { foreach ($tokens as $token) { $termText = $token->getTermText(); if (($lowerTermText == null || $lowerTermText < $termText) && ($upperTermText == null || $termText < $upperTermText)) { $words[] = $termText; } } } $highlighter->highlight($words); } public function __toString() { return (($this->_field === null)? '' : $this->_field . ':') . (($this->_inclusive)? '[' : '{') . (($this->_lowerTerm !== null)? $this->_lowerTerm->text : 'null') . ' TO ' . (($this->_upperTerm !== null)? $this->_upperTerm->text : 'null') . (($this->_inclusive)? ']' : '}') . (($this->getBoost() != 1)? '^' . round($this->getBoost(), 4) : ''); } } 
class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM { private static $_instance = null; private $_lexer; private $_tokens; private $_currentToken; private $_lastToken = null; private $_rqFirstTerm = null; private $_context; private $_contextStack; private $_encoding; private $_defaultEncoding = ''; private $_suppressQueryParsingExceptions = true; const B_OR = 0; const B_AND = 1; private $_defaultOperator = self::B_OR; const ST_COMMON_QUERY_ELEMENT = 0; const ST_CLOSEDINT_RQ_START = 1; const ST_CLOSEDINT_RQ_FIRST_TERM = 2; const ST_CLOSEDINT_RQ_TO_TERM = 3; const ST_CLOSEDINT_RQ_LAST_TERM = 4; const ST_CLOSEDINT_RQ_END = 5; const ST_OPENEDINT_RQ_START = 6; const ST_OPENEDINT_RQ_FIRST_TERM = 7; const ST_OPENEDINT_RQ_TO_TERM = 8; const ST_OPENEDINT_RQ_LAST_TERM = 9; const ST_OPENEDINT_RQ_END = 10; public function __construct() { parent::__construct(array(self::ST_COMMON_QUERY_ELEMENT, self::ST_CLOSEDINT_RQ_START, self::ST_CLOSEDINT_RQ_FIRST_TERM, self::ST_CLOSEDINT_RQ_TO_TERM, self::ST_CLOSEDINT_RQ_LAST_TERM, self::ST_CLOSEDINT_RQ_END, self::ST_OPENEDINT_RQ_START, self::ST_OPENEDINT_RQ_FIRST_TERM, self::ST_OPENEDINT_RQ_TO_TERM, self::ST_OPENEDINT_RQ_LAST_TERM, self::ST_OPENEDINT_RQ_END ), Zend_Search_Lucene_Search_QueryToken::getTypes()); $this->addRules( array(array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_START, self::ST_CLOSEDINT_RQ_START), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_START, self::ST_OPENEDINT_RQ_START), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, self::ST_COMMON_QUERY_ELEMENT), array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, self::ST_COMMON_QUERY_ELEMENT) )); $this->addRules( array(array(self::ST_CLOSEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_FIRST_TERM), array(self::ST_CLOSEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_CLOSEDINT_RQ_TO_TERM), array(self::ST_CLOSEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_LAST_TERM), array(self::ST_CLOSEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_END, self::ST_COMMON_QUERY_ELEMENT) )); $this->addRules( array(array(self::ST_OPENEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_FIRST_TERM), array(self::ST_OPENEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_OPENEDINT_RQ_TO_TERM), array(self::ST_OPENEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_LAST_TERM), array(self::ST_OPENEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_END, self::ST_COMMON_QUERY_ELEMENT) )); $addTermEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addTermEntry'); $addPhraseEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addPhraseEntry'); $setFieldAction = new Zend_Search_Lucene_FSMAction($this, 'setField'); $setSignAction = new Zend_Search_Lucene_FSMAction($this, 'setSign'); $setFuzzyProxAction = new Zend_Search_Lucene_FSMAction($this, 'processFuzzyProximityModifier'); $processModifierParameterAction = new Zend_Search_Lucene_FSMAction($this, 'processModifierParameter'); $subqueryStartAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryStart'); $subqueryEndAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryEnd'); $logicalOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'logicalOperator'); $openedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQFirstTerm'); $openedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQLastTerm'); $closedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQFirstTerm'); $closedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQLastTerm'); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, $addTermEntryAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, $addPhraseEntryAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, $setFieldAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, $setSignAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, $setSignAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, $setFuzzyProxAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, $processModifierParameterAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, $subqueryStartAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, $subqueryEndAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, $logicalOperatorAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, $logicalOperatorAction); $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, $logicalOperatorAction); $this->addEntryAction(self::ST_OPENEDINT_RQ_FIRST_TERM, $openedRQFirstTermAction); $this->addEntryAction(self::ST_OPENEDINT_RQ_LAST_TERM, $openedRQLastTermAction); $this->addEntryAction(self::ST_CLOSEDINT_RQ_FIRST_TERM, $closedRQFirstTermAction); $this->addEntryAction(self::ST_CLOSEDINT_RQ_LAST_TERM, $closedRQLastTermAction);  $this->_lexer = new Zend_Search_Lucene_Search_QueryLexer(); } private static function _getInstance() { if (self::$_instance === null) { self::$_instance = new self(); } return self::$_instance; } public static function setDefaultEncoding($encoding) { self::_getInstance()->_defaultEncoding = $encoding; } public static function getDefaultEncoding() { return self::_getInstance()->_defaultEncoding; } public static function setDefaultOperator($operator) { self::_getInstance()->_defaultOperator = $operator; } public static function getDefaultOperator() { return self::_getInstance()->_defaultOperator; } public static function suppressQueryParsingExceptions() { self::_getInstance()->_suppressQueryParsingExceptions = true; } public static function dontSuppressQueryParsingExceptions() { self::_getInstance()->_suppressQueryParsingExceptions = false; } public static function queryParsingExceptionsSuppressed() { return self::_getInstance()->_suppressQueryParsingExceptions; } public static function escape($keyword) { return '\\' . implode('\\', str_split($keyword)); } public static function parse($strQuery, $encoding = null) { self::_getInstance(); self::$_instance->reset();  try {  self::$_instance->_encoding = ($encoding !== null) ? $encoding : self::$_instance->_defaultEncoding; self::$_instance->_lastToken = null; self::$_instance->_context = new Zend_Search_Lucene_Search_QueryParserContext(self::$_instance->_encoding); self::$_instance->_contextStack = array(); self::$_instance->_tokens = self::$_instance->_lexer->tokenize($strQuery, self::$_instance->_encoding); if (count(self::$_instance->_tokens) == 0) {  return new Zend_Search_Lucene_Search_Query_Insignificant(); } foreach (self::$_instance->_tokens as $token) { try { self::$_instance->_currentToken = $token; self::$_instance->process($token->type); self::$_instance->_lastToken = $token; } catch (Exception $e) { if (strpos($e->getMessage(), 'There is no any rule for') !== false) { throw new Zend_Search_Lucene_Search_QueryParserException( 'Syntax error at char position ' . $token->position . '.', 0, $e); }  throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } } if (count(self::$_instance->_contextStack) != 0) { throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing.' ); } return self::$_instance->_context->getQuery(); } catch (Zend_Search_Lucene_Search_QueryParserException $e) { if (self::$_instance->_suppressQueryParsingExceptions) { $queryTokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($strQuery, self::$_instance->_encoding);  $query = new Zend_Search_Lucene_Search_Query_MultiTerm(); $termsSign = (self::$_instance->_defaultOperator == self::B_AND) ? true : null ;  foreach ($queryTokens as $token) { $query->addTerm(new Zend_Search_Lucene_Index_Term($token->getTermText()), $termsSign); } return $query; } else {  throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } } } public function addTermEntry() {  $entry = new Zend_Search_Lucene_Search_QueryEntry_Term($this->_currentToken->text, $this->_context->getField()); $this->_context->addEntry($entry); } public function addPhraseEntry() {  $entry = new Zend_Search_Lucene_Search_QueryEntry_Phrase($this->_currentToken->text, $this->_context->getField()); $this->_context->addEntry($entry); } public function setField() { $this->_context->setNextEntryField($this->_currentToken->text); } public function setSign() { $this->_context->setNextEntrySign($this->_currentToken->type); } public function processFuzzyProximityModifier() { $this->_context->processFuzzyProximityModifier(); } public function processModifierParameter() { if ($this->_lastToken === null) {  throw new Zend_Search_Lucene_Search_QueryParserException('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' ); } switch ($this->_lastToken->type) { case Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK: $this->_context->processFuzzyProximityModifier($this->_currentToken->text); break; case Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK: $this->_context->boost($this->_currentToken->text); break; default:  throw new Zend_Search_Lucene_Exception('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' ); } } public function subqueryStart() {  $this->_contextStack[] = $this->_context; $this->_context = new Zend_Search_Lucene_Search_QueryParserContext($this->_encoding, $this->_context->getField()); } public function subqueryEnd() { if (count($this->_contextStack) == 0) {  throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing. Char position ' . $this->_currentToken->position . '.' ); } $query = $this->_context->getQuery(); $this->_context = array_pop($this->_contextStack);  $this->_context->addEntry(new Zend_Search_Lucene_Search_QueryEntry_Subquery($query)); } public function logicalOperator() { $this->_context->addLogicalOperator($this->_currentToken->type); } public function openedRQFirstTerm() { $this->_rqFirstTerm = $this->_currentToken->text; } public function openedRQLastTerm() { $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding); if (count($tokens) > 1) {  throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); } else if (count($tokens) == 1) {  $from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); } else { $from = null; } $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding); if (count($tokens) > 1) {  throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); } else if (count($tokens) == 1) {  $to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); } else { $to = null; } if ($from === null && $to === null) {  throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term'); }  $rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, false);  $entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery); $this->_context->addEntry($entry); } public function closedRQFirstTerm() { $this->_rqFirstTerm = $this->_currentToken->text; } public function closedRQLastTerm() { $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding); if (count($tokens) > 1) {  throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); } else if (count($tokens) == 1) {  $from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); } else { $from = null; } $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding); if (count($tokens) > 1) {  throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms'); } else if (count($tokens) == 1) {  $to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField()); } else { $to = null; } if ($from === null && $to === null) {  throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term'); }  $rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, true);  $entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery); $this->_context->addEntry($entry); } } 
interface Zend_Search_Lucene_Index_TermsStream_Interface { public function resetTermsStream(); public function skipTo(Zend_Search_Lucene_Index_Term $prefix); public function nextTerm(); public function currentTerm(); public function closeTermsStream(); } 
class Zend_Search_Lucene_Field { public $name; public $value; public $isStored = false; public $isIndexed = true; public $isTokenized = true; public $isBinary = false; public $storeTermVector = false; public $boost = 1.0; public $encoding; public function __construct($name, $value, $encoding, $isStored, $isIndexed, $isTokenized, $isBinary = false) { $this->name = $name; $this->value = $value; if (!$isBinary) { $this->encoding = $encoding; $this->isTokenized = $isTokenized; } else { $this->encoding = ''; $this->isTokenized = false; } $this->isStored = $isStored; $this->isIndexed = $isIndexed; $this->isBinary = $isBinary; $this->storeTermVector = false; $this->boost = 1.0; } public static function keyword($name, $value, $encoding = '') { return new self($name, $value, $encoding, true, true, false); } public static function unIndexed($name, $value, $encoding = '') { return new self($name, $value, $encoding, true, false, false); } public static function binary($name, $value) { return new self($name, $value, '', true, false, false, true); } public static function text($name, $value, $encoding = '') { return new self($name, $value, $encoding, true, true, true); } public static function unStored($name, $value, $encoding = '') { return new self($name, $value, $encoding, false, true, true); } public function getUtf8Value() { if (strcasecmp($this->encoding, 'utf8' ) == 0 || strcasecmp($this->encoding, 'utf-8') == 0 ) { return $this->value; } else { return (PHP_OS != 'AIX') ? iconv($this->encoding, 'UTF-8', $this->value) : iconv('ISO8859-1', 'UTF-8', $this->value); } } } 
class Zend_Search_Lucene_Document { protected $_fields = array(); public $boost = 1.0; public function __get($offset) { return $this->getFieldValue($offset); } public function addField(Zend_Search_Lucene_Field $field) { $this->_fields[$field->name] = $field; return $this; } public function getFieldNames() { return array_keys($this->_fields); } public function getField($fieldName) { if (!array_key_exists($fieldName, $this->_fields)) {  throw new Zend_Search_Lucene_Exception("Field name \"$fieldName\" not found in document."); } return $this->_fields[$fieldName]; } public function getFieldValue($fieldName) { return $this->getField($fieldName)->value; } public function getFieldUtf8Value($fieldName) { return $this->getField($fieldName)->getUtf8Value(); } } 
interface Zend_Search_Lucene_Interface extends Zend_Search_Lucene_Index_TermsStream_Interface { public static function getActualGeneration(Zend_Search_Lucene_Storage_Directory $directory); public static function getSegmentFileName($generation); public function getFormatVersion(); public function setFormatVersion($formatVersion); public function getDirectory(); public function count(); public function maxDoc(); public function numDocs(); public function isDeleted($id); public static function setDefaultSearchField($fieldName); public static function getDefaultSearchField(); public static function setResultSetLimit($limit); public static function getResultSetLimit(); public function getMaxBufferedDocs(); public function setMaxBufferedDocs($maxBufferedDocs); public function getMaxMergeDocs(); public function setMaxMergeDocs($maxMergeDocs); public function getMergeFactor(); public function setMergeFactor($mergeFactor); public function find($query); public function getFieldNames($indexed = false); public function getDocument($id); public function hasTerm(Zend_Search_Lucene_Index_Term $term); public function termDocs(Zend_Search_Lucene_Index_Term $term, $docsFilter = null); public function termDocsFilter(Zend_Search_Lucene_Index_Term $term, $docsFilter = null); public function termFreqs(Zend_Search_Lucene_Index_Term $term, $docsFilter = null); public function termPositions(Zend_Search_Lucene_Index_Term $term, $docsFilter = null); public function docFreq(Zend_Search_Lucene_Index_Term $term); public function getSimilarity(); public function norm($id, $fieldName); public function hasDeletions(); public function delete($id); public function addDocument(Zend_Search_Lucene_Document $document); public function commit(); public function optimize(); public function terms(); public function undeleteAll(); public function addReference(); public function removeReference(); } 
class Zend_Search_Lucene_Proxy implements Zend_Search_Lucene_Interface { private $_index; public function __construct(Zend_Search_Lucene_Interface $index) { $this->_index = $index; $this->_index->addReference(); } public function __destruct() { if ($this->_index !== null) { $this->_index->removeReference(); } $this->_index = null; } public static function getActualGeneration(Zend_Search_Lucene_Storage_Directory $directory) { Zend_Search_Lucene::getActualGeneration($directory); } public static function getSegmentFileName($generation) { Zend_Search_Lucene::getSegmentFileName($generation); } public function getFormatVersion() { return $this->_index->getFormatVersion(); } public function setFormatVersion($formatVersion) { $this->_index->setFormatVersion($formatVersion); } public function getDirectory() { return $this->_index->getDirectory(); } public function count() { return $this->_index->count(); } public function maxDoc() { return $this->_index->maxDoc(); } public function numDocs() { return $this->_index->numDocs(); } public function isDeleted($id) { return $this->_index->isDeleted($id); } public static function setDefaultSearchField($fieldName) { Zend_Search_Lucene::setDefaultSearchField($fieldName); } public static function getDefaultSearchField() { return Zend_Search_Lucene::getDefaultSearchField(); } public static function setResultSetLimit($limit) { Zend_Search_Lucene::setResultSetLimit($limit); } public static function getResultSetLimit() { return Zend_Search_Lucene::getResultSetLimit(); } public function getMaxBufferedDocs() { return $this->_index->getMaxBufferedDocs(); } public function setMaxBufferedDocs($maxBufferedDocs) { $this->_index->setMaxBufferedDocs($maxBufferedDocs); } public function getMaxMergeDocs() { return $this->_index->getMaxMergeDocs(); } public function setMaxMergeDocs($maxMergeDocs) { $this->_index->setMaxMergeDocs($maxMergeDocs); } public function getMergeFactor() { return $this->_index->getMergeFactor(); } public function setMergeFactor($mergeFactor) { $this->_index->setMergeFactor($mergeFactor); } public function find($query) { $parameters = func_get_args(); return call_user_func_array(array(&$this->_index, 'find'), $parameters); } public function getFieldNames($indexed = false) { return $this->_index->getFieldNames($indexed); } public function getDocument($id) { return $this->_index->getDocument($id); } public function hasTerm(Zend_Search_Lucene_Index_Term $term) { return $this->_index->hasTerm($term); } public function termDocs(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) { return $this->_index->termDocs($term, $docsFilter); } public function termDocsFilter(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) { return $this->_index->termDocsFilter($term, $docsFilter); } public function termFreqs(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) { return $this->_index->termFreqs($term, $docsFilter); } public function termPositions(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) { return $this->_index->termPositions($term, $docsFilter); } public function docFreq(Zend_Search_Lucene_Index_Term $term) { return $this->_index->docFreq($term); } public function getSimilarity() { return $this->_index->getSimilarity(); } public function norm($id, $fieldName) { return $this->_index->norm($id, $fieldName); } public function hasDeletions() { return $this->_index->hasDeletions(); } public function delete($id) { return $this->_index->delete($id); } public function addDocument(Zend_Search_Lucene_Document $document) { $this->_index->addDocument($document); } public function commit() { $this->_index->commit(); } public function optimize() { $this->_index->optimize(); } public function terms() { return $this->_index->terms(); } public function resetTermsStream() { $this->_index->resetTermsStream(); } public function skipTo(Zend_Search_Lucene_Index_Term $prefix) { return $this->_index->skipTo($prefix); } public function nextTerm() { return $this->_index->nextTerm(); } public function currentTerm() { return $this->_index->currentTerm(); } public function closeTermsStream() { $this->_index->closeTermsStream(); } public function undeleteAll() { return $this->_index->undeleteAll(); } public function addReference() { return $this->_index->addReference(); } public function removeReference() { return $this->_index->removeReference(); } } 
class Zend_Search_Lucene_Search_QueryHit { protected $_index = null; protected $_document = null; public $id; public $score; public function __construct(Zend_Search_Lucene_Interface $index) {  $this->_index = new Zend_Search_Lucene_Proxy($index); } public function __get($offset) { return $this->getDocument()->getFieldValue($offset); } public function getDocument() { if (!$this->_document instanceof Zend_Search_Lucene_Document) { $this->_document = $this->_index->getDocument($this->id); } return $this->_document; } public function getIndex() { return $this->_index; } } 
class Zend_Search_Lucene_Search_Similarity_Default extends Zend_Search_Lucene_Search_Similarity { public function lengthNorm($fieldName, $numTerms) { if ($numTerms == 0) { return 1E10; } return 1.0/sqrt($numTerms); } public function queryNorm($sumOfSquaredWeights) { return 1.0/sqrt($sumOfSquaredWeights); } public function tf($freq) { return sqrt($freq); } public function sloppyFreq($distance) { return 1.0/($distance + 1); } public function idfFreq($docFreq, $numDocs) { return log($numDocs/(float)($docFreq+1)) + 1.0; } public function coord($overlap, $maxOverlap) { return $overlap/(float)$maxOverlap; } } 
abstract class Zend_Search_Lucene_Search_Similarity { private static $_defaultImpl; private static $_normTable = array( 0 => 0.0, 1 => 5.820766E-10, 2 => 6.9849193E-10, 3 => 8.1490725E-10, 4 => 9.313226E-10, 5 => 1.1641532E-9, 6 => 1.3969839E-9, 7 => 1.6298145E-9, 8 => 1.8626451E-9, 9 => 2.3283064E-9, 10 => 2.7939677E-9, 11 => 3.259629E-9, 12 => 3.7252903E-9, 13 => 4.656613E-9, 14 => 5.5879354E-9, 15 => 6.519258E-9, 16 => 7.4505806E-9, 17 => 9.313226E-9, 18 => 1.1175871E-8, 19 => 1.3038516E-8, 20 => 1.4901161E-8, 21 => 1.8626451E-8, 22 => 2.2351742E-8, 23 => 2.6077032E-8, 24 => 2.9802322E-8, 25 => 3.7252903E-8, 26 => 4.4703484E-8, 27 => 5.2154064E-8, 28 => 5.9604645E-8, 29 => 7.4505806E-8, 30 => 8.940697E-8, 31 => 1.0430813E-7, 32 => 1.1920929E-7, 33 => 1.4901161E-7, 34 => 1.7881393E-7, 35 => 2.0861626E-7, 36 => 2.3841858E-7, 37 => 2.9802322E-7, 38 => 3.5762787E-7, 39 => 4.172325E-7, 40 => 4.7683716E-7, 41 => 5.9604645E-7, 42 => 7.1525574E-7, 43 => 8.34465E-7, 44 => 9.536743E-7, 45 => 1.1920929E-6, 46 => 1.4305115E-6, 47 => 1.66893E-6, 48 => 1.9073486E-6, 49 => 2.3841858E-6, 50 => 2.861023E-6, 51 => 3.33786E-6, 52 => 3.8146973E-6, 53 => 4.7683716E-6, 54 => 5.722046E-6, 55 => 6.67572E-6, 56 => 7.6293945E-6, 57 => 9.536743E-6, 58 => 1.1444092E-5, 59 => 1.335144E-5, 60 => 1.5258789E-5, 61 => 1.9073486E-5, 62 => 2.2888184E-5, 63 => 2.670288E-5, 64 => 3.0517578E-5, 65 => 3.8146973E-5, 66 => 4.5776367E-5, 67 => 5.340576E-5, 68 => 6.1035156E-5, 69 => 7.6293945E-5, 70 => 9.1552734E-5, 71 => 1.0681152E-4, 72 => 1.2207031E-4, 73 => 1.5258789E-4, 74 => 1.8310547E-4, 75 => 2.1362305E-4, 76 => 2.4414062E-4, 77 => 3.0517578E-4, 78 => 3.6621094E-4, 79 => 4.272461E-4, 80 => 4.8828125E-4, 81 => 6.1035156E-4, 82 => 7.324219E-4, 83 => 8.544922E-4, 84 => 9.765625E-4, 85 => 0.0012207031, 86 => 0.0014648438, 87 => 0.0017089844, 88 => 0.001953125, 89 => 0.0024414062, 90 => 0.0029296875, 91 => 0.0034179688, 92 => 0.00390625, 93 => 0.0048828125, 94 => 0.005859375, 95 => 0.0068359375, 96 => 0.0078125, 97 => 0.009765625, 98 => 0.01171875, 99 => 0.013671875, 100 => 0.015625, 101 => 0.01953125, 102 => 0.0234375, 103 => 0.02734375, 104 => 0.03125, 105 => 0.0390625, 106 => 0.046875, 107 => 0.0546875, 108 => 0.0625, 109 => 0.078125, 110 => 0.09375, 111 => 0.109375, 112 => 0.125, 113 => 0.15625, 114 => 0.1875, 115 => 0.21875, 116 => 0.25, 117 => 0.3125, 118 => 0.375, 119 => 0.4375, 120 => 0.5, 121 => 0.625, 122 => 0.75, 123 => 0.875, 124 => 1.0, 125 => 1.25, 126 => 1.5, 127 => 1.75, 128 => 2.0, 129 => 2.5, 130 => 3.0, 131 => 3.5, 132 => 4.0, 133 => 5.0, 134 => 6.0, 135 => 7.0, 136 => 8.0, 137 => 10.0, 138 => 12.0, 139 => 14.0, 140 => 16.0, 141 => 20.0, 142 => 24.0, 143 => 28.0, 144 => 32.0, 145 => 40.0, 146 => 48.0, 147 => 56.0, 148 => 64.0, 149 => 80.0, 150 => 96.0, 151 => 112.0, 152 => 128.0, 153 => 160.0, 154 => 192.0, 155 => 224.0, 156 => 256.0, 157 => 320.0, 158 => 384.0, 159 => 448.0, 160 => 512.0, 161 => 640.0, 162 => 768.0, 163 => 896.0, 164 => 1024.0, 165 => 1280.0, 166 => 1536.0, 167 => 1792.0, 168 => 2048.0, 169 => 2560.0, 170 => 3072.0, 171 => 3584.0, 172 => 4096.0, 173 => 5120.0, 174 => 6144.0, 175 => 7168.0, 176 => 8192.0, 177 => 10240.0, 178 => 12288.0, 179 => 14336.0, 180 => 16384.0, 181 => 20480.0, 182 => 24576.0, 183 => 28672.0, 184 => 32768.0, 185 => 40960.0, 186 => 49152.0, 187 => 57344.0, 188 => 65536.0, 189 => 81920.0, 190 => 98304.0, 191 => 114688.0, 192 => 131072.0, 193 => 163840.0, 194 => 196608.0, 195 => 229376.0, 196 => 262144.0, 197 => 327680.0, 198 => 393216.0, 199 => 458752.0, 200 => 524288.0, 201 => 655360.0, 202 => 786432.0, 203 => 917504.0, 204 => 1048576.0, 205 => 1310720.0, 206 => 1572864.0, 207 => 1835008.0, 208 => 2097152.0, 209 => 2621440.0, 210 => 3145728.0, 211 => 3670016.0, 212 => 4194304.0, 213 => 5242880.0, 214 => 6291456.0, 215 => 7340032.0, 216 => 8388608.0, 217 => 1.048576E7, 218 => 1.2582912E7, 219 => 1.4680064E7, 220 => 1.6777216E7, 221 => 2.097152E7, 222 => 2.5165824E7, 223 => 2.9360128E7, 224 => 3.3554432E7, 225 => 4.194304E7, 226 => 5.0331648E7, 227 => 5.8720256E7, 228 => 6.7108864E7, 229 => 8.388608E7, 230 => 1.00663296E8, 231 => 1.17440512E8, 232 => 1.34217728E8, 233 => 1.6777216E8, 234 => 2.01326592E8, 235 => 2.34881024E8, 236 => 2.68435456E8, 237 => 3.3554432E8, 238 => 4.02653184E8, 239 => 4.69762048E8, 240 => 5.3687091E8, 241 => 6.7108864E8, 242 => 8.0530637E8, 243 => 9.395241E8, 244 => 1.07374182E9, 245 => 1.34217728E9, 246 => 1.61061274E9, 247 => 1.87904819E9, 248 => 2.14748365E9, 249 => 2.68435456E9, 250 => 3.22122547E9, 251 => 3.75809638E9, 252 => 4.2949673E9, 253 => 5.3687091E9, 254 => 6.4424509E9, 255 => 7.5161928E9 ); public static function setDefault(Zend_Search_Lucene_Search_Similarity $similarity) { self::$_defaultImpl = $similarity; } public static function getDefault() { if (!self::$_defaultImpl instanceof Zend_Search_Lucene_Search_Similarity) {  self::$_defaultImpl = new Zend_Search_Lucene_Search_Similarity_Default(); } return self::$_defaultImpl; } abstract public function lengthNorm($fieldName, $numTokens); abstract public function queryNorm($sumOfSquaredWeights); public static function decodeNorm($byte) { return self::$_normTable[$byte & 0xFF]; } static function encodeNorm($f) { return self::_floatToByte($f); } private static function _floatToByte($f) { if ($f <= 0.0) { return 0; } $lowIndex = 0; $highIndex = 255; while ($highIndex >= $lowIndex) { $mid = ($highIndex + $lowIndex) >> 1; $delta = $f - self::$_normTable[$mid]; if ($delta < 0) { $highIndex = $mid-1; } elseif ($delta > 0) { $lowIndex = $mid+1; } else { return $mid; } } if ($highIndex != 255 && $f - self::$_normTable[$highIndex] > self::$_normTable[$highIndex+1] - $f ) { return $highIndex + 1; } else { return $highIndex; } } abstract public function tf($freq); abstract public function sloppyFreq($distance); public function idf($input, Zend_Search_Lucene_Interface $reader) { if (!is_array($input)) { return $this->idfFreq($reader->docFreq($input), $reader->count()); } else { $idf = 0.0; foreach ($input as $term) { $idf += $this->idfFreq($reader->docFreq($term), $reader->count()); } return $idf; } } abstract public function idfFreq($docFreq, $numDocs); abstract public function coord($overlap, $maxOverlap); } 
class Zend_Search_Lucene_Index_FieldInfo { public $name; public $isIndexed; public $number; public $storeTermVector; public $normsOmitted; public $payloadsStored; public function __construct($name, $isIndexed, $number, $storeTermVector, $normsOmitted = false, $payloadsStored = false) { $this->name = $name; $this->isIndexed = $isIndexed; $this->number = $number; $this->storeTermVector = $storeTermVector; $this->normsOmitted = $normsOmitted; $this->payloadsStored = $payloadsStored; } } 
class Zend_Search_Lucene_Index_TermInfo { public $docFreq; public $freqPointer; public $proxPointer; public $skipOffset; public $indexPointer; public function __construct($docFreq, $freqPointer, $proxPointer, $skipOffset, $indexPointer = null) { $this->docFreq = $docFreq; $this->freqPointer = $freqPointer; $this->proxPointer = $proxPointer; $this->skipOffset = $skipOffset; $this->indexPointer = $indexPointer; } } 
class Zend_Search_Lucene_Index_DictionaryLoader { public static function load($data) { $termDictionary = array(); $termInfos = array(); $pos = 0; $tiVersion = ord($data[0]) << 24 | ord($data[1]) << 16 | ord($data[2]) << 8 | ord($data[3]); $pos += 4; if ($tiVersion != (int)0xFFFFFFFE && $tiVersion != (int)0xFFFFFFFD ) {  throw new Zend_Search_Lucene_Exception('Wrong TermInfoIndexFile file format'); } if (PHP_INT_SIZE > 4) { $indexTermCount = ord($data[$pos]) << 56 | ord($data[$pos+1]) << 48 | ord($data[$pos+2]) << 40 | ord($data[$pos+3]) << 32 | ord($data[$pos+4]) << 24 | ord($data[$pos+5]) << 16 | ord($data[$pos+6]) << 8 | ord($data[$pos+7]); } else { if ((ord($data[$pos]) != 0) || (ord($data[$pos+1]) != 0) || (ord($data[$pos+2]) != 0) || (ord($data[$pos+3]) != 0) || ((ord($data[$pos+4]) & 0x80) != 0)) {  throw new Zend_Search_Lucene_Exception('Largest supported segment size (for 32-bit mode) is 2Gb'); } $indexTermCount = ord($data[$pos+4]) << 24 | ord($data[$pos+5]) << 16 | ord($data[$pos+6]) << 8 | ord($data[$pos+7]); } $pos += 8; $pos += 4; $skipInterval = ord($data[$pos]) << 24 | ord($data[$pos+1]) << 16 | ord($data[$pos+2]) << 8 | ord($data[$pos+3]); $pos += 4; if ($indexTermCount < 1) {  throw new Zend_Search_Lucene_Exception('Wrong number of terms in a term dictionary index'); } if ($tiVersion == (int)0xFFFFFFFD ) { $pos += 4; } $prevTerm = ''; $freqPointer = 0; $proxPointer = 0; $indexPointer = 0; for ($count = 0; $count < $indexTermCount; $count++) { $nbyte = ord($data[$pos++]); $termPrefixLength = $nbyte & 0x7F; for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { $nbyte = ord($data[$pos++]); $termPrefixLength |= ($nbyte & 0x7F) << $shift; } $nbyte = ord($data[$pos++]); $len = $nbyte & 0x7F; for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { $nbyte = ord($data[$pos++]); $len |= ($nbyte & 0x7F) << $shift; } if ($len == 0) { $termSuffix = ''; } else { $termSuffix = substr($data, $pos, $len); $pos += $len; for ($count1 = 0; $count1 < $len; $count1++ ) { if (( ord($termSuffix[$count1]) & 0xC0 ) == 0xC0) { $addBytes = 1; if (ord($termSuffix[$count1]) & 0x20 ) { $addBytes++; if (ord($termSuffix[$count1]) & 0x10 ) { $addBytes++; } } $termSuffix .= substr($data, $pos, $addBytes); $pos += $addBytes; $len += $addBytes; if (ord($termSuffix[$count1]) == 0xC0 && ord($termSuffix[$count1+1]) == 0x80 ) { $termSuffix[$count1] = 0; $termSuffix = substr($termSuffix,0,$count1+1) . substr($termSuffix,$count1+2); } $count1 += $addBytes; } } } $pb = 0; $pc = 0; while ($pb < strlen($prevTerm) && $pc < $termPrefixLength) { $charBytes = 1; if ((ord($prevTerm[$pb]) & 0xC0) == 0xC0) { $charBytes++; if (ord($prevTerm[$pb]) & 0x20 ) { $charBytes++; if (ord($prevTerm[$pb]) & 0x10 ) { $charBytes++; } } } if ($pb + $charBytes > strlen($data)) { break; } $pc++; $pb += $charBytes; } $termValue = substr($prevTerm, 0, $pb) . $termSuffix; $nbyte = ord($data[$pos++]); $termFieldNum = $nbyte & 0x7F; for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { $nbyte = ord($data[$pos++]); $termFieldNum |= ($nbyte & 0x7F) << $shift; } $nbyte = ord($data[$pos++]); $docFreq = $nbyte & 0x7F; for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { $nbyte = ord($data[$pos++]); $docFreq |= ($nbyte & 0x7F) << $shift; } $nbyte = ord($data[$pos++]); $vint = $nbyte & 0x7F; for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { $nbyte = ord($data[$pos++]); $vint |= ($nbyte & 0x7F) << $shift; } $freqPointer += $vint; $nbyte = ord($data[$pos++]); $vint = $nbyte & 0x7F; for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { $nbyte = ord($data[$pos++]); $vint |= ($nbyte & 0x7F) << $shift; } $proxPointer += $vint; if( $docFreq >= $skipInterval ) { $nbyte = ord($data[$pos++]); $vint = $nbyte & 0x7F; for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { $nbyte = ord($data[$pos++]); $vint |= ($nbyte & 0x7F) << $shift; } $skipDelta = $vint; } else { $skipDelta = 0; } $nbyte = ord($data[$pos++]); $vint = $nbyte & 0x7F; for ($shift=7; ($nbyte & 0x80) != 0; $shift += 7) { $nbyte = ord($data[$pos++]); $vint |= ($nbyte & 0x7F) << $shift; } $indexPointer += $vint; $termDictionary[] = array($termFieldNum, $termValue); $termInfos[] = array($docFreq, $freqPointer, $proxPointer, $skipDelta, $indexPointer); $prevTerm = $termValue; } if ($termDictionary[0][0] != (int)0xFFFFFFFF) {  throw new Zend_Search_Lucene_Exception('Wrong TermInfoIndexFile file format'); } if (PHP_INT_SIZE > 4) { $termDictionary[0][0] = -1; } return array($termDictionary, $termInfos); } } 
class Zend_Search_Lucene_Index_SegmentInfo implements Zend_Search_Lucene_Index_TermsStream_Interface { const FULL_SCAN_VS_FETCH_BOUNDARY = 5; private $_docCount; private $_name; private $_termDictionary; private $_termDictionaryInfos; private $_fields; private $_fieldsDicPositions; private $_segFiles; private $_segFileSizes; private $_delGen; private $_hasSingleNormFile; private $_isCompound; private $_directory; private $_norms = array(); private $_deleted = null; private $_deletedDirty = false; private $_usesSharedDocStore; private $_sharedDocStoreOptions; public function __construct(Zend_Search_Lucene_Storage_Directory $directory, $name, $docCount, $delGen = 0, $docStoreOptions = null, $hasSingleNormFile = false, $isCompound = null) { $this->_directory = $directory; $this->_name = $name; $this->_docCount = $docCount; if ($docStoreOptions !== null) { $this->_usesSharedDocStore = true; $this->_sharedDocStoreOptions = $docStoreOptions; if ($docStoreOptions['isCompound']) { $cfxFile = $this->_directory->getFileObject($docStoreOptions['segment'] . '.cfx'); $cfxFilesCount = $cfxFile->readVInt(); $cfxFiles = array(); $cfxFileSizes = array(); for ($count = 0; $count < $cfxFilesCount; $count++) { $dataOffset = $cfxFile->readLong(); if ($count != 0) { $cfxFileSizes[$fileName] = $dataOffset - end($cfxFiles); } $fileName = $cfxFile->readString(); $cfxFiles[$fileName] = $dataOffset; } if ($count != 0) { $cfxFileSizes[$fileName] = $this->_directory->fileLength($docStoreOptions['segment'] . '.cfx') - $dataOffset; } $this->_sharedDocStoreOptions['files'] = $cfxFiles; $this->_sharedDocStoreOptions['fileSizes'] = $cfxFileSizes; } } $this->_hasSingleNormFile = $hasSingleNormFile; $this->_delGen = $delGen; $this->_termDictionary = null; if ($isCompound !== null) { $this->_isCompound = $isCompound; } else {  try { $this->_directory->getFileObject($name . '.cfs'); $this->_isCompound = true; } catch (Zend_Search_Lucene_Exception $e) { if (strpos($e->getMessage(), 'is not readable') !== false) { $this->_isCompound = false; } else { throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } } } $this->_segFiles = array(); if ($this->_isCompound) { $cfsFile = $this->_directory->getFileObject($name . '.cfs'); $segFilesCount = $cfsFile->readVInt(); for ($count = 0; $count < $segFilesCount; $count++) { $dataOffset = $cfsFile->readLong(); if ($count != 0) { $this->_segFileSizes[$fileName] = $dataOffset - end($this->_segFiles); } $fileName = $cfsFile->readString(); $this->_segFiles[$fileName] = $dataOffset; } if ($count != 0) { $this->_segFileSizes[$fileName] = $this->_directory->fileLength($name . '.cfs') - $dataOffset; } } $fnmFile = $this->openCompoundFile('.fnm'); $fieldsCount = $fnmFile->readVInt(); $fieldNames = array(); $fieldNums = array(); $this->_fields = array(); for ($count=0; $count < $fieldsCount; $count++) { $fieldName = $fnmFile->readString(); $fieldBits = $fnmFile->readByte(); $this->_fields[$count] = new Zend_Search_Lucene_Index_FieldInfo($fieldName, $fieldBits & 0x01 , $count, $fieldBits & 0x02 , $fieldBits & 0x10 , $fieldBits & 0x20 ); if ($fieldBits & 0x10) { $this->_norms[$count] = str_repeat(chr(Zend_Search_Lucene_Search_Similarity::encodeNorm(1.0)), $docCount); } $fieldNums[$count] = $count; $fieldNames[$count] = $fieldName; } array_multisort($fieldNames, SORT_ASC, SORT_REGULAR, $fieldNums); $this->_fieldsDicPositions = array_flip($fieldNums); if ($this->_delGen == -2) { $this->_delGen = $this->_detectLatestDelGen(); } $this->_deleted = $this->_loadDelFile(); } private function _loadDelFile() { if ($this->_delGen == -1) { return null; } else if ($this->_delGen == 0) { return $this->_loadPre21DelFile(); } else { return $this->_load21DelFile(); } } private function _loadPre21DelFile() {  try { $delFile = $this->_directory->getFileObject($this->_name . '.del'); $byteCount = $delFile->readInt(); $byteCount = ceil($byteCount/8); $bitCount = $delFile->readInt(); if ($bitCount == 0) { $delBytes = ''; } else { $delBytes = $delFile->readBytes($byteCount); } if (extension_loaded('bitset')) { return $delBytes; } else { $deletions = array(); for ($count = 0; $count < $byteCount; $count++) { $byte = ord($delBytes[$count]); for ($bit = 0; $bit < 8; $bit++) { if ($byte & (1<<$bit)) { $deletions[$count*8 + $bit] = 1; } } } return $deletions; } } catch(Zend_Search_Lucene_Exception $e) { if (strpos($e->getMessage(), 'is not readable') === false) { throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } $this->_delGen = -1; return null; } } private function _load21DelFile() { $delFile = $this->_directory->getFileObject($this->_name . '_' . base_convert($this->_delGen, 10, 36) . '.del'); $format = $delFile->readInt(); if ($format == (int)0xFFFFFFFF) { if (extension_loaded('bitset')) { $deletions = bitset_empty(); } else { $deletions = array(); } $byteCount = $delFile->readInt(); $bitCount = $delFile->readInt(); $delFileSize = $this->_directory->fileLength($this->_name . '_' . base_convert($this->_delGen, 10, 36) . '.del'); $byteNum = 0; do { $dgap = $delFile->readVInt(); $nonZeroByte = $delFile->readByte(); $byteNum += $dgap; if (extension_loaded('bitset')) { for ($bit = 0; $bit < 8; $bit++) { if ($nonZeroByte & (1<<$bit)) { bitset_incl($deletions, $byteNum*8 + $bit); } } return $deletions; } else { for ($bit = 0; $bit < 8; $bit++) { if ($nonZeroByte & (1<<$bit)) { $deletions[$byteNum*8 + $bit] = 1; } } return (count($deletions) > 0) ? $deletions : null; } } while ($delFile->tell() < $delFileSize); } else { $byteCount = ceil($format/8); $bitCount = $delFile->readInt(); if ($bitCount == 0) { $delBytes = ''; } else { $delBytes = $delFile->readBytes($byteCount); } if (extension_loaded('bitset')) { return $delBytes; } else { $deletions = array(); for ($count = 0; $count < $byteCount; $count++) { $byte = ord($delBytes[$count]); for ($bit = 0; $bit < 8; $bit++) { if ($byte & (1<<$bit)) { $deletions[$count*8 + $bit] = 1; } } } return (count($deletions) > 0) ? $deletions : null; } } } public function openCompoundFile($extension, $shareHandler = true) { if (($extension == '.fdx' || $extension == '.fdt') && $this->_usesSharedDocStore) { $fdxFName = $this->_sharedDocStoreOptions['segment'] . '.fdx'; $fdtFName = $this->_sharedDocStoreOptions['segment'] . '.fdt'; if (!$this->_sharedDocStoreOptions['isCompound']) { $fdxFile = $this->_directory->getFileObject($fdxFName, $shareHandler); $fdxFile->seek($this->_sharedDocStoreOptions['offset']*8, SEEK_CUR); if ($extension == '.fdx') { return $fdxFile; } else { $fdtStartOffset = $fdxFile->readLong(); $fdtFile = $this->_directory->getFileObject($fdtFName, $shareHandler); $fdtFile->seek($fdtStartOffset, SEEK_CUR); return $fdtFile; } } if( !isset($this->_sharedDocStoreOptions['files'][$fdxFName]) ) {  throw new Zend_Search_Lucene_Exception('Shared doc storage segment compound file doesn\'t contain ' . $fdxFName . ' file.' ); } if( !isset($this->_sharedDocStoreOptions['files'][$fdtFName]) ) {  throw new Zend_Search_Lucene_Exception('Shared doc storage segment compound file doesn\'t contain ' . $fdtFName . ' file.' ); } $cfxFile = $this->_directory->getFileObject($this->_sharedDocStoreOptions['segment'] . '.cfx', $shareHandler); $cfxFile->seek($this->_sharedDocStoreOptions['files'][$fdxFName]); $cfxFile->seek($this->_sharedDocStoreOptions['offset']*8, SEEK_CUR); if ($extension == '.fdx') { return $cfxFile; } else { $fdtStartOffset = $cfxFile->readLong(); $cfxFile->seek($this->_sharedDocStoreOptions['files'][$fdtFName]); $cfxFile->seek($fdtStartOffset, SEEK_CUR); return $fdtFile; } } $filename = $this->_name . $extension; if (!$this->_isCompound) { return $this->_directory->getFileObject($filename, $shareHandler); } if( !isset($this->_segFiles[$filename]) ) {  throw new Zend_Search_Lucene_Exception('Segment compound file doesn\'t contain ' . $filename . ' file.' ); } $file = $this->_directory->getFileObject($this->_name . '.cfs', $shareHandler); $file->seek($this->_segFiles[$filename]); return $file; } public function compoundFileLength($extension) { if (($extension == '.fdx' || $extension == '.fdt') && $this->_usesSharedDocStore) { $filename = $this->_sharedDocStoreOptions['segment'] . $extension; if (!$this->_sharedDocStoreOptions['isCompound']) { return $this->_directory->fileLength($filename); } if( !isset($this->_sharedDocStoreOptions['fileSizes'][$filename]) ) {  throw new Zend_Search_Lucene_Exception('Shared doc store compound file doesn\'t contain ' . $filename . ' file.' ); } return $this->_sharedDocStoreOptions['fileSizes'][$filename]; } $filename = $this->_name . $extension; if ($this->_directory->fileExists($filename)) { return $this->_directory->fileLength($filename); } if( !isset($this->_segFileSizes[$filename]) ) {  throw new Zend_Search_Lucene_Exception('Index compound file doesn\'t contain ' . $filename . ' file.' ); } return $this->_segFileSizes[$filename]; } public function getFieldNum($fieldName) { foreach( $this->_fields as $field ) { if( $field->name == $fieldName ) { return $field->number; } } return -1; } public function getField($fieldNum) { return $this->_fields[$fieldNum]; } public function getFields($indexed = false) { $result = array(); foreach( $this->_fields as $field ) { if( (!$indexed) || $field->isIndexed ) { $result[ $field->name ] = $field->name; } } return $result; } public function getFieldInfos() { return $this->_fields; } public function getDelGen() { return $this->_delGen; } public function count() { return $this->_docCount; } private function _deletedCount() { if ($this->_deleted === null) { return 0; } if (extension_loaded('bitset')) { return count(bitset_to_array($this->_deleted)); } else { return count($this->_deleted); } } public function numDocs() { if ($this->hasDeletions()) { return $this->_docCount - $this->_deletedCount(); } else { return $this->_docCount; } } private function _getFieldPosition($fieldNum) { return isset($this->_fieldsDicPositions[$fieldNum]) ? $this->_fieldsDicPositions[$fieldNum] : $fieldNum; } public function getName() { return $this->_name; } private $_termInfoCache = array(); private function _cleanUpTermInfoCache() { foreach ($this->_termInfoCache as $key => $termInfo) { unset($this->_termInfoCache[$key]); if (count($this->_termInfoCache) == 768) { break; } } } private function _loadDictionaryIndex() { if ($this->_directory->fileExists($this->_name . '.sti')) { $stiFile = $this->_directory->getFileObject($this->_name . '.sti'); $stiFileData = $stiFile->readBytes($this->_directory->fileLength($this->_name . '.sti')); if (($unserializedData = @unserialize($stiFileData)) !== false) { list($this->_termDictionary, $this->_termDictionaryInfos) = $unserializedData; return; } } $tiiFile = $this->openCompoundFile('.tii'); $tiiFileData = $tiiFile->readBytes($this->compoundFileLength('.tii'));  list($this->_termDictionary, $this->_termDictionaryInfos) = Zend_Search_Lucene_Index_DictionaryLoader::load($tiiFileData); $stiFileData = serialize(array($this->_termDictionary, $this->_termDictionaryInfos)); $stiFile = $this->_directory->createFile($this->_name . '.sti'); $stiFile->writeBytes($stiFileData); } public function getTermInfo(Zend_Search_Lucene_Index_Term $term) { $termKey = $term->key(); if (isset($this->_termInfoCache[$termKey])) { $termInfo = $this->_termInfoCache[$termKey]; unset($this->_termInfoCache[$termKey]); $this->_termInfoCache[$termKey] = $termInfo; return $termInfo; } if ($this->_termDictionary === null) { $this->_loadDictionaryIndex(); } $searchField = $this->getFieldNum($term->field); if ($searchField == -1) { return null; } $searchDicField = $this->_getFieldPosition($searchField); $lowIndex = 0; $highIndex = count($this->_termDictionary)-1; while ($highIndex >= $lowIndex) { $mid = ($highIndex + $lowIndex) >> 1; $midTerm = $this->_termDictionary[$mid]; $fieldNum = $this->_getFieldPosition($midTerm[0] ); $delta = $searchDicField - $fieldNum; if ($delta == 0) { $delta = strcmp($term->text, $midTerm[1] ); } if ($delta < 0) { $highIndex = $mid-1; } elseif ($delta > 0) { $lowIndex = $mid+1; } else { $a = $this->_termDictionaryInfos[$mid]; $termInfo = new Zend_Search_Lucene_Index_TermInfo($a[0], $a[1], $a[2], $a[3], $a[4]); $this->_termInfoCache[$termKey] = $termInfo; return $termInfo; } } if ($highIndex == -1) { return null; } $prevPosition = $highIndex; $prevTerm = $this->_termDictionary[$prevPosition]; $prevTermInfo = $this->_termDictionaryInfos[$prevPosition]; $tisFile = $this->openCompoundFile('.tis'); $tiVersion = $tisFile->readInt(); if ($tiVersion != (int)0xFFFFFFFE && $tiVersion != (int)0xFFFFFFFD ) {  throw new Zend_Search_Lucene_Exception('Wrong TermInfoFile file format'); } $termCount = $tisFile->readLong(); $indexInterval = $tisFile->readInt(); $skipInterval = $tisFile->readInt(); if ($tiVersion == (int)0xFFFFFFFD ) { $maxSkipLevels = $tisFile->readInt(); } $tisFile->seek($prevTermInfo[4] - (($tiVersion == (int)0xFFFFFFFD)? 24 : 20) , SEEK_CUR); $termValue = $prevTerm[1] ; $termFieldNum = $prevTerm[0] ; $freqPointer = $prevTermInfo[1] ; $proxPointer = $prevTermInfo[2] ; for ($count = $prevPosition*$indexInterval + 1; $count <= $termCount && ( $this->_getFieldPosition($termFieldNum) < $searchDicField || ($this->_getFieldPosition($termFieldNum) == $searchDicField && strcmp($termValue, $term->text) < 0) ); $count++) { $termPrefixLength = $tisFile->readVInt(); $termSuffix = $tisFile->readString(); $termFieldNum = $tisFile->readVInt(); $termValue = Zend_Search_Lucene_Index_Term::getPrefix($termValue, $termPrefixLength) . $termSuffix; $docFreq = $tisFile->readVInt(); $freqPointer += $tisFile->readVInt(); $proxPointer += $tisFile->readVInt(); if( $docFreq >= $skipInterval ) { $skipOffset = $tisFile->readVInt(); } else { $skipOffset = 0; } } if ($termFieldNum == $searchField && $termValue == $term->text) { $termInfo = new Zend_Search_Lucene_Index_TermInfo($docFreq, $freqPointer, $proxPointer, $skipOffset); } else { $termInfo = null; } $this->_termInfoCache[$termKey] = $termInfo; if (count($this->_termInfoCache) == 1024) { $this->_cleanUpTermInfoCache(); } return $termInfo; } public function termDocs(Zend_Search_Lucene_Index_Term $term, $shift = 0, $docsFilter = null) { $termInfo = $this->getTermInfo($term); if (!$termInfo instanceof Zend_Search_Lucene_Index_TermInfo) { if ($docsFilter !== null && $docsFilter instanceof Zend_Search_Lucene_Index_DocsFilter) { $docsFilter->segmentFilters[$this->_name] = array(); } return array(); } $frqFile = $this->openCompoundFile('.frq'); $frqFile->seek($termInfo->freqPointer,SEEK_CUR); $docId = 0; $result = array(); if ($docsFilter !== null) { if (!$docsFilter instanceof Zend_Search_Lucene_Index_DocsFilter) {  throw new Zend_Search_Lucene_Exception('Documents filter must be an instance of Zend_Search_Lucene_Index_DocsFilter or null.'); } if (isset($docsFilter->segmentFilters[$this->_name])) { $filter = &$docsFilter->segmentFilters[$this->_name]; if (count($filter) == 0) { return array(); } if ($this->_docCount/count($filter) < self::FULL_SCAN_VS_FETCH_BOUNDARY) { $updatedFilterData = array(); for( $count=0; $count < $termInfo->docFreq; $count++ ) { $docDelta = $frqFile->readVInt(); if( $docDelta % 2 == 1 ) { $docId += ($docDelta-1)/2; } else { $docId += $docDelta/2; $frqFile->readVInt(); } if (isset($filter[$docId])) { $result[] = $shift + $docId; $updatedFilterData[$docId] = 1; } } $docsFilter->segmentFilters[$this->_name] = $updatedFilterData; } else { $updatedFilterData = array(); for( $count=0; $count < $termInfo->docFreq; $count++ ) { $docDelta = $frqFile->readVInt(); if( $docDelta % 2 == 1 ) { $docId += ($docDelta-1)/2; } else { $docId += $docDelta/2; $frqFile->readVInt(); } if (isset($filter[$docId])) { $result[] = $shift + $docId; $updatedFilterData[$docId] = 1; } } $docsFilter->segmentFilters[$this->_name] = $updatedFilterData; } } else { $filterData = array(); for( $count=0; $count < $termInfo->docFreq; $count++ ) { $docDelta = $frqFile->readVInt(); if( $docDelta % 2 == 1 ) { $docId += ($docDelta-1)/2; } else { $docId += $docDelta/2; $frqFile->readVInt(); } $result[] = $shift + $docId; $filterData[$docId] = 1; } $docsFilter->segmentFilters[$this->_name] = $filterData; } } else { for( $count=0; $count < $termInfo->docFreq; $count++ ) { $docDelta = $frqFile->readVInt(); if( $docDelta % 2 == 1 ) { $docId += ($docDelta-1)/2; } else { $docId += $docDelta/2; $frqFile->readVInt(); } $result[] = $shift + $docId; } } return $result; } public function termFreqs(Zend_Search_Lucene_Index_Term $term, $shift = 0, $docsFilter = null) { $termInfo = $this->getTermInfo($term); if (!$termInfo instanceof Zend_Search_Lucene_Index_TermInfo) { if ($docsFilter !== null && $docsFilter instanceof Zend_Search_Lucene_Index_DocsFilter) { $docsFilter->segmentFilters[$this->_name] = array(); } return array(); } $frqFile = $this->openCompoundFile('.frq'); $frqFile->seek($termInfo->freqPointer,SEEK_CUR); $result = array(); $docId = 0; $result = array(); if ($docsFilter !== null) { if (!$docsFilter instanceof Zend_Search_Lucene_Index_DocsFilter) {  throw new Zend_Search_Lucene_Exception('Documents filter must be an instance of Zend_Search_Lucene_Index_DocsFilter or null.'); } if (isset($docsFilter->segmentFilters[$this->_name])) { $filter = &$docsFilter->segmentFilters[$this->_name]; if (count($filter) == 0) { return array(); } if ($this->_docCount/count($filter) < self::FULL_SCAN_VS_FETCH_BOUNDARY) { $updatedFilterData = array(); for ($count = 0; $count < $termInfo->docFreq; $count++) { $docDelta = $frqFile->readVInt(); if ($docDelta % 2 == 1) { $docId += ($docDelta-1)/2; if (isset($filter[$docId])) { $result[$shift + $docId] = 1; $updatedFilterData[$docId] = 1; } } else { $docId += $docDelta/2; $freq = $frqFile->readVInt(); if (isset($filter[$docId])) { $result[$shift + $docId] = $freq; $updatedFilterData[$docId] = 1; } } } $docsFilter->segmentFilters[$this->_name] = $updatedFilterData; } else { $updatedFilterData = array(); for ($count = 0; $count < $termInfo->docFreq; $count++) { $docDelta = $frqFile->readVInt(); if ($docDelta % 2 == 1) { $docId += ($docDelta-1)/2; if (isset($filter[$docId])) { $result[$shift + $docId] = 1; $updatedFilterData[$docId] = 1; } } else { $docId += $docDelta/2; $freq = $frqFile->readVInt(); if (isset($filter[$docId])) { $result[$shift + $docId] = $freq; $updatedFilterData[$docId] = 1; } } } $docsFilter->segmentFilters[$this->_name] = $updatedFilterData; } } else { $filterData = array(); for ($count = 0; $count < $termInfo->docFreq; $count++) { $docDelta = $frqFile->readVInt(); if ($docDelta % 2 == 1) { $docId += ($docDelta-1)/2; $result[$shift + $docId] = 1; $filterData[$docId] = 1; } else { $docId += $docDelta/2; $result[$shift + $docId] = $frqFile->readVInt(); $filterData[$docId] = 1; } } $docsFilter->segmentFilters[$this->_name] = $filterData; } } else { for ($count = 0; $count < $termInfo->docFreq; $count++) { $docDelta = $frqFile->readVInt(); if ($docDelta % 2 == 1) { $docId += ($docDelta-1)/2; $result[$shift + $docId] = 1; } else { $docId += $docDelta/2; $result[$shift + $docId] = $frqFile->readVInt(); } } } return $result; } public function termPositions(Zend_Search_Lucene_Index_Term $term, $shift = 0, $docsFilter = null) { $termInfo = $this->getTermInfo($term); if (!$termInfo instanceof Zend_Search_Lucene_Index_TermInfo) { if ($docsFilter !== null && $docsFilter instanceof Zend_Search_Lucene_Index_DocsFilter) { $docsFilter->segmentFilters[$this->_name] = array(); } return array(); } $frqFile = $this->openCompoundFile('.frq'); $frqFile->seek($termInfo->freqPointer,SEEK_CUR); $docId = 0; $freqs = array(); if ($docsFilter !== null) { if (!$docsFilter instanceof Zend_Search_Lucene_Index_DocsFilter) {  throw new Zend_Search_Lucene_Exception('Documents filter must be an instance of Zend_Search_Lucene_Index_DocsFilter or null.'); } if (isset($docsFilter->segmentFilters[$this->_name])) { $filter = &$docsFilter->segmentFilters[$this->_name]; if (count($filter) == 0) { return array(); } if ($this->_docCount/count($filter) < self::FULL_SCAN_VS_FETCH_BOUNDARY) { for ($count = 0; $count < $termInfo->docFreq; $count++) { $docDelta = $frqFile->readVInt(); if ($docDelta % 2 == 1) { $docId += ($docDelta-1)/2; $freqs[$docId] = 1; } else { $docId += $docDelta/2; $freqs[$docId] = $frqFile->readVInt(); } } $updatedFilterData = array(); $result = array(); $prxFile = $this->openCompoundFile('.prx'); $prxFile->seek($termInfo->proxPointer, SEEK_CUR); foreach ($freqs as $docId => $freq) { $termPosition = 0; $positions = array(); for ($count = 0; $count < $freq; $count++ ) { $termPosition += $prxFile->readVInt(); $positions[] = $termPosition; } if (isset($filter[$docId])) { $updatedFilterData[$docId] = 1; $result[$shift + $docId] = $positions; } } $docsFilter->segmentFilters[$this->_name] = $updatedFilterData; } else { for ($count = 0; $count < $termInfo->docFreq; $count++) { $docDelta = $frqFile->readVInt(); if ($docDelta % 2 == 1) { $docId += ($docDelta-1)/2; $freqs[$docId] = 1; } else { $docId += $docDelta/2; $freqs[$docId] = $frqFile->readVInt(); } } $updatedFilterData = array(); $result = array(); $prxFile = $this->openCompoundFile('.prx'); $prxFile->seek($termInfo->proxPointer, SEEK_CUR); foreach ($freqs as $docId => $freq) { $termPosition = 0; $positions = array(); for ($count = 0; $count < $freq; $count++ ) { $termPosition += $prxFile->readVInt(); $positions[] = $termPosition; } if (isset($filter[$docId])) { $updatedFilterData[$docId] = 1; $result[$shift + $docId] = $positions; } } $docsFilter->segmentFilters[$this->_name] = $updatedFilterData; } } else { for ($count = 0; $count < $termInfo->docFreq; $count++) { $docDelta = $frqFile->readVInt(); if ($docDelta % 2 == 1) { $docId += ($docDelta-1)/2; $freqs[$docId] = 1; } else { $docId += $docDelta/2; $freqs[$docId] = $frqFile->readVInt(); } } $filterData = array(); $result = array(); $prxFile = $this->openCompoundFile('.prx'); $prxFile->seek($termInfo->proxPointer, SEEK_CUR); foreach ($freqs as $docId => $freq) { $filterData[$docId] = 1; $termPosition = 0; $positions = array(); for ($count = 0; $count < $freq; $count++ ) { $termPosition += $prxFile->readVInt(); $positions[] = $termPosition; } $result[$shift + $docId] = $positions; } $docsFilter->segmentFilters[$this->_name] = $filterData; } } else { for ($count = 0; $count < $termInfo->docFreq; $count++) { $docDelta = $frqFile->readVInt(); if ($docDelta % 2 == 1) { $docId += ($docDelta-1)/2; $freqs[$docId] = 1; } else { $docId += $docDelta/2; $freqs[$docId] = $frqFile->readVInt(); } } $result = array(); $prxFile = $this->openCompoundFile('.prx'); $prxFile->seek($termInfo->proxPointer, SEEK_CUR); foreach ($freqs as $docId => $freq) { $termPosition = 0; $positions = array(); for ($count = 0; $count < $freq; $count++ ) { $termPosition += $prxFile->readVInt(); $positions[] = $termPosition; } $result[$shift + $docId] = $positions; } } return $result; } private function _loadNorm($fieldNum) { if ($this->_hasSingleNormFile) { $normfFile = $this->openCompoundFile('.nrm'); $header = $normfFile->readBytes(3); $headerFormatVersion = $normfFile->readByte(); if ($header != 'NRM' || $headerFormatVersion != (int)0xFF) {  throw new Zend_Search_Lucene_Exception('Wrong norms file format.'); } foreach ($this->_fields as $fNum => $fieldInfo) { if ($fieldInfo->isIndexed) { $this->_norms[$fNum] = $normfFile->readBytes($this->_docCount); } } } else { $fFile = $this->openCompoundFile('.f' . $fieldNum); $this->_norms[$fieldNum] = $fFile->readBytes($this->_docCount); } } public function norm($id, $fieldName) { $fieldNum = $this->getFieldNum($fieldName); if ( !($this->_fields[$fieldNum]->isIndexed) ) { return null; } if (!isset($this->_norms[$fieldNum])) { $this->_loadNorm($fieldNum); } return Zend_Search_Lucene_Search_Similarity::decodeNorm( ord($this->_norms[$fieldNum][$id]) ); } public function normVector($fieldName) { $fieldNum = $this->getFieldNum($fieldName); if ($fieldNum == -1 || !($this->_fields[$fieldNum]->isIndexed)) { $similarity = Zend_Search_Lucene_Search_Similarity::getDefault(); return str_repeat(chr($similarity->encodeNorm( $similarity->lengthNorm($fieldName, 0) )), $this->_docCount); } if (!isset($this->_norms[$fieldNum])) { $this->_loadNorm($fieldNum); } return $this->_norms[$fieldNum]; } public function hasDeletions() { return $this->_deleted !== null; } public function hasSingleNormFile() { return $this->_hasSingleNormFile ? true : false; } public function isCompound() { return $this->_isCompound; } public function delete($id) { $this->_deletedDirty = true; if (extension_loaded('bitset')) { if ($this->_deleted === null) { $this->_deleted = bitset_empty($id); } bitset_incl($this->_deleted, $id); } else { if ($this->_deleted === null) { $this->_deleted = array(); } $this->_deleted[$id] = 1; } } public function isDeleted($id) { if ($this->_deleted === null) { return false; } if (extension_loaded('bitset')) { return bitset_in($this->_deleted, $id); } else { return isset($this->_deleted[$id]); } } private function _detectLatestDelGen() { $delFileList = array(); foreach ($this->_directory->fileList() as $file) { if ($file == $this->_name . '.del') { $delFileList[] = 0; } else if (preg_match('/^' . $this->_name . '_([a-zA-Z0-9]+)\.del$/i', $file, $matches)) { $delFileList[] = (int)base_convert($matches[1], 36, 10); } } if (count($delFileList) == 0) { return -1; } else { return max($delFileList); } } public function writeChanges() { $latestDelGen = $this->_detectLatestDelGen(); if (!$this->_deletedDirty) { if ($latestDelGen == $this->_delGen) { return; } else if ($latestDelGen > $this->_delGen) { $this->_delGen = $latestDelGen; $this->_deleted = $this->_loadDelFile(); return; } else {  throw new Zend_Search_Lucene_Exception('Delete file processing workflow is corrupted for the segment \'' . $this->_name . '\'.'); } } if ($latestDelGen > $this->_delGen) { $this->_delGen = $latestDelGen; $latestDelete = $this->_loadDelFile(); if (extension_loaded('bitset')) { $this->_deleted = bitset_union($this->_deleted, $latestDelete); } else { $this->_deleted += $latestDelete; } } if (extension_loaded('bitset')) { $delBytes = $this->_deleted; $bitCount = count(bitset_to_array($delBytes)); } else { $byteCount = floor($this->_docCount/8)+1; $delBytes = str_repeat(chr(0), $byteCount); for ($count = 0; $count < $byteCount; $count++) { $byte = 0; for ($bit = 0; $bit < 8; $bit++) { if (isset($this->_deleted[$count*8 + $bit])) { $byte |= (1<<$bit); } } $delBytes[$count] = chr($byte); } $bitCount = count($this->_deleted); } if ($this->_delGen == -1) { $this->_delGen = 1; } else { $this->_delGen++; } $delFile = $this->_directory->createFile($this->_name . '_' . base_convert($this->_delGen, 10, 36) . '.del'); $delFile->writeInt($this->_docCount); $delFile->writeInt($bitCount); $delFile->writeBytes($delBytes); $this->_deletedDirty = false; } private $_tisFile = null; private $_tisFileOffset; private $_frqFile = null; private $_frqFileOffset; private $_prxFile = null; private $_prxFileOffset; private $_termCount = 0; private $_termNum = 0; private $_indexInterval; private $_skipInterval; private $_lastTermInfo = null; private $_lastTerm = null; private $_docMap = null; private $_lastTermPositions; private $_termsScanMode; const SM_TERMS_ONLY = 0; const SM_FULL_INFO = 1; const SM_MERGE_INFO = 2; public function resetTermsStream() { $argList = func_get_args(); if (count($argList) > 2) {  throw new Zend_Search_Lucene_Exception('Wrong number of arguments'); } else if (count($argList) == 2) { $startId = $argList[0]; $mode = $argList[1]; } else if (count($argList) == 1) { $startId = $argList[0]; $mode = self::SM_TERMS_ONLY; } else { $startId = 0; $mode = self::SM_TERMS_ONLY; } if ($this->_tisFile !== null) { $this->_tisFile = null; } $this->_tisFile = $this->openCompoundFile('.tis', false); $this->_tisFileOffset = $this->_tisFile->tell(); $tiVersion = $this->_tisFile->readInt(); if ($tiVersion != (int)0xFFFFFFFE && $tiVersion != (int)0xFFFFFFFD ) {  throw new Zend_Search_Lucene_Exception('Wrong TermInfoFile file format'); } $this->_termCount = $this->_termNum = $this->_tisFile->readLong(); $this->_indexInterval = $this->_tisFile->readInt(); $this->_skipInterval = $this->_tisFile->readInt(); if ($tiVersion == (int)0xFFFFFFFD ) { $maxSkipLevels = $this->_tisFile->readInt(); } if ($this->_frqFile !== null) { $this->_frqFile = null; } if ($this->_prxFile !== null) { $this->_prxFile = null; } $this->_docMap = array(); $this->_lastTerm = new Zend_Search_Lucene_Index_Term('', -1); $this->_lastTermInfo = new Zend_Search_Lucene_Index_TermInfo(0, 0, 0, 0); $this->_lastTermPositions = null; $this->_termsScanMode = $mode; switch ($mode) { case self::SM_TERMS_ONLY: break; case self::SM_FULL_INFO: case self::SM_MERGE_INFO: $this->_frqFile = $this->openCompoundFile('.frq', false); $this->_frqFileOffset = $this->_frqFile->tell(); $this->_prxFile = $this->openCompoundFile('.prx', false); $this->_prxFileOffset = $this->_prxFile->tell(); for ($count = 0; $count < $this->_docCount; $count++) { if (!$this->isDeleted($count)) { $this->_docMap[$count] = $startId + (($mode == self::SM_MERGE_INFO) ? count($this->_docMap) : $count); } } break; default:  throw new Zend_Search_Lucene_Exception('Wrong terms scaning mode specified.'); break; } $nextSegmentStartId = $startId + (($mode == self::SM_MERGE_INFO) ? count($this->_docMap) : $this->_docCount); $this->nextTerm(); return $nextSegmentStartId; } public function skipTo(Zend_Search_Lucene_Index_Term $prefix) { if ($this->_termDictionary === null) { $this->_loadDictionaryIndex(); } $searchField = $this->getFieldNum($prefix->field); if ($searchField == -1) { $this->_tisFile = null; $this->_frqFile = null; $this->_prxFile = null; $this->_lastTerm = null; $this->_lastTermInfo = null; $this->_lastTermPositions = null; return; } $searchDicField = $this->_getFieldPosition($searchField); $lowIndex = 0; $highIndex = count($this->_termDictionary)-1; while ($highIndex >= $lowIndex) { $mid = ($highIndex + $lowIndex) >> 1; $midTerm = $this->_termDictionary[$mid]; $fieldNum = $this->_getFieldPosition($midTerm[0] ); $delta = $searchDicField - $fieldNum; if ($delta == 0) { $delta = strcmp($prefix->text, $midTerm[1] ); } if ($delta < 0) { $highIndex = $mid-1; } elseif ($delta > 0) { $lowIndex = $mid+1; } else { break; } } if ($highIndex == -1) { $this->_tisFile = null; $this->_frqFile = null; $this->_prxFile = null; $this->_lastTerm = null; $this->_lastTermInfo = null; $this->_lastTermPositions = null; return; } $prevPosition = $highIndex; $prevTerm = $this->_termDictionary[$prevPosition]; $prevTermInfo = $this->_termDictionaryInfos[$prevPosition]; if ($this->_tisFile === null) { $this->_tisFile = $this->openCompoundFile('.tis', false); if ($this->_termsScanMode == self::SM_FULL_INFO || $this->_termsScanMode == self::SM_MERGE_INFO) { $this->_frqFile = $this->openCompoundFile('.frq', false); $this->_prxFile = $this->openCompoundFile('.prx', false); } } $this->_tisFile->seek($this->_tisFileOffset + $prevTermInfo[4], SEEK_SET); $this->_lastTerm = new Zend_Search_Lucene_Index_Term($prevTerm[1] , ($prevTerm[0] == -1) ? '' : $this->_fields[$prevTerm[0] ]->name); $this->_lastTermInfo = new Zend_Search_Lucene_Index_TermInfo($prevTermInfo[0] , $prevTermInfo[1] , $prevTermInfo[2] , $prevTermInfo[3] ); $this->_termCount = $this->_termNum - $prevPosition*$this->_indexInterval; if ($highIndex == 0) { $this->nextTerm(); } else if ($prefix->field == $this->_lastTerm->field && $prefix->text == $this->_lastTerm->text) { if ($this->_termsScanMode == self::SM_FULL_INFO || $this->_termsScanMode == self::SM_MERGE_INFO) { $this->_lastTermPositions = array(); $this->_frqFile->seek($this->_lastTermInfo->freqPointer + $this->_frqFileOffset, SEEK_SET); $freqs = array(); $docId = 0; for( $count = 0; $count < $this->_lastTermInfo->docFreq; $count++ ) { $docDelta = $this->_frqFile->readVInt(); if( $docDelta % 2 == 1 ) { $docId += ($docDelta-1)/2; $freqs[ $docId ] = 1; } else { $docId += $docDelta/2; $freqs[ $docId ] = $this->_frqFile->readVInt(); } } $this->_prxFile->seek($this->_lastTermInfo->proxPointer + $this->_prxFileOffset, SEEK_SET); foreach ($freqs as $docId => $freq) { $termPosition = 0; $positions = array(); for ($count = 0; $count < $freq; $count++ ) { $termPosition += $this->_prxFile->readVInt(); $positions[] = $termPosition; } if (isset($this->_docMap[$docId])) { $this->_lastTermPositions[$this->_docMap[$docId]] = $positions; } } } return; } while ($this->_lastTerm !== null) { if ( strcmp($this->_lastTerm->field, $prefix->field) > 0 || ($prefix->field == $this->_lastTerm->field && strcmp($this->_lastTerm->text, $prefix->text) >= 0) ) { return; } $this->nextTerm(); } } public function nextTerm() { if ($this->_tisFile === null || $this->_termCount == 0) { $this->_lastTerm = null; $this->_lastTermInfo = null; $this->_lastTermPositions = null; $this->_docMap = null; $this->_tisFile = null; $this->_frqFile = null; $this->_prxFile = null; return null; } $termPrefixLength = $this->_tisFile->readVInt(); $termSuffix = $this->_tisFile->readString(); $termFieldNum = $this->_tisFile->readVInt(); $termValue = Zend_Search_Lucene_Index_Term::getPrefix($this->_lastTerm->text, $termPrefixLength) . $termSuffix; $this->_lastTerm = new Zend_Search_Lucene_Index_Term($termValue, $this->_fields[$termFieldNum]->name); $docFreq = $this->_tisFile->readVInt(); $freqPointer = $this->_lastTermInfo->freqPointer + $this->_tisFile->readVInt(); $proxPointer = $this->_lastTermInfo->proxPointer + $this->_tisFile->readVInt(); if ($docFreq >= $this->_skipInterval) { $skipOffset = $this->_tisFile->readVInt(); } else { $skipOffset = 0; } $this->_lastTermInfo = new Zend_Search_Lucene_Index_TermInfo($docFreq, $freqPointer, $proxPointer, $skipOffset); if ($this->_termsScanMode == self::SM_FULL_INFO || $this->_termsScanMode == self::SM_MERGE_INFO) { $this->_lastTermPositions = array(); $this->_frqFile->seek($this->_lastTermInfo->freqPointer + $this->_frqFileOffset, SEEK_SET); $freqs = array(); $docId = 0; for( $count = 0; $count < $this->_lastTermInfo->docFreq; $count++ ) { $docDelta = $this->_frqFile->readVInt(); if( $docDelta % 2 == 1 ) { $docId += ($docDelta-1)/2; $freqs[ $docId ] = 1; } else { $docId += $docDelta/2; $freqs[ $docId ] = $this->_frqFile->readVInt(); } } $this->_prxFile->seek($this->_lastTermInfo->proxPointer + $this->_prxFileOffset, SEEK_SET); foreach ($freqs as $docId => $freq) { $termPosition = 0; $positions = array(); for ($count = 0; $count < $freq; $count++ ) { $termPosition += $this->_prxFile->readVInt(); $positions[] = $termPosition; } if (isset($this->_docMap[$docId])) { $this->_lastTermPositions[$this->_docMap[$docId]] = $positions; } } } $this->_termCount--; if ($this->_termCount == 0) { $this->_tisFile = null; $this->_frqFile = null; $this->_prxFile = null; } return $this->_lastTerm; } public function closeTermsStream() { $this->_tisFile = null; $this->_frqFile = null; $this->_prxFile = null; $this->_lastTerm = null; $this->_lastTermInfo = null; $this->_lastTermPositions = null; $this->_docMap = null; } public function currentTerm() { return $this->_lastTerm; } public function currentTermPositions() { return $this->_lastTermPositions; } } 
abstract class Zend_Search_Lucene_Storage_Directory { abstract public function close(); abstract public function fileList(); abstract public function createFile($filename); abstract public function deleteFile($filename); abstract public function purgeFile($filename); abstract public function fileExists($filename); abstract public function fileLength($filename); abstract public function fileModified($filename); abstract public function renameFile($from, $to); abstract public function touchFile($filename); abstract public function getFileObject($filename, $shareHandler = true); } 
abstract class Zend_Search_Lucene_Storage_File { abstract protected function _fread($length=1); abstract public function seek($offset, $whence=SEEK_SET); abstract public function tell(); abstract public function flush(); abstract protected function _fwrite($data, $length=null); abstract public function lock($lockType, $nonBlockinLock = false); abstract public function unlock(); public function readByte() { return ord($this->_fread(1)); } public function writeByte($byte) { return $this->_fwrite(chr($byte), 1); } public function readBytes($num) { return $this->_fread($num); } public function writeBytes($data, $num=null) { $this->_fwrite($data, $num); } public function readInt() { $str = $this->_fread(4); return ord($str[0]) << 24 | ord($str[1]) << 16 | ord($str[2]) << 8 | ord($str[3]); } public function writeInt($value) { settype($value, 'integer'); $this->_fwrite( chr($value>>24 & 0xFF) . chr($value>>16 & 0xFF) . chr($value>>8 & 0xFF) . chr($value & 0xFF), 4 ); } public function readLong() { if (PHP_INT_SIZE > 4) { $str = $this->_fread(8); return ord($str[0]) << 56 | ord($str[1]) << 48 | ord($str[2]) << 40 | ord($str[3]) << 32 | ord($str[4]) << 24 | ord($str[5]) << 16 | ord($str[6]) << 8 | ord($str[7]); } else { return $this->readLong32Bit(); } } public function writeLong($value) { if (PHP_INT_SIZE > 4) { settype($value, 'integer'); $this->_fwrite( chr($value>>56 & 0xFF) . chr($value>>48 & 0xFF) . chr($value>>40 & 0xFF) . chr($value>>32 & 0xFF) . chr($value>>24 & 0xFF) . chr($value>>16 & 0xFF) . chr($value>>8 & 0xFF) . chr($value & 0xFF), 8 ); } else { $this->writeLong32Bit($value); } } public function readLong32Bit() { $wordHigh = $this->readInt(); $wordLow = $this->readInt(); if ($wordHigh & (int)0x80000000) { if ($wordHigh == (int)0xFFFFFFFF && ($wordLow & (int)0x80000000)) { return $wordLow; } else {  throw new Zend_Search_Lucene_Exception('Long integers lower than -2147483648 (0x80000000) are not supported on 32-bit platforms.'); } } if ($wordLow < 0) { $wordLow &= 0x7FFFFFFF; $wordLow += (float)0x80000000; } if ($wordHigh == 0) { return $wordLow; } return $wordHigh*(float)0x100000000 + $wordLow; } public function writeLong32Bit($value) { if ($value < (int)0x80000000) {  throw new Zend_Search_Lucene_Exception('Long integers lower than -2147483648 (0x80000000) are not supported on 32-bit platforms.'); } if ($value < 0) { $wordHigh = (int)0xFFFFFFFF; $wordLow = (int)$value; } else { $wordHigh = (int)($value/(float)0x100000000); $wordLow = $value - $wordHigh*(float)0x100000000; if ($wordLow > 0x7FFFFFFF) { $wordLow -= 0x80000000; $wordLow |= 0x80000000; } } $this->writeInt($wordHigh); $this->writeInt($wordLow); } public function readVInt() { $nextByte = ord($this->_fread(1)); $val = $nextByte & 0x7F; for ($shift=7; ($nextByte & 0x80) != 0; $shift += 7) { $nextByte = ord($this->_fread(1)); $val |= ($nextByte & 0x7F) << $shift; } return $val; } public function writeVInt($value) { settype($value, 'integer'); while ($value > 0x7F) { $this->_fwrite(chr( ($value & 0x7F)|0x80 )); $value >>= 7; } $this->_fwrite(chr($value)); } public function readString() { $strlen = $this->readVInt(); if ($strlen == 0) { return ''; } else { $str_val = $this->_fread($strlen); for ($count = 0; $count < $strlen; $count++ ) { if (( ord($str_val[$count]) & 0xC0 ) == 0xC0) { $addBytes = 1; if (ord($str_val[$count]) & 0x20 ) { $addBytes++; if (ord($str_val[$count]) & 0x10 ) { $addBytes++; } } $str_val .= $this->_fread($addBytes); $strlen += $addBytes; if (ord($str_val[$count]) == 0xC0 && ord($str_val[$count+1]) == 0x80 ) { $str_val[$count] = 0; $str_val = substr($str_val,0,$count+1) . substr($str_val,$count+2); } $count += $addBytes; } } return $str_val; } } public function writeString($str) { settype($str, 'string'); $chars = $strlen = strlen($str); $containNullChars = false; for ($count = 0; $count < $strlen; $count++ ) { if ((ord($str[$count]) & 0xC0) == 0xC0) { $addBytes = 1; if (ord($str[$count]) & 0x20 ) { $addBytes++; if (ord($str[$count]) & 0x10 ) { $addBytes++; } } $chars -= $addBytes; if (ord($str[$count]) == 0 ) { $containNullChars = true; } $count += $addBytes; } } if ($chars < 0) {  throw new Zend_Search_Lucene_Exception('Invalid UTF-8 string'); } $this->writeVInt($chars); if ($containNullChars) { $this->_fwrite(str_replace($str, "\x00", "\xC0\x80")); } else { $this->_fwrite($str); } } public function readBinary() { return $this->_fread($this->readVInt()); } } 
class Zend_Search_Lucene_LockManager { const WRITE_LOCK_FILE = 'write.lock.file'; const READ_LOCK_FILE = 'read.lock.file'; const READ_LOCK_PROCESSING_LOCK_FILE = 'read-lock-processing.lock.file'; const OPTIMIZATION_LOCK_FILE = 'optimization.lock.file'; public static function obtainWriteLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) { $lock = $lockDirectory->createFile(self::WRITE_LOCK_FILE); if (!$lock->lock(LOCK_EX)) {  throw new Zend_Search_Lucene_Exception('Can\'t obtain exclusive index lock'); } return $lock; } public static function releaseWriteLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) { $lock = $lockDirectory->getFileObject(self::WRITE_LOCK_FILE); $lock->unlock(); } private static function _startReadLockProcessing(Zend_Search_Lucene_Storage_Directory $lockDirectory) { $lock = $lockDirectory->createFile(self::READ_LOCK_PROCESSING_LOCK_FILE); if (!$lock->lock(LOCK_EX)) {  throw new Zend_Search_Lucene_Exception('Can\'t obtain exclusive lock for the read lock processing file'); } return $lock; } private static function _stopReadLockProcessing(Zend_Search_Lucene_Storage_Directory $lockDirectory) { $lock = $lockDirectory->getFileObject(self::READ_LOCK_PROCESSING_LOCK_FILE); $lock->unlock(); } public static function obtainReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) { $lock = $lockDirectory->createFile(self::READ_LOCK_FILE); if (!$lock->lock(LOCK_SH)) {  throw new Zend_Search_Lucene_Exception('Can\'t obtain shared reading index lock'); } return $lock; } public static function releaseReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) { $lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE); $lock->unlock(); } public static function escalateReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) { self::_startReadLockProcessing($lockDirectory); $lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE); $lock->unlock(); for ($retries = 0; $retries < 10; $retries++) { if ($lock->lock(LOCK_EX, true)) { self::_stopReadLockProcessing($lockDirectory); return true; } usleep(1); } $lock->lock(LOCK_SH); self::_stopReadLockProcessing($lockDirectory); return false; } public static function deEscalateReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) { $lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE); $lock->lock(LOCK_SH); } public static function obtainOptimizationLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) { $lock = $lockDirectory->createFile(self::OPTIMIZATION_LOCK_FILE); if (!$lock->lock(LOCK_EX, true)) { return false; } return $lock; } public static function releaseOptimizationLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) { $lock = $lockDirectory->getFileObject(self::OPTIMIZATION_LOCK_FILE); $lock->unlock(); } } 
class Zend_Search_Lucene_Storage_File_Filesystem extends Zend_Search_Lucene_Storage_File { protected $_fileHandle; public function __construct($filename, $mode='r+b') { global $php_errormsg; if (strpos($mode, 'w') === false && !is_readable($filename)) {  throw new Zend_Search_Lucene_Exception('File \'' . $filename . '\' is not readable.'); } $trackErrors = ini_get('track_errors'); ini_set('track_errors', '1'); $this->_fileHandle = @fopen($filename, $mode); if ($this->_fileHandle === false) { ini_set('track_errors', $trackErrors);  throw new Zend_Search_Lucene_Exception($php_errormsg); } ini_set('track_errors', $trackErrors); } public function seek($offset, $whence=SEEK_SET) { return fseek($this->_fileHandle, $offset, $whence); } public function tell() { return ftell($this->_fileHandle); } public function flush() { return fflush($this->_fileHandle); } public function close() { if ($this->_fileHandle !== null ) { @fclose($this->_fileHandle); $this->_fileHandle = null; } } public function size() { $position = ftell($this->_fileHandle); fseek($this->_fileHandle, 0, SEEK_END); $size = ftell($this->_fileHandle); fseek($this->_fileHandle,$position); return $size; } protected function _fread($length=1) { if ($length == 0) { return ''; } if ($length < 1024) { return fread($this->_fileHandle, $length); } $data = ''; while ($length > 0 && !feof($this->_fileHandle)) { $nextBlock = fread($this->_fileHandle, $length); if ($nextBlock === false) {  throw new Zend_Search_Lucene_Exception( "Error occured while file reading." ); } $data .= $nextBlock; $length -= strlen($nextBlock); } if ($length != 0) {  throw new Zend_Search_Lucene_Exception( "Error occured while file reading." ); } return $data; } protected function _fwrite($data, $length=null) { if ($length === null ) { fwrite($this->_fileHandle, $data); } else { fwrite($this->_fileHandle, $data, $length); } } public function lock($lockType, $nonBlockingLock = false) { if ($nonBlockingLock) { return flock($this->_fileHandle, $lockType | LOCK_NB); } else { return flock($this->_fileHandle, $lockType); } } public function unlock() { if ($this->_fileHandle !== null ) { return flock($this->_fileHandle, LOCK_UN); } else { return true; } } } 
class Zend_Search_Lucene_Storage_Directory_Filesystem extends Zend_Search_Lucene_Storage_Directory { protected $_dirPath = null; protected $_fileHandlers; protected static $_defaultFilePermissions = 0666; public static function getDefaultFilePermissions() { return self::$_defaultFilePermissions; } public static function setDefaultFilePermissions($mode) { self::$_defaultFilePermissions = $mode; } public static function mkdirs($dir, $mode = 0777, $recursive = true) { if (($dir === null) || $dir === '') { return false; } if (is_dir($dir) || $dir === '/') { return true; } if (self::mkdirs(dirname($dir), $mode, $recursive)) { return mkdir($dir, $mode); } return false; } public function __construct($path) { if (!is_dir($path)) { if (file_exists($path)) {  throw new Zend_Search_Lucene_Exception('Path exists, but it\'s not a directory'); } else { if (!self::mkdirs($path)) {  throw new Zend_Search_Lucene_Exception("Can't create directory '$path'."); } } } $this->_dirPath = $path; $this->_fileHandlers = array(); } public function close() { foreach ($this->_fileHandlers as $fileObject) { $fileObject->close(); } $this->_fileHandlers = array(); } public function fileList() { $result = array(); $dirContent = opendir( $this->_dirPath ); while (($file = readdir($dirContent)) !== false) { if (($file == '..')||($file == '.')) continue; if( !is_dir($this->_dirPath . '/' . $file) ) { $result[] = $file; } } closedir($dirContent); return $result; } public function createFile($filename) { if (isset($this->_fileHandlers[$filename])) { $this->_fileHandlers[$filename]->close(); } unset($this->_fileHandlers[$filename]);  $this->_fileHandlers[$filename] = new Zend_Search_Lucene_Storage_File_Filesystem($this->_dirPath . '/' . $filename, 'w+b'); @chmod($this->_dirPath . '/' . $filename, self::$_defaultFilePermissions); return $this->_fileHandlers[$filename]; } public function deleteFile($filename) { if (isset($this->_fileHandlers[$filename])) { $this->_fileHandlers[$filename]->close(); } unset($this->_fileHandlers[$filename]); global $php_errormsg; $trackErrors = ini_get('track_errors'); ini_set('track_errors', '1'); if (!@unlink($this->_dirPath . '/' . $filename)) { ini_set('track_errors', $trackErrors);  throw new Zend_Search_Lucene_Exception('Can\'t delete file: ' . $php_errormsg); } ini_set('track_errors', $trackErrors); } public function purgeFile($filename) { if (isset($this->_fileHandlers[$filename])) { $this->_fileHandlers[$filename]->close(); } unset($this->_fileHandlers[$filename]); } public function fileExists($filename) { return isset($this->_fileHandlers[$filename]) || file_exists($this->_dirPath . '/' . $filename); } public function fileLength($filename) { if (isset( $this->_fileHandlers[$filename] )) { return $this->_fileHandlers[$filename]->size(); } return filesize($this->_dirPath .'/'. $filename); } public function fileModified($filename) { return filemtime($this->_dirPath .'/'. $filename); } public function renameFile($from, $to) { global $php_errormsg; if (isset($this->_fileHandlers[$from])) { $this->_fileHandlers[$from]->close(); } unset($this->_fileHandlers[$from]); if (isset($this->_fileHandlers[$to])) { $this->_fileHandlers[$to]->close(); } unset($this->_fileHandlers[$to]); if (file_exists($this->_dirPath . '/' . $to)) { if (!unlink($this->_dirPath . '/' . $to)) {  throw new Zend_Search_Lucene_Exception('Delete operation failed'); } } $trackErrors = ini_get('track_errors'); ini_set('track_errors', '1'); $success = @rename($this->_dirPath . '/' . $from, $this->_dirPath . '/' . $to); if (!$success) { ini_set('track_errors', $trackErrors);  throw new Zend_Search_Lucene_Exception($php_errormsg); } ini_set('track_errors', $trackErrors); return $success; } public function touchFile($filename) { return touch($this->_dirPath .'/'. $filename); } public function getFileObject($filename, $shareHandler = true) { $fullFilename = $this->_dirPath . '/' . $filename;  if (!$shareHandler) { return new Zend_Search_Lucene_Storage_File_Filesystem($fullFilename); } if (isset( $this->_fileHandlers[$filename] )) { $this->_fileHandlers[$filename]->seek(0); return $this->_fileHandlers[$filename]; } $this->_fileHandlers[$filename] = new Zend_Search_Lucene_Storage_File_Filesystem($fullFilename); return $this->_fileHandlers[$filename]; } } 
abstract class Zend_Search_Lucene_Index_SegmentWriter { public static $indexInterval = 128; public static $skipInterval = 0x7FFFFFFF; public static $maxSkipLevels = 0; protected $_docCount = 0; protected $_name; protected $_directory; protected $_files = array(); protected $_fields = array(); protected $_norms = array(); protected $_fdxFile = null; protected $_fdtFile = null; public function __construct(Zend_Search_Lucene_Storage_Directory $directory, $name) { $this->_directory = $directory; $this->_name = $name; } public function addField(Zend_Search_Lucene_Field $field) { if (!isset($this->_fields[$field->name])) { $fieldNumber = count($this->_fields); $this->_fields[$field->name] = new Zend_Search_Lucene_Index_FieldInfo($field->name, $field->isIndexed, $fieldNumber, $field->storeTermVector); return $fieldNumber; } else { $this->_fields[$field->name]->isIndexed |= $field->isIndexed; $this->_fields[$field->name]->storeTermVector |= $field->storeTermVector; return $this->_fields[$field->name]->number; } } public function addFieldInfo(Zend_Search_Lucene_Index_FieldInfo $fieldInfo) { if (!isset($this->_fields[$fieldInfo->name])) { $fieldNumber = count($this->_fields); $this->_fields[$fieldInfo->name] = new Zend_Search_Lucene_Index_FieldInfo($fieldInfo->name, $fieldInfo->isIndexed, $fieldNumber, $fieldInfo->storeTermVector); return $fieldNumber; } else { $this->_fields[$fieldInfo->name]->isIndexed |= $fieldInfo->isIndexed; $this->_fields[$fieldInfo->name]->storeTermVector |= $fieldInfo->storeTermVector; return $this->_fields[$fieldInfo->name]->number; } } public function getFieldInfos() { return $this->_fields; } public function addStoredFields($storedFields) { if (!isset($this->_fdxFile)) { $this->_fdxFile = $this->_directory->createFile($this->_name . '.fdx'); $this->_fdtFile = $this->_directory->createFile($this->_name . '.fdt'); $this->_files[] = $this->_name . '.fdx'; $this->_files[] = $this->_name . '.fdt'; } $this->_fdxFile->writeLong($this->_fdtFile->tell()); $this->_fdtFile->writeVInt(count($storedFields)); foreach ($storedFields as $field) { $this->_fdtFile->writeVInt($this->_fields[$field->name]->number); $fieldBits = ($field->isTokenized ? 0x01 : 0x00) | ($field->isBinary ? 0x02 : 0x00) | 0x00; $this->_fdtFile->writeByte($fieldBits); if ($field->isBinary) { $this->_fdtFile->writeVInt(strlen($field->value)); $this->_fdtFile->writeBytes($field->value); } else { $this->_fdtFile->writeString($field->getUtf8Value()); } } $this->_docCount++; } public function count() { return $this->_docCount; } public function getName() { return $this->_name; } protected function _dumpFNM() { $fnmFile = $this->_directory->createFile($this->_name . '.fnm'); $fnmFile->writeVInt(count($this->_fields)); $nrmFile = $this->_directory->createFile($this->_name . '.nrm'); $nrmFile->writeBytes('NRM'); $nrmFile->writeByte((int)0xFF); foreach ($this->_fields as $field) { $fnmFile->writeString($field->name); $fnmFile->writeByte(($field->isIndexed ? 0x01 : 0x00) | ($field->storeTermVector ? 0x02 : 0x00) ); if ($field->isIndexed) { $nrmFile->writeBytes($this->_norms[$field->name]); } } $this->_files[] = $this->_name . '.fnm'; $this->_files[] = $this->_name . '.nrm'; } private $_tisFile = null; private $_tiiFile = null; private $_frqFile = null; private $_prxFile = null; private $_termCount; private $_prevTerm; private $_prevTermInfo; private $_prevIndexTerm; private $_prevIndexTermInfo; private $_lastIndexPosition; public function initializeDictionaryFiles() { $this->_tisFile = $this->_directory->createFile($this->_name . '.tis'); $this->_tisFile->writeInt((int)0xFFFFFFFD); $this->_tisFile->writeLong(0 ); $this->_tisFile->writeInt(self::$indexInterval); $this->_tisFile->writeInt(self::$skipInterval); $this->_tisFile->writeInt(self::$maxSkipLevels); $this->_tiiFile = $this->_directory->createFile($this->_name . '.tii'); $this->_tiiFile->writeInt((int)0xFFFFFFFD); $this->_tiiFile->writeLong(0 ); $this->_tiiFile->writeInt(self::$indexInterval); $this->_tiiFile->writeInt(self::$skipInterval); $this->_tiiFile->writeInt(self::$maxSkipLevels); $this->_tiiFile->writeVInt(0); $this->_tiiFile->writeString(''); $this->_tiiFile->writeInt((int)0xFFFFFFFF); $this->_tiiFile->writeByte((int)0x0F); $this->_tiiFile->writeVInt(0); $this->_tiiFile->writeVInt(0); $this->_tiiFile->writeVInt(0); $this->_tiiFile->writeVInt(24); $this->_frqFile = $this->_directory->createFile($this->_name . '.frq'); $this->_prxFile = $this->_directory->createFile($this->_name . '.prx'); $this->_files[] = $this->_name . '.tis'; $this->_files[] = $this->_name . '.tii'; $this->_files[] = $this->_name . '.frq'; $this->_files[] = $this->_name . '.prx'; $this->_prevTerm = null; $this->_prevTermInfo = null; $this->_prevIndexTerm = null; $this->_prevIndexTermInfo = null; $this->_lastIndexPosition = 24; $this->_termCount = 0; } public function addTerm($termEntry, $termDocs) { $freqPointer = $this->_frqFile->tell(); $proxPointer = $this->_prxFile->tell(); $prevDoc = 0; foreach ($termDocs as $docId => $termPositions) { $docDelta = ($docId - $prevDoc)*2; $prevDoc = $docId; if (count($termPositions) > 1) { $this->_frqFile->writeVInt($docDelta); $this->_frqFile->writeVInt(count($termPositions)); } else { $this->_frqFile->writeVInt($docDelta + 1); } $prevPosition = 0; foreach ($termPositions as $position) { $this->_prxFile->writeVInt($position - $prevPosition); $prevPosition = $position; } } if (count($termDocs) >= self::$skipInterval) { $skipOffset = $this->_frqFile->tell() - $freqPointer; } else { $skipOffset = 0; } $term = new Zend_Search_Lucene_Index_Term($termEntry->text, $this->_fields[$termEntry->field]->number); $termInfo = new Zend_Search_Lucene_Index_TermInfo(count($termDocs), $freqPointer, $proxPointer, $skipOffset); $this->_dumpTermDictEntry($this->_tisFile, $this->_prevTerm, $term, $this->_prevTermInfo, $termInfo); if (($this->_termCount + 1) % self::$indexInterval == 0) { $this->_dumpTermDictEntry($this->_tiiFile, $this->_prevIndexTerm, $term, $this->_prevIndexTermInfo, $termInfo); $indexPosition = $this->_tisFile->tell(); $this->_tiiFile->writeVInt($indexPosition - $this->_lastIndexPosition); $this->_lastIndexPosition = $indexPosition; } $this->_termCount++; } public function closeDictionaryFiles() { $this->_tisFile->seek(4); $this->_tisFile->writeLong($this->_termCount); $this->_tiiFile->seek(4); $this->_tiiFile->writeLong(($this->_termCount - $this->_termCount % self::$indexInterval)/self::$indexInterval + 1); } protected function _dumpTermDictEntry(Zend_Search_Lucene_Storage_File $dicFile, &$prevTerm, Zend_Search_Lucene_Index_Term $term, &$prevTermInfo, Zend_Search_Lucene_Index_TermInfo $termInfo) { if (isset($prevTerm) && $prevTerm->field == $term->field) { $matchedBytes = 0; $maxBytes = min(strlen($prevTerm->text), strlen($term->text)); while ($matchedBytes < $maxBytes && $prevTerm->text[$matchedBytes] == $term->text[$matchedBytes]) { $matchedBytes++; } $prefixBytes = 0; $prefixChars = 0; while ($prefixBytes < $matchedBytes) { $charBytes = 1; if ((ord($term->text[$prefixBytes]) & 0xC0) == 0xC0) { $charBytes++; if (ord($term->text[$prefixBytes]) & 0x20 ) { $charBytes++; if (ord($term->text[$prefixBytes]) & 0x10 ) { $charBytes++; } } } if ($prefixBytes + $charBytes > $matchedBytes) { break; } $prefixChars++; $prefixBytes += $charBytes; } $dicFile->writeVInt($prefixChars); $dicFile->writeString(substr($term->text, $prefixBytes)); } else { $dicFile->writeVInt(0); $dicFile->writeString($term->text); } $dicFile->writeVInt($term->field); $dicFile->writeVInt($termInfo->docFreq); $prevTerm = $term; if (!isset($prevTermInfo)) { $dicFile->writeVInt($termInfo->freqPointer); $dicFile->writeVInt($termInfo->proxPointer); } else { $dicFile->writeVInt($termInfo->freqPointer - $prevTermInfo->freqPointer); $dicFile->writeVInt($termInfo->proxPointer - $prevTermInfo->proxPointer); } if ($termInfo->skipOffset != 0) { $dicFile->writeVInt($termInfo->skipOffset); } $prevTermInfo = $termInfo; } protected function _generateCFS() { $cfsFile = $this->_directory->createFile($this->_name . '.cfs'); $cfsFile->writeVInt(count($this->_files)); $dataOffsetPointers = array(); foreach ($this->_files as $fileName) { $dataOffsetPointers[$fileName] = $cfsFile->tell(); $cfsFile->writeLong(0); $cfsFile->writeString($fileName); } foreach ($this->_files as $fileName) { $dataOffset = $cfsFile->tell(); $cfsFile->seek($dataOffsetPointers[$fileName]); $cfsFile->writeLong($dataOffset); $cfsFile->seek($dataOffset); $dataFile = $this->_directory->getFileObject($fileName); $byteCount = $this->_directory->fileLength($fileName); while ($byteCount > 0) { $data = $dataFile->readBytes(min($byteCount, 131072 )); $byteCount -= strlen($data); $cfsFile->writeBytes($data); } $this->_directory->deleteFile($fileName); } } abstract public function close(); } 
class Zend_Search_Lucene_Index_SegmentWriter_DocumentWriter extends Zend_Search_Lucene_Index_SegmentWriter { protected $_termDictionary; protected $_termDocs; public function __construct(Zend_Search_Lucene_Storage_Directory $directory, $name) { parent::__construct($directory, $name); $this->_termDocs = array(); $this->_termDictionary = array(); } public function addDocument(Zend_Search_Lucene_Document $document) {  $storedFields = array(); $docNorms = array(); $similarity = Zend_Search_Lucene_Search_Similarity::getDefault(); foreach ($document->getFieldNames() as $fieldName) { $field = $document->getField($fieldName); if ($field->storeTermVector) {  throw new Zend_Search_Lucene_Exception('Store term vector functionality is not supported yet.'); } if ($field->isIndexed) { if ($field->isTokenized) {  $analyzer = Zend_Search_Lucene_Analysis_Analyzer::getDefault(); $analyzer->setInput($field->value, $field->encoding); $position = 0; $tokenCounter = 0; while (($token = $analyzer->nextToken()) !== null) { $tokenCounter++; $term = new Zend_Search_Lucene_Index_Term($token->getTermText(), $field->name); $termKey = $term->key(); if (!isset($this->_termDictionary[$termKey])) { $this->_termDictionary[$termKey] = $term; $this->_termDocs[$termKey] = array(); $this->_termDocs[$termKey][$this->_docCount] = array(); } else if (!isset($this->_termDocs[$termKey][$this->_docCount])) { $this->_termDocs[$termKey][$this->_docCount] = array(); } $position += $token->getPositionIncrement(); $this->_termDocs[$termKey][$this->_docCount][] = $position; } if ($tokenCounter == 0) { $field = clone($field); $field->isIndexed = $field->isTokenized = false; } else { $docNorms[$field->name] = chr($similarity->encodeNorm( $similarity->lengthNorm($field->name, $tokenCounter)* $document->boost* $field->boost )); } } else if (($fieldUtf8Value = $field->getUtf8Value()) == '') { $field = clone($field); $field->isIndexed = $field->isTokenized = false; } else { $term = new Zend_Search_Lucene_Index_Term($fieldUtf8Value, $field->name); $termKey = $term->key(); if (!isset($this->_termDictionary[$termKey])) { $this->_termDictionary[$termKey] = $term; $this->_termDocs[$termKey] = array(); $this->_termDocs[$termKey][$this->_docCount] = array(); } else if (!isset($this->_termDocs[$termKey][$this->_docCount])) { $this->_termDocs[$termKey][$this->_docCount] = array(); } $this->_termDocs[$termKey][$this->_docCount][] = 0; $docNorms[$field->name] = chr($similarity->encodeNorm( $similarity->lengthNorm($field->name, 1)* $document->boost* $field->boost )); } } if ($field->isStored) { $storedFields[] = $field; } $this->addField($field); } foreach ($this->_fields as $fieldName => $field) { if (!$field->isIndexed) { continue; } if (!isset($this->_norms[$fieldName])) { $this->_norms[$fieldName] = str_repeat(chr($similarity->encodeNorm( $similarity->lengthNorm($fieldName, 0) )), $this->_docCount); } if (isset($docNorms[$fieldName])){ $this->_norms[$fieldName] .= $docNorms[$fieldName]; } else { $this->_norms[$fieldName] .= chr($similarity->encodeNorm( $similarity->lengthNorm($fieldName, 0) )); } } $this->addStoredFields($storedFields); } protected function _dumpDictionary() { ksort($this->_termDictionary, SORT_STRING); $this->initializeDictionaryFiles(); foreach ($this->_termDictionary as $termId => $term) { $this->addTerm($term, $this->_termDocs[$termId]); } $this->closeDictionaryFiles(); } public function close() { if ($this->_docCount == 0) { return null; } $this->_dumpFNM(); $this->_dumpDictionary(); $this->_generateCFS();  return new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, $this->_name, $this->_docCount, -1, null, true, true); } } 
class Zend_Search_Lucene_Index_SegmentWriter_StreamWriter extends Zend_Search_Lucene_Index_SegmentWriter { public function __construct(Zend_Search_Lucene_Storage_Directory $directory, $name) { parent::__construct($directory, $name); } public function createStoredFieldsFiles() { $this->_fdxFile = $this->_directory->createFile($this->_name . '.fdx'); $this->_fdtFile = $this->_directory->createFile($this->_name . '.fdt'); $this->_files[] = $this->_name . '.fdx'; $this->_files[] = $this->_name . '.fdt'; } public function addNorm($fieldName, $normVector) { if (isset($this->_norms[$fieldName])) { $this->_norms[$fieldName] .= $normVector; } else { $this->_norms[$fieldName] = $normVector; } } public function close() { if ($this->_docCount == 0) { return null; } $this->_dumpFNM(); $this->_generateCFS();  return new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, $this->_name, $this->_docCount, -1, null, true, true); } } 
abstract class Zend_Search_Lucene_PriorityQueue { private $_heap = array(); public function put($element) { $nodeId = count($this->_heap); $parentId = ($nodeId-1) >> 1; while ($nodeId != 0 && $this->_less($element, $this->_heap[$parentId])) { $this->_heap[$nodeId] = $this->_heap[$parentId]; $nodeId = $parentId; $parentId = ($nodeId-1) >> 1; } $this->_heap[$nodeId] = $element; } public function top() { if (count($this->_heap) == 0) { return null; } return $this->_heap[0]; } public function pop() { if (count($this->_heap) == 0) { return null; } $top = $this->_heap[0]; $lastId = count($this->_heap) - 1; $nodeId = 0; $childId = 1; if ($lastId > 2 && $this->_less($this->_heap[2], $this->_heap[1])) { $childId = 2; } while ($childId < $lastId && $this->_less($this->_heap[$childId], $this->_heap[$lastId]) ) { $this->_heap[$nodeId] = $this->_heap[$childId]; $nodeId = $childId; $childId = ($nodeId << 1) + 1; if (($childId+1) < $lastId && $this->_less($this->_heap[$childId+1], $this->_heap[$childId]) ) { $childId++; } } $this->_heap[$nodeId] = $this->_heap[$lastId]; unset($this->_heap[$lastId]); return $top; } public function clear() { $this->_heap = array(); } abstract protected function _less($el1, $el2); } 
class Zend_Search_Lucene_Index_TermsPriorityQueue extends Zend_Search_Lucene_PriorityQueue { protected function _less($termsStream1, $termsStream2) { return strcmp($termsStream1->currentTerm()->key(), $termsStream2->currentTerm()->key()) < 0; } } 
class Zend_Search_Lucene_Index_SegmentMerger { private $_writer; private $_docCount; private $_segmentInfos = array(); private $_mergeDone = false; private $_fieldsMap = array(); public function __construct($directory, $name) {  $this->_writer = new Zend_Search_Lucene_Index_SegmentWriter_StreamWriter($directory, $name); } public function addSource(Zend_Search_Lucene_Index_SegmentInfo $segmentInfo) { $this->_segmentInfos[$segmentInfo->getName()] = $segmentInfo; } public function merge() { if ($this->_mergeDone) {  throw new Zend_Search_Lucene_Exception('Merge is already done.'); } if (count($this->_segmentInfos) < 1) {  throw new Zend_Search_Lucene_Exception('Wrong number of segments to be merged (' . count($this->_segmentInfos) . ').'); } $this->_mergeFields(); $this->_mergeNorms(); $this->_mergeStoredFields(); $this->_mergeTerms(); $this->_mergeDone = true; return $this->_writer->close(); } private function _mergeFields() { foreach ($this->_segmentInfos as $segName => $segmentInfo) { foreach ($segmentInfo->getFieldInfos() as $fieldInfo) { $this->_fieldsMap[$segName][$fieldInfo->number] = $this->_writer->addFieldInfo($fieldInfo); } } } private function _mergeNorms() { foreach ($this->_writer->getFieldInfos() as $fieldInfo) { if ($fieldInfo->isIndexed) { foreach ($this->_segmentInfos as $segName => $segmentInfo) { if ($segmentInfo->hasDeletions()) { $srcNorm = $segmentInfo->normVector($fieldInfo->name); $norm = ''; $docs = $segmentInfo->count(); for ($count = 0; $count < $docs; $count++) { if (!$segmentInfo->isDeleted($count)) { $norm .= $srcNorm[$count]; } } $this->_writer->addNorm($fieldInfo->name, $norm); } else { $this->_writer->addNorm($fieldInfo->name, $segmentInfo->normVector($fieldInfo->name)); } } } } } private function _mergeStoredFields() { $this->_docCount = 0; foreach ($this->_segmentInfos as $segName => $segmentInfo) { $fdtFile = $segmentInfo->openCompoundFile('.fdt'); for ($count = 0; $count < $segmentInfo->count(); $count++) { $fieldCount = $fdtFile->readVInt(); $storedFields = array(); for ($count2 = 0; $count2 < $fieldCount; $count2++) { $fieldNum = $fdtFile->readVInt(); $bits = $fdtFile->readByte(); $fieldInfo = $segmentInfo->getField($fieldNum); if (!($bits & 2)) { $storedFields[] = new Zend_Search_Lucene_Field($fieldInfo->name, $fdtFile->readString(), 'UTF-8', true, $fieldInfo->isIndexed, $bits & 1 ); } else { $storedFields[] = new Zend_Search_Lucene_Field($fieldInfo->name, $fdtFile->readBinary(), '', true, $fieldInfo->isIndexed, $bits & 1, true); } } if (!$segmentInfo->isDeleted($count)) { $this->_docCount++; $this->_writer->addStoredFields($storedFields); } } } } private function _mergeTerms() {  $segmentInfoQueue = new Zend_Search_Lucene_Index_TermsPriorityQueue(); $segmentStartId = 0; foreach ($this->_segmentInfos as $segName => $segmentInfo) { $segmentStartId = $segmentInfo->resetTermsStream($segmentStartId, Zend_Search_Lucene_Index_SegmentInfo::SM_MERGE_INFO); if ($segmentInfo->currentTerm() !== null) { $segmentInfoQueue->put($segmentInfo); } } $this->_writer->initializeDictionaryFiles(); $termDocs = array(); while (($segmentInfo = $segmentInfoQueue->pop()) !== null) { $termDocs += $segmentInfo->currentTermPositions(); if ($segmentInfoQueue->top() === null || $segmentInfoQueue->top()->currentTerm()->key() != $segmentInfo->currentTerm()->key()) { ksort($termDocs, SORT_NUMERIC); if (count($termDocs) > 0) { $this->_writer->addTerm($segmentInfo->currentTerm(), $termDocs); } $termDocs = array(); } $segmentInfo->nextTerm(); if ($segmentInfo->currentTerm() !== null) { $segmentInfoQueue->put($segmentInfo); } } $this->_writer->closeDictionaryFiles(); } } 
class Zend_Search_Lucene_Index_Writer { public $maxBufferedDocs = 10; public $maxMergeDocs = PHP_INT_MAX; public $mergeFactor = 10; private $_directory = null; private $_versionUpdate = 0; private $_newSegments = array(); private $_segmentsToDelete = array(); private $_currentSegment = null; private $_segmentInfos; private $_targetFormatVersion; private static $_indexExtensions = array('.cfs' => '.cfs', '.cfx' => '.cfx', '.fnm' => '.fnm', '.fdx' => '.fdx', '.fdt' => '.fdt', '.tis' => '.tis', '.tii' => '.tii', '.frq' => '.frq', '.prx' => '.prx', '.tvx' => '.tvx', '.tvd' => '.tvd', '.tvf' => '.tvf', '.del' => '.del', '.sti' => '.sti' ); public static function createIndex(Zend_Search_Lucene_Storage_Directory $directory, $generation, $nameCount) { if ($generation == 0) { foreach ($directory->fileList() as $file) { if ($file == 'deletable' || $file == 'segments' || isset(self::$_indexExtensions[ substr($file, strlen($file)-4)]) || preg_match('/\.f\d+$/i', $file) ) { $directory->deleteFile($file); } } $segmentsFile = $directory->createFile('segments'); $segmentsFile->writeInt((int)0xFFFFFFFF); $segmentsFile->writeLong(round(microtime(true))); $segmentsFile->writeInt($nameCount); $segmentsFile->writeInt(0); $deletableFile = $directory->createFile('deletable'); $deletableFile->writeInt(0); } else { $genFile = $directory->createFile('segments.gen'); $genFile->writeInt((int)0xFFFFFFFE); $genFile->writeLong($generation); $genFile->writeLong($generation); $segmentsFile = $directory->createFile(Zend_Search_Lucene::getSegmentFileName($generation)); $segmentsFile->writeInt((int)0xFFFFFFFD); $segmentsFile->writeLong(round(microtime(true))); $segmentsFile->writeInt($nameCount); $segmentsFile->writeInt(0); } } public function __construct(Zend_Search_Lucene_Storage_Directory $directory, &$segmentInfos, $targetFormatVersion) { $this->_directory = $directory; $this->_segmentInfos = &$segmentInfos; $this->_targetFormatVersion = $targetFormatVersion; } public function addDocument(Zend_Search_Lucene_Document $document) {  if ($this->_currentSegment === null) { $this->_currentSegment = new Zend_Search_Lucene_Index_SegmentWriter_DocumentWriter($this->_directory, $this->_newSegmentName()); } $this->_currentSegment->addDocument($document); if ($this->_currentSegment->count() >= $this->maxBufferedDocs) { $this->commit(); } $this->_maybeMergeSegments(); $this->_versionUpdate++; } private function _hasAnythingToMerge() { $segmentSizes = array(); foreach ($this->_segmentInfos as $segName => $segmentInfo) { $segmentSizes[$segName] = $segmentInfo->count(); } $mergePool = array(); $poolSize = 0; $sizeToMerge = $this->maxBufferedDocs; asort($segmentSizes, SORT_NUMERIC); foreach ($segmentSizes as $segName => $size) { while ($size >= $sizeToMerge) { if ($poolSize >= $sizeToMerge) { return true; } $mergePool = array(); $poolSize = 0; $sizeToMerge *= $this->mergeFactor; if ($sizeToMerge > $this->maxMergeDocs) { return false; } } $mergePool[] = $this->_segmentInfos[$segName]; $poolSize += $size; } if ($poolSize >= $sizeToMerge) { return true; } return false; } private function _maybeMergeSegments() { if (Zend_Search_Lucene_LockManager::obtainOptimizationLock($this->_directory) === false) { return; } if (!$this->_hasAnythingToMerge()) { Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); return; } $this->_updateSegments(); $segmentSizes = array(); foreach ($this->_segmentInfos as $segName => $segmentInfo) { $segmentSizes[$segName] = $segmentInfo->count(); } $mergePool = array(); $poolSize = 0; $sizeToMerge = $this->maxBufferedDocs; asort($segmentSizes, SORT_NUMERIC); foreach ($segmentSizes as $segName => $size) { while ($size >= $sizeToMerge) { if ($poolSize >= $sizeToMerge) { $this->_mergeSegments($mergePool); } $mergePool = array(); $poolSize = 0; $sizeToMerge *= $this->mergeFactor; if ($sizeToMerge > $this->maxMergeDocs) { Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); return; } } $mergePool[] = $this->_segmentInfos[$segName]; $poolSize += $size; } if ($poolSize >= $sizeToMerge) { $this->_mergeSegments($mergePool); } Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); } private function _mergeSegments($segments) { $newName = $this->_newSegmentName();  $merger = new Zend_Search_Lucene_Index_SegmentMerger($this->_directory, $newName); foreach ($segments as $segmentInfo) { $merger->addSource($segmentInfo); $this->_segmentsToDelete[$segmentInfo->getName()] = $segmentInfo->getName(); } $newSegment = $merger->merge(); if ($newSegment !== null) { $this->_newSegments[$newSegment->getName()] = $newSegment; } $this->commit(); } private function _updateSegments() { Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory); foreach ($this->_segmentInfos as $segInfo) { $segInfo->writeChanges(); } $generation = Zend_Search_Lucene::getActualGeneration($this->_directory); $segmentsFile = $this->_directory->getFileObject(Zend_Search_Lucene::getSegmentFileName($generation), false); $newSegmentFile = $this->_directory->createFile(Zend_Search_Lucene::getSegmentFileName(++$generation), false); try { $genFile = $this->_directory->getFileObject('segments.gen', false); } catch (Zend_Search_Lucene_Exception $e) { if (strpos($e->getMessage(), 'is not readable') !== false) { $genFile = $this->_directory->createFile('segments.gen'); } else { throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } } $genFile->writeInt((int)0xFFFFFFFE); $genFile->writeLong($generation); try { if ($this->_targetFormatVersion == Zend_Search_Lucene::FORMAT_2_1) { $newSegmentFile->writeInt((int)0xFFFFFFFD); } else if ($this->_targetFormatVersion == Zend_Search_Lucene::FORMAT_2_3) { $newSegmentFile->writeInt((int)0xFFFFFFFC); } $format = $segmentsFile->readInt(); if ($format == (int)0xFFFFFFFF) { $srcFormat = Zend_Search_Lucene::FORMAT_PRE_2_1; } else if ($format == (int)0xFFFFFFFD) { $srcFormat = Zend_Search_Lucene::FORMAT_2_1; } else if ($format == (int)0xFFFFFFFC) { $srcFormat = Zend_Search_Lucene::FORMAT_2_3; } else { throw new Zend_Search_Lucene_Exception('Unsupported segments file format'); } $version = $segmentsFile->readLong() + $this->_versionUpdate; $this->_versionUpdate = 0; $newSegmentFile->writeLong($version); $newSegmentFile->writeInt($segmentsFile->readInt()); $numOfSegmentsOffset = $newSegmentFile->tell(); $newSegmentFile->writeInt(0); $segmentsCount = $segmentsFile->readInt(); $segments = array(); for ($count = 0; $count < $segmentsCount; $count++) { $segName = $segmentsFile->readString(); $segSize = $segmentsFile->readInt(); if ($srcFormat == Zend_Search_Lucene::FORMAT_PRE_2_1) { $delGen = 0; $hasSingleNormFile = false; $numField = (int)0xFFFFFFFF; $isCompoundByte = 0; $docStoreOptions = null; } else { $delGen = $segmentsFile->readLong(); if ($srcFormat == Zend_Search_Lucene::FORMAT_2_3) { $docStoreOffset = $segmentsFile->readInt(); if ($docStoreOffset != (int)0xFFFFFFFF) { $docStoreSegment = $segmentsFile->readString(); $docStoreIsCompoundFile = $segmentsFile->readByte(); $docStoreOptions = array('offset' => $docStoreOffset, 'segment' => $docStoreSegment, 'isCompound' => ($docStoreIsCompoundFile == 1)); } else { $docStoreOptions = null; } } else { $docStoreOptions = null; } $hasSingleNormFile = $segmentsFile->readByte(); $numField = $segmentsFile->readInt(); $normGens = array(); if ($numField != (int)0xFFFFFFFF) { for ($count1 = 0; $count1 < $numField; $count1++) { $normGens[] = $segmentsFile->readLong(); } } $isCompoundByte = $segmentsFile->readByte(); } if (!in_array($segName, $this->_segmentsToDelete)) { if (!isset($this->_segmentInfos[$segName])) { if ($isCompoundByte == 0xFF) { $isCompound = false; } else if ($isCompoundByte == 0x00) { $isCompound = null; } else if ($isCompoundByte == 0x01) { $isCompound = true; }  $this->_segmentInfos[$segName] = new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, $segName, $segSize, $delGen, $docStoreOptions, $hasSingleNormFile, $isCompound); } else { $delGen = $this->_segmentInfos[$segName]->getDelGen(); } $newSegmentFile->writeString($segName); $newSegmentFile->writeInt($segSize); $newSegmentFile->writeLong($delGen); if ($this->_targetFormatVersion == Zend_Search_Lucene::FORMAT_2_3) { if ($docStoreOptions !== null) { $newSegmentFile->writeInt($docStoreOffset); $newSegmentFile->writeString($docStoreSegment); $newSegmentFile->writeByte($docStoreIsCompoundFile); } else { $newSegmentFile->writeInt((int)0xFFFFFFFF); } } else if ($docStoreOptions !== null) { Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); throw new Zend_Search_Lucene_Exception('Index conversion to lower format version is not supported.'); } $newSegmentFile->writeByte($hasSingleNormFile); $newSegmentFile->writeInt($numField); if ($numField != (int)0xFFFFFFFF) { foreach ($normGens as $normGen) { $newSegmentFile->writeLong($normGen); } } $newSegmentFile->writeByte($isCompoundByte); $segments[$segName] = $segSize; } } $segmentsFile->close(); $segmentsCount = count($segments) + count($this->_newSegments); foreach ($this->_newSegments as $segName => $segmentInfo) { $newSegmentFile->writeString($segName); $newSegmentFile->writeInt($segmentInfo->count()); $newSegmentFile->writeInt((int)0xFFFFFFFF);$newSegmentFile->writeInt((int)0xFFFFFFFF); if ($this->_targetFormatVersion == Zend_Search_Lucene::FORMAT_2_3) { $newSegmentFile->writeInt((int)0xFFFFFFFF); } $newSegmentFile->writeByte($segmentInfo->hasSingleNormFile()); $newSegmentFile->writeInt((int)0xFFFFFFFF); $newSegmentFile->writeByte($segmentInfo->isCompound() ? 1 : -1); $segments[$segmentInfo->getName()] = $segmentInfo->count(); $this->_segmentInfos[$segName] = $segmentInfo; } $this->_newSegments = array(); $newSegmentFile->seek($numOfSegmentsOffset); $newSegmentFile->writeInt($segmentsCount); $newSegmentFile->close(); } catch (Exception $e) { $generation--; $genFile->seek(4, SEEK_SET); $genFile->writeLong($generation); $genFile->writeLong($generation); Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory);  throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } $genFile->writeLong($generation); if (Zend_Search_Lucene_LockManager::escalateReadLock($this->_directory)) { $filesToDelete = array(); $filesTypes = array(); $filesNumbers = array(); $delFiles = array(); foreach ($this->_directory->fileList() as $file) { if ($file == 'deletable') { $filesToDelete[] = $file; $filesTypes[] = 0; $filesNumbers[] = 0; } else if ($file == 'segments') { $filesToDelete[] = $file; $filesTypes[] = 1; $filesNumbers[] = 0; } else if (preg_match('/^segments_[a-zA-Z0-9]+$/i', $file)) { if ($file != Zend_Search_Lucene::getSegmentFileName($generation)) { $filesToDelete[] = $file; $filesTypes[] = 2; $filesNumbers[] = (int)base_convert(substr($file, 9), 36, 10); } } else if (preg_match('/(^_([a-zA-Z0-9]+))\.f\d+$/i', $file, $matches)) { if (!isset($segments[$matches[1]])) { $filesToDelete[] = $file; $filesTypes[] = 3; $filesNumbers[] = (int)base_convert($matches[2], 36, 10); } } else if (preg_match('/(^_([a-zA-Z0-9]+))(_([a-zA-Z0-9]+))\.del$/i', $file, $matches)) { if (!isset($segments[$matches[1]])) { $filesToDelete[] = $file; $filesTypes[] = 3; $filesNumbers[] = (int)base_convert($matches[2], 36, 10); } else { $segmentNumber = (int)base_convert($matches[2], 36, 10); $delGeneration = (int)base_convert($matches[4], 36, 10); if (!isset($delFiles[$segmentNumber])) { $delFiles[$segmentNumber] = array(); } $delFiles[$segmentNumber][$delGeneration] = $file; } } else if (isset(self::$_indexExtensions[substr($file, strlen($file)-4)])) { $segmentName = substr($file, 0, strlen($file) - 4); if (!isset($segments[$segmentName]) && ($this->_currentSegment === null || $this->_currentSegment->getName() != $segmentName)) { $filesToDelete[] = $file; $filesTypes[] = 3; $filesNumbers[] = (int)base_convert(substr($file, 1 , strlen($file)-5), 36, 10); } } } $maxGenNumber = 0; foreach ($delFiles as $segmentNumber => $segmentDelFiles) { ksort($delFiles[$segmentNumber], SORT_NUMERIC); array_pop($delFiles[$segmentNumber]); end($delFiles[$segmentNumber]); $lastGenNumber = key($delFiles[$segmentNumber]); if ($lastGenNumber > $maxGenNumber) { $maxGenNumber = $lastGenNumber; } } foreach ($delFiles as $segmentNumber => $segmentDelFiles) { foreach ($segmentDelFiles as $delGeneration => $file) { $filesToDelete[] = $file; $filesTypes[] = 4; $filesNumbers[] = $segmentNumber*$maxGenNumber + $delGeneration; } } array_multisort($filesTypes, SORT_ASC, SORT_NUMERIC, $filesNumbers, SORT_ASC, SORT_NUMERIC, $filesToDelete, SORT_ASC, SORT_STRING); foreach ($filesToDelete as $file) { try { if (substr($file, strlen($file)-4) != '.cfx') { $this->_directory->deleteFile($file); } } catch (Zend_Search_Lucene_Exception $e) { if (strpos($e->getMessage(), 'Can\'t delete file') === false) { throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } } } Zend_Search_Lucene_LockManager::deEscalateReadLock($this->_directory); } else { foreach ($this->_segmentsToDelete as $segName) { foreach (self::$_indexExtensions as $ext) { $this->_directory->purgeFile($segName . $ext); } } } $this->_segmentsToDelete = array(); Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); foreach ($this->_segmentInfos as $segName => $segmentInfo) { if (!isset($segments[$segName])) { unset($this->_segmentInfos[$segName]); } } } public function commit() { if ($this->_currentSegment !== null) { $newSegment = $this->_currentSegment->close(); if ($newSegment !== null) { $this->_newSegments[$newSegment->getName()] = $newSegment; } $this->_currentSegment = null; } $this->_updateSegments(); } public function addIndexes($readers) { } public function optimize() { if (Zend_Search_Lucene_LockManager::obtainOptimizationLock($this->_directory) === false) { return false; } $this->_updateSegments(); $this->_mergeSegments($this->_segmentInfos); Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory); return true; } private function _newSegmentName() { Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory); $generation = Zend_Search_Lucene::getActualGeneration($this->_directory); $segmentsFile = $this->_directory->getFileObject(Zend_Search_Lucene::getSegmentFileName($generation), false); $segmentsFile->seek(12); $segmentNameCounter = $segmentsFile->readInt(); $segmentsFile->seek(12); $segmentsFile->writeInt($segmentNameCounter + 1); $segmentsFile->flush(); Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); return '_' . base_convert($segmentNameCounter, 10, 36); } } 
class Zend_Search_Lucene_TermStreamsPriorityQueue implements Zend_Search_Lucene_Index_TermsStream_Interface { protected $_termStreams; protected $_termsStreamQueue = null; protected $_lastTerm = null; public function __construct(array $termStreams) { $this->_termStreams = $termStreams; $this->resetTermsStream(); } public function resetTermsStream() {  $this->_termsStreamQueue = new Zend_Search_Lucene_Index_TermsPriorityQueue(); foreach ($this->_termStreams as $termStream) { $termStream->resetTermsStream(); if ($termStream->currentTerm() !== null) { $this->_termsStreamQueue->put($termStream); } } $this->nextTerm(); } public function skipTo(Zend_Search_Lucene_Index_Term $prefix) { $this->_termsStreamQueue = new Zend_Search_Lucene_Index_TermsPriorityQueue(); foreach ($this->_termStreams as $termStream) { $termStream->skipTo($prefix); if ($termStream->currentTerm() !== null) { $this->_termsStreamQueue->put($termStream); } } return $this->nextTerm(); } public function nextTerm() { while (($termStream = $this->_termsStreamQueue->pop()) !== null) { if ($this->_termsStreamQueue->top() === null || $this->_termsStreamQueue->top()->currentTerm()->key() != $termStream->currentTerm()->key()) { $this->_lastTerm = $termStream->currentTerm(); if ($termStream->nextTerm() !== null) { $this->_termsStreamQueue->put($termStream); } return $this->_lastTerm; } if ($termStream->nextTerm() !== null) { $this->_termsStreamQueue->put($termStream); } } $this->_lastTerm = null; return null; } public function currentTerm() { return $this->_lastTerm; } public function closeTermsStream() { while (($termStream = $this->_termsStreamQueue->pop()) !== null) { $termStream->closeTermsStream(); } $this->_termsStreamQueue = null; $this->_lastTerm = null; } } 
class Zend_Search_Lucene implements Zend_Search_Lucene_Interface { private static $_defaultSearchField = null; private static $_resultSetLimit = 0; private static $_termsPerQueryLimit = 1024; private $_directory = null; private $_closeDirOnExit = true; private $_writer = null; private $_segmentInfos = array(); private $_docCount = 0; private $_hasChanges = false; private $_closed = false; private $_refCount = 0; private $_generation; const FORMAT_PRE_2_1 = 0; const FORMAT_2_1 = 1; const FORMAT_2_3 = 2; private $_formatVersion; public static function create($directory) {  return new Zend_Search_Lucene_Proxy(new Zend_Search_Lucene($directory, true)); } public static function open($directory) {  return new Zend_Search_Lucene_Proxy(new Zend_Search_Lucene($directory, false)); } const GENERATION_RETRIEVE_COUNT = 10; const GENERATION_RETRIEVE_PAUSE = 50; public static function getActualGeneration(Zend_Search_Lucene_Storage_Directory $directory) {  try { for ($count = 0; $count < self::GENERATION_RETRIEVE_COUNT; $count++) { $genFile = $directory->getFileObject('segments.gen', false); $format = $genFile->readInt(); if ($format != (int)0xFFFFFFFE) { throw new Zend_Search_Lucene_Exception('Wrong segments.gen file format'); } $gen1 = $genFile->readLong(); $gen2 = $genFile->readLong(); if ($gen1 == $gen2) { return $gen1; } usleep(self::GENERATION_RETRIEVE_PAUSE * 1000); } throw new Zend_Search_Lucene_Exception('Index is under processing now'); } catch (Zend_Search_Lucene_Exception $e) { if (strpos($e->getMessage(), 'is not readable') !== false) { try { $segmentsFile = $directory->getFileObject('segments', false); return 0; } catch (Zend_Search_Lucene_Exception $e) { if (strpos($e->getMessage(), 'is not readable') !== false) { return -1; } else { throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } } } else { throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } } return -1; } public function getGeneration() { return $this->_generation; } public static function getSegmentFileName($generation) { if ($generation == 0) { return 'segments'; } return 'segments_' . base_convert($generation, 10, 36); } public function getFormatVersion() { return $this->_formatVersion; } public function setFormatVersion($formatVersion) { if ($formatVersion != self::FORMAT_PRE_2_1 && $formatVersion != self::FORMAT_2_1 && $formatVersion != self::FORMAT_2_3) {  throw new Zend_Search_Lucene_Exception('Unsupported index format'); } $this->_formatVersion = $formatVersion; } private function _readPre21SegmentsFile() { $segmentsFile = $this->_directory->getFileObject('segments'); $format = $segmentsFile->readInt(); if ($format != (int)0xFFFFFFFF) {  throw new Zend_Search_Lucene_Exception('Wrong segments file format'); } $segmentsFile->readLong(); $segmentsFile->readInt(); $segments = $segmentsFile->readInt(); $this->_docCount = 0; for ($count = 0; $count < $segments; $count++) { $segName = $segmentsFile->readString(); $segSize = $segmentsFile->readInt(); $this->_docCount += $segSize; $this->_segmentInfos[$segName] = new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, $segName, $segSize); } $this->_formatVersion = self::FORMAT_2_1; } private function _readSegmentsFile() { $segmentsFile = $this->_directory->getFileObject(self::getSegmentFileName($this->_generation)); $format = $segmentsFile->readInt(); if ($format == (int)0xFFFFFFFC) { $this->_formatVersion = self::FORMAT_2_3; } else if ($format == (int)0xFFFFFFFD) { $this->_formatVersion = self::FORMAT_2_1; } else {  throw new Zend_Search_Lucene_Exception('Unsupported segments file format'); } $segmentsFile->readLong(); $segmentsFile->readInt(); $segments = $segmentsFile->readInt(); $this->_docCount = 0; for ($count = 0; $count < $segments; $count++) { $segName = $segmentsFile->readString(); $segSize = $segmentsFile->readInt(); $delGen = $segmentsFile->readLong(); if ($this->_formatVersion == self::FORMAT_2_3) { $docStoreOffset = $segmentsFile->readInt(); if ($docStoreOffset != (int)0xFFFFFFFF) { $docStoreSegment = $segmentsFile->readString(); $docStoreIsCompoundFile = $segmentsFile->readByte(); $docStoreOptions = array('offset' => $docStoreOffset, 'segment' => $docStoreSegment, 'isCompound' => ($docStoreIsCompoundFile == 1)); } else { $docStoreOptions = null; } } else { $docStoreOptions = null; } $hasSingleNormFile = $segmentsFile->readByte(); $numField = $segmentsFile->readInt(); $normGens = array(); if ($numField != (int)0xFFFFFFFF) { for ($count1 = 0; $count1 < $numField; $count1++) { $normGens[] = $segmentsFile->readLong(); }  throw new Zend_Search_Lucene_Exception('Separate norm files are not supported. Optimize index to use it with Zend_Search_Lucene.'); } $isCompoundByte = $segmentsFile->readByte(); if ($isCompoundByte == 0xFF) { $isCompound = false; } else if ($isCompoundByte == 0x00) { $isCompound = null; } else if ($isCompoundByte == 0x01) { $isCompound = true; } $this->_docCount += $segSize; $this->_segmentInfos[$segName] = new Zend_Search_Lucene_Index_SegmentInfo($this->_directory, $segName, $segSize, $delGen, $docStoreOptions, $hasSingleNormFile, $isCompound); } } public function __construct($directory = null, $create = false) { if ($directory === null) {  throw new Zend_Search_Exception('No index directory specified'); } if (is_string($directory)) {  $this->_directory = new Zend_Search_Lucene_Storage_Directory_Filesystem($directory); $this->_closeDirOnExit = true; } else { $this->_directory = $directory; $this->_closeDirOnExit = false; } $this->_segmentInfos = array(); Zend_Search_Lucene_LockManager::obtainReadLock($this->_directory); $this->_generation = self::getActualGeneration($this->_directory); if ($create) {  try { Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory); } catch (Zend_Search_Lucene_Exception $e) { Zend_Search_Lucene_LockManager::releaseReadLock($this->_directory); if (strpos($e->getMessage(), 'Can\'t obtain exclusive index lock') === false) { throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } else { throw new Zend_Search_Lucene_Exception('Can\'t create index. It\'s under processing now', 0, $e); } } if ($this->_generation == -1) { $this->_generation = 1; $nameCounter = 0; } else { $segmentsFile = $this->_directory->getFileObject(self::getSegmentFileName($this->_generation)); $segmentsFile->seek(12); $nameCounter = $segmentsFile->readInt(); $this->_generation++; }  Zend_Search_Lucene_Index_Writer::createIndex($this->_directory, $this->_generation, $nameCounter); Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory); } if ($this->_generation == -1) {  throw new Zend_Search_Lucene_Exception('Index doesn\'t exists in the specified directory.'); } else if ($this->_generation == 0) { $this->_readPre21SegmentsFile(); } else { $this->_readSegmentsFile(); } } private function _close() { if ($this->_closed) { return; } $this->commit(); Zend_Search_Lucene_LockManager::releaseReadLock($this->_directory); if ($this->_closeDirOnExit) { $this->_directory->close(); } $this->_directory = null; $this->_writer = null; $this->_segmentInfos = null; $this->_closed = true; } public function addReference() { $this->_refCount++; } public function removeReference() { $this->_refCount--; if ($this->_refCount == 0) { $this->_close(); } } public function __destruct() { $this->_close(); } private function _getIndexWriter() { if ($this->_writer === null) {  $this->_writer = new Zend_Search_Lucene_Index_Writer($this->_directory, $this->_segmentInfos, $this->_formatVersion); } return $this->_writer; } public function getDirectory() { return $this->_directory; } public function count() { return $this->_docCount; } public function maxDoc() { return $this->count(); } public function numDocs() { $numDocs = 0; foreach ($this->_segmentInfos as $segmentInfo) { $numDocs += $segmentInfo->numDocs(); } return $numDocs; } public function isDeleted($id) { $this->commit(); if ($id >= $this->_docCount) {  throw new Zend_Search_Lucene_Exception('Document id is out of the range.'); } $segmentStartId = 0; foreach ($this->_segmentInfos as $segmentInfo) { if ($segmentStartId + $segmentInfo->count() > $id) { break; } $segmentStartId += $segmentInfo->count(); } return $segmentInfo->isDeleted($id - $segmentStartId); } public static function setDefaultSearchField($fieldName) { self::$_defaultSearchField = $fieldName; } public static function getDefaultSearchField() { return self::$_defaultSearchField; } public static function setResultSetLimit($limit) { self::$_resultSetLimit = $limit; } public static function getResultSetLimit() { return self::$_resultSetLimit; } public static function setTermsPerQueryLimit($limit) { self::$_termsPerQueryLimit = $limit; } public static function getTermsPerQueryLimit() { return self::$_termsPerQueryLimit; } public function getMaxBufferedDocs() { return $this->_getIndexWriter()->maxBufferedDocs; } public function setMaxBufferedDocs($maxBufferedDocs) { $this->_getIndexWriter()->maxBufferedDocs = $maxBufferedDocs; } public function getMaxMergeDocs() { return $this->_getIndexWriter()->maxMergeDocs; } public function setMaxMergeDocs($maxMergeDocs) { $this->_getIndexWriter()->maxMergeDocs = $maxMergeDocs; } public function getMergeFactor() { return $this->_getIndexWriter()->mergeFactor; } public function setMergeFactor($mergeFactor) { $this->_getIndexWriter()->mergeFactor = $mergeFactor; } public function find($query) { if (is_string($query)) {  $query = Zend_Search_Lucene_Search_QueryParser::parse($query); } if (!$query instanceof Zend_Search_Lucene_Search_Query) {  throw new Zend_Search_Lucene_Exception('Query must be a string or Zend_Search_Lucene_Search_Query object'); } $this->commit(); $hits = array(); $scores = array(); $ids = array(); $query = $query->rewrite($this)->optimize($this); $query->execute($this); $topScore = 0;  foreach ($query->matchedDocs() as $id => $num) { $docScore = $query->score($id, $this); if( $docScore != 0 ) { $hit = new Zend_Search_Lucene_Search_QueryHit($this); $hit->id = $id; $hit->score = $docScore; $hits[] = $hit; $ids[] = $id; $scores[] = $docScore; if ($docScore > $topScore) { $topScore = $docScore; } } if (self::$_resultSetLimit != 0 && count($hits) >= self::$_resultSetLimit) { break; } } if (count($hits) == 0) { return array(); } if ($topScore > 1) { foreach ($hits as $hit) { $hit->score /= $topScore; } } if (func_num_args() == 1) { array_multisort($scores, SORT_DESC, SORT_NUMERIC, $ids, SORT_ASC, SORT_NUMERIC, $hits); } else { $argList = func_get_args(); $fieldNames = $this->getFieldNames(); $sortArgs = array(); $sortReg = SORT_REGULAR; $sortAsc = SORT_ASC; $sortNum = SORT_NUMERIC; $sortFieldValues = array();  for ($count = 1; $count < count($argList); $count++) { $fieldName = $argList[$count]; if (!is_string($fieldName)) { throw new Zend_Search_Lucene_Exception('Field name must be a string.'); } if (strtolower($fieldName) == 'score') { $sortArgs[] = &$scores; } else { if (!in_array($fieldName, $fieldNames)) { throw new Zend_Search_Lucene_Exception('Wrong field name.'); } if (!isset($sortFieldValues[$fieldName])) { $valuesArray = array(); foreach ($hits as $hit) { try { $value = $hit->getDocument()->getFieldValue($fieldName); } catch (Zend_Search_Lucene_Exception $e) { if (strpos($e->getMessage(), 'not found') === false) { throw new Zend_Search_Lucene_Exception($e->getMessage(), $e->getCode(), $e); } else { $value = null; } } $valuesArray[] = $value; } $sortFieldValues[$fieldName] = $valuesArray; } $sortArgs[] = &$sortFieldValues[$fieldName]; } if ($count + 1 < count($argList) && is_integer($argList[$count+1])) { $count++; $sortArgs[] = &$argList[$count]; if ($count + 1 < count($argList) && is_integer($argList[$count+1])) { $count++; $sortArgs[] = &$argList[$count]; } else { if ($argList[$count] == SORT_ASC || $argList[$count] == SORT_DESC) { $sortArgs[] = &$sortReg; } else { $sortArgs[] = &$sortAsc; } } } else { $sortArgs[] = &$sortAsc; $sortArgs[] = &$sortReg; } } $sortArgs[] = &$ids; $sortArgs[] = &$sortAsc; $sortArgs[] = &$sortNum; $sortArgs[] = &$hits; call_user_func_array('array_multisort', $sortArgs); } return $hits; } public function getFieldNames($indexed = false) { $result = array(); foreach( $this->_segmentInfos as $segmentInfo ) { $result = array_merge($result, $segmentInfo->getFields($indexed)); } return $result; } public function getDocument($id) { if ($id instanceof Zend_Search_Lucene_Search_QueryHit) { $id = $id->id; } if ($id >= $this->_docCount) {  throw new Zend_Search_Lucene_Exception('Document id is out of the range.'); } $segmentStartId = 0; foreach ($this->_segmentInfos as $segmentInfo) { if ($segmentStartId + $segmentInfo->count() > $id) { break; } $segmentStartId += $segmentInfo->count(); } $fdxFile = $segmentInfo->openCompoundFile('.fdx'); $fdxFile->seek(($id-$segmentStartId)*8, SEEK_CUR); $fieldValuesPosition = $fdxFile->readLong(); $fdtFile = $segmentInfo->openCompoundFile('.fdt'); $fdtFile->seek($fieldValuesPosition, SEEK_CUR); $fieldCount = $fdtFile->readVInt(); $doc = new Zend_Search_Lucene_Document(); for ($count = 0; $count < $fieldCount; $count++) { $fieldNum = $fdtFile->readVInt(); $bits = $fdtFile->readByte(); $fieldInfo = $segmentInfo->getField($fieldNum); if (!($bits & 2)) { $field = new Zend_Search_Lucene_Field($fieldInfo->name, $fdtFile->readString(), 'UTF-8', true, $fieldInfo->isIndexed, $bits & 1 ); } else { $field = new Zend_Search_Lucene_Field($fieldInfo->name, $fdtFile->readBinary(), '', true, $fieldInfo->isIndexed, $bits & 1, true ); } $doc->addField($field); } return $doc; } public function hasTerm(Zend_Search_Lucene_Index_Term $term) { foreach ($this->_segmentInfos as $segInfo) { if ($segInfo->getTermInfo($term) !== null) { return true; } } return false; } public function termDocs(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) { $subResults = array(); $segmentStartDocId = 0; foreach ($this->_segmentInfos as $segmentInfo) { $subResults[] = $segmentInfo->termDocs($term, $segmentStartDocId, $docsFilter); $segmentStartDocId += $segmentInfo->count(); } if (count($subResults) == 0) { return array(); } else if (count($subResults) == 1) { return reset($subResults); } else { $result = call_user_func_array('array_merge', $subResults); } return $result; } public function termDocsFilter(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) { $segmentStartDocId = 0; $result = new Zend_Search_Lucene_Index_DocsFilter(); foreach ($this->_segmentInfos as $segmentInfo) { $subResults[] = $segmentInfo->termDocs($term, $segmentStartDocId, $docsFilter); $segmentStartDocId += $segmentInfo->count(); } if (count($subResults) == 0) { return array(); } else if (count($subResults) == 1) { return reset($subResults); } else { $result = call_user_func_array('array_merge', $subResults); } return $result; } public function termFreqs(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) { $result = array(); $segmentStartDocId = 0; foreach ($this->_segmentInfos as $segmentInfo) { $result += $segmentInfo->termFreqs($term, $segmentStartDocId, $docsFilter); $segmentStartDocId += $segmentInfo->count(); } return $result; } public function termPositions(Zend_Search_Lucene_Index_Term $term, $docsFilter = null) { $result = array(); $segmentStartDocId = 0; foreach ($this->_segmentInfos as $segmentInfo) { $result += $segmentInfo->termPositions($term, $segmentStartDocId, $docsFilter); $segmentStartDocId += $segmentInfo->count(); } return $result; } public function docFreq(Zend_Search_Lucene_Index_Term $term) { $result = 0; foreach ($this->_segmentInfos as $segInfo) { $termInfo = $segInfo->getTermInfo($term); if ($termInfo !== null) { $result += $termInfo->docFreq; } } return $result; } public function getSimilarity() {  return Zend_Search_Lucene_Search_Similarity::getDefault(); } public function norm($id, $fieldName) { if ($id >= $this->_docCount) { return null; } $segmentStartId = 0; foreach ($this->_segmentInfos as $segInfo) { if ($segmentStartId + $segInfo->count() > $id) { break; } $segmentStartId += $segInfo->count(); } if ($segInfo->isDeleted($id - $segmentStartId)) { return 0; } return $segInfo->norm($id - $segmentStartId, $fieldName); } public function hasDeletions() { foreach ($this->_segmentInfos as $segmentInfo) { if ($segmentInfo->hasDeletions()) { return true; } } return false; } public function delete($id) { if ($id instanceof Zend_Search_Lucene_Search_QueryHit) { $id = $id->id; } if ($id >= $this->_docCount) {  throw new Zend_Search_Lucene_Exception('Document id is out of the range.'); } $segmentStartId = 0; foreach ($this->_segmentInfos as $segmentInfo) { if ($segmentStartId + $segmentInfo->count() > $id) { break; } $segmentStartId += $segmentInfo->count(); } $segmentInfo->delete($id - $segmentStartId); $this->_hasChanges = true; } public function addDocument(Zend_Search_Lucene_Document $document) { $this->_getIndexWriter()->addDocument($document); $this->_docCount++; $this->_hasChanges = true; } private function _updateDocCount() { $this->_docCount = 0; foreach ($this->_segmentInfos as $segInfo) { $this->_docCount += $segInfo->count(); } } public function commit() { if ($this->_hasChanges) { $this->_getIndexWriter()->commit(); $this->_updateDocCount(); $this->_hasChanges = false; } } public function optimize() { $this->commit(); if (count($this->_segmentInfos) > 1 || $this->hasDeletions()) { $this->_getIndexWriter()->optimize(); $this->_updateDocCount(); } } public function terms() { $result = array();  $segmentInfoQueue = new Zend_Search_Lucene_Index_TermsPriorityQueue(); foreach ($this->_segmentInfos as $segmentInfo) { $segmentInfo->resetTermsStream(); if ($segmentInfo->currentTerm() !== null) { $segmentInfoQueue->put($segmentInfo); } } while (($segmentInfo = $segmentInfoQueue->pop()) !== null) { if ($segmentInfoQueue->top() === null || $segmentInfoQueue->top()->currentTerm()->key() != $segmentInfo->currentTerm()->key()) { $result[] = $segmentInfo->currentTerm(); } if ($segmentInfo->nextTerm() !== null) { $segmentInfoQueue->put($segmentInfo); } } return $result; } private $_termsStream = null; public function resetTermsStream() { if ($this->_termsStream === null) {  $this->_termsStream = new Zend_Search_Lucene_TermStreamsPriorityQueue($this->_segmentInfos); } else { $this->_termsStream->resetTermsStream(); } } public function skipTo(Zend_Search_Lucene_Index_Term $prefix) { $this->_termsStream->skipTo($prefix); } public function nextTerm() { return $this->_termsStream->nextTerm(); } public function currentTerm() { return $this->_termsStream->currentTerm(); } public function closeTermsStream() { $this->_termsStream->closeTermsStream(); $this->_termsStream = null; } public function undeleteAll() {} } 