7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
16 * @package Zend_Search_Lucene
18 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: QueryParser.php 16541 2009-07-07 06:59:03Z bkarwin $
23 /** Zend_Search_Lucene_Index_Term */
24 require_once 'Zend/Search/Lucene/Index/Term.php';
26 /** Zend_Search_Lucene_Search_Query_Term */
27 require_once 'Zend/Search/Lucene/Search/Query/Term.php';
29 /** Zend_Search_Lucene_Search_Query_MultiTerm */
30 require_once 'Zend/Search/Lucene/Search/Query/MultiTerm.php';
32 /** Zend_Search_Lucene_Search_Query_Boolean */
33 require_once 'Zend/Search/Lucene/Search/Query/Boolean.php';
35 /** Zend_Search_Lucene_Search_Query_Preprocessing_Phrase */
36 require_once 'Zend/Search/Lucene/Search/Query/Preprocessing/Phrase.php';
38 /** Zend_Search_Lucene_Search_Query_Preprocessing_Term */
39 require_once 'Zend/Search/Lucene/Search/Query/Preprocessing/Term.php';
41 /** Zend_Search_Lucene_Search_Query_Preprocessing_Fuzzy */
42 require_once 'Zend/Search/Lucene/Search/Query/Preprocessing/Fuzzy.php';
44 /** Zend_Search_Lucene_Search_Query_Wildcard */
45 require_once 'Zend/Search/Lucene/Search/Query/Wildcard.php';
47 /** Zend_Search_Lucene_Search_Query_Range */
48 require_once 'Zend/Search/Lucene/Search/Query/Range.php';
50 /** Zend_Search_Lucene_Search_Query_Fuzzy */
51 require_once 'Zend/Search/Lucene/Search/Query/Fuzzy.php';
53 /** Zend_Search_Lucene_Search_Query_Empty */
54 require_once 'Zend/Search/Lucene/Search/Query/Empty.php';
56 /** Zend_Search_Lucene_Search_Query_Insignificant */
57 require_once 'Zend/Search/Lucene/Search/Query/Insignificant.php';
59 /** Zend_Search_Lucene_Search_QueryLexer */
60 require_once 'Zend/Search/Lucene/Search/QueryLexer.php';
62 /** Zend_Search_Lucene_Search_QueryParserContext */
63 require_once 'Zend/Search/Lucene/Search/QueryParserContext.php';
65 /** Zend_Search_Lucene_FSM */
66 require_once 'Zend/Search/Lucene/FSM.php';
70 * @package Zend_Search_Lucene
72 * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
73 * @license http://framework.zend.com/license/new-bsd New BSD License
75 class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
80 * @var Zend_Search_Lucene_Search_QueryParser
82 private static $_instance = null;
88 * @var Zend_Search_Lucene_Search_QueryLexer
94 * Array of Zend_Search_Lucene_Search_QueryToken objects
103 * @var integer|string
105 private $_currentToken;
110 * It can be processed within FSM states, but this addirional state simplifies FSM
112 * @var Zend_Search_Lucene_Search_QueryToken
114 private $_lastToken = null;
117 * Range query first term
121 private $_rqFirstTerm = null;
124 * Current query parser context
126 * @var Zend_Search_Lucene_Search_QueryParserContext
135 private $_contextStack;
138 * Query string encoding
145 * Query string default encoding
149 private $_defaultEncoding = '';
152 * Defines query parsing mode.
154 * If this option is turned on, then query parser suppress query parser exceptions
155 * and constructs multi-term query using all words from a query.
157 * That helps to avoid exceptions caused by queries, which don't conform to query language,
158 * but limits possibilities to check, that query entered by user has some inconsistencies.
163 * Use {@link Zend_Search_Lucene::suppressQueryParsingExceptions()},
164 * {@link Zend_Search_Lucene::dontSuppressQueryParsingExceptions()} and
165 * {@link Zend_Search_Lucene::checkQueryParsingExceptionsSuppressMode()} to operate
170 private $_suppressQueryParsingExceptions = true;
173 * Boolean operators constants
179 * Default boolean queries operator
183 private $_defaultOperator = self::B_OR;
186 /** Query parser State Machine states */
187 const ST_COMMON_QUERY_ELEMENT = 0; // Terms, phrases, operators
188 const ST_CLOSEDINT_RQ_START = 1; // Range query start (closed interval) - '['
189 const ST_CLOSEDINT_RQ_FIRST_TERM = 2; // First term in '[term1 to term2]' construction
190 const ST_CLOSEDINT_RQ_TO_TERM = 3; // 'TO' lexeme in '[term1 to term2]' construction
191 const ST_CLOSEDINT_RQ_LAST_TERM = 4; // Second term in '[term1 to term2]' construction
192 const ST_CLOSEDINT_RQ_END = 5; // Range query end (closed interval) - ']'
193 const ST_OPENEDINT_RQ_START = 6; // Range query start (opened interval) - '{'
194 const ST_OPENEDINT_RQ_FIRST_TERM = 7; // First term in '{term1 to term2}' construction
195 const ST_OPENEDINT_RQ_TO_TERM = 8; // 'TO' lexeme in '{term1 to term2}' construction
196 const ST_OPENEDINT_RQ_LAST_TERM = 9; // Second term in '{term1 to term2}' construction
197 const ST_OPENEDINT_RQ_END = 10; // Range query end (opened interval) - '}'
202 public function __construct()
204 parent::__construct(array(self::ST_COMMON_QUERY_ELEMENT,
205 self::ST_CLOSEDINT_RQ_START,
206 self::ST_CLOSEDINT_RQ_FIRST_TERM,
207 self::ST_CLOSEDINT_RQ_TO_TERM,
208 self::ST_CLOSEDINT_RQ_LAST_TERM,
209 self::ST_CLOSEDINT_RQ_END,
210 self::ST_OPENEDINT_RQ_START,
211 self::ST_OPENEDINT_RQ_FIRST_TERM,
212 self::ST_OPENEDINT_RQ_TO_TERM,
213 self::ST_OPENEDINT_RQ_LAST_TERM,
214 self::ST_OPENEDINT_RQ_END
216 Zend_Search_Lucene_Search_QueryToken::getTypes());
219 array(array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_COMMON_QUERY_ELEMENT),
220 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, self::ST_COMMON_QUERY_ELEMENT),
221 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, self::ST_COMMON_QUERY_ELEMENT),
222 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, self::ST_COMMON_QUERY_ELEMENT),
223 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, self::ST_COMMON_QUERY_ELEMENT),
224 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, self::ST_COMMON_QUERY_ELEMENT),
225 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK, self::ST_COMMON_QUERY_ELEMENT),
226 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_START, self::ST_CLOSEDINT_RQ_START),
227 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_START, self::ST_OPENEDINT_RQ_START),
228 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, self::ST_COMMON_QUERY_ELEMENT),
229 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, self::ST_COMMON_QUERY_ELEMENT),
230 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, self::ST_COMMON_QUERY_ELEMENT),
231 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, self::ST_COMMON_QUERY_ELEMENT),
232 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, self::ST_COMMON_QUERY_ELEMENT),
233 array(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, self::ST_COMMON_QUERY_ELEMENT)
236 array(array(self::ST_CLOSEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_FIRST_TERM),
237 array(self::ST_CLOSEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_CLOSEDINT_RQ_TO_TERM),
238 array(self::ST_CLOSEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_CLOSEDINT_RQ_LAST_TERM),
239 array(self::ST_CLOSEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_INCL_END, self::ST_COMMON_QUERY_ELEMENT)
242 array(array(self::ST_OPENEDINT_RQ_START, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_FIRST_TERM),
243 array(self::ST_OPENEDINT_RQ_FIRST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_TO_LEXEME, self::ST_OPENEDINT_RQ_TO_TERM),
244 array(self::ST_OPENEDINT_RQ_TO_TERM, Zend_Search_Lucene_Search_QueryToken::TT_WORD, self::ST_OPENEDINT_RQ_LAST_TERM),
245 array(self::ST_OPENEDINT_RQ_LAST_TERM, Zend_Search_Lucene_Search_QueryToken::TT_RANGE_EXCL_END, self::ST_COMMON_QUERY_ELEMENT)
250 $addTermEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addTermEntry');
251 $addPhraseEntryAction = new Zend_Search_Lucene_FSMAction($this, 'addPhraseEntry');
252 $setFieldAction = new Zend_Search_Lucene_FSMAction($this, 'setField');
253 $setSignAction = new Zend_Search_Lucene_FSMAction($this, 'setSign');
254 $setFuzzyProxAction = new Zend_Search_Lucene_FSMAction($this, 'processFuzzyProximityModifier');
255 $processModifierParameterAction = new Zend_Search_Lucene_FSMAction($this, 'processModifierParameter');
256 $subqueryStartAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryStart');
257 $subqueryEndAction = new Zend_Search_Lucene_FSMAction($this, 'subqueryEnd');
258 $logicalOperatorAction = new Zend_Search_Lucene_FSMAction($this, 'logicalOperator');
259 $openedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQFirstTerm');
260 $openedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'openedRQLastTerm');
261 $closedRQFirstTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQFirstTerm');
262 $closedRQLastTermAction = new Zend_Search_Lucene_FSMAction($this, 'closedRQLastTerm');
265 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_WORD, $addTermEntryAction);
266 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PHRASE, $addPhraseEntryAction);
267 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FIELD, $setFieldAction);
268 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_REQUIRED, $setSignAction);
269 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_PROHIBITED, $setSignAction);
270 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK, $setFuzzyProxAction);
271 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NUMBER, $processModifierParameterAction);
272 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_START, $subqueryStartAction);
273 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_SUBQUERY_END, $subqueryEndAction);
274 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_AND_LEXEME, $logicalOperatorAction);
275 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_OR_LEXEME, $logicalOperatorAction);
276 $this->addInputAction(self::ST_COMMON_QUERY_ELEMENT, Zend_Search_Lucene_Search_QueryToken::TT_NOT_LEXEME, $logicalOperatorAction);
278 $this->addEntryAction(self::ST_OPENEDINT_RQ_FIRST_TERM, $openedRQFirstTermAction);
279 $this->addEntryAction(self::ST_OPENEDINT_RQ_LAST_TERM, $openedRQLastTermAction);
280 $this->addEntryAction(self::ST_CLOSEDINT_RQ_FIRST_TERM, $closedRQFirstTermAction);
281 $this->addEntryAction(self::ST_CLOSEDINT_RQ_LAST_TERM, $closedRQLastTermAction);
285 $this->_lexer = new Zend_Search_Lucene_Search_QueryLexer();
289 * Get query parser instance
291 * @return Zend_Search_Lucene_Search_QueryParser
293 private static function _getInstance()
295 if (self::$_instance === null) {
296 self::$_instance = new self();
298 return self::$_instance;
302 * Set query string default encoding
304 * @param string $encoding
306 public static function setDefaultEncoding($encoding)
308 self::_getInstance()->_defaultEncoding = $encoding;
312 * Get query string default encoding
316 public static function getDefaultEncoding()
318 return self::_getInstance()->_defaultEncoding;
322 * Set default boolean operator
324 * @param integer $operator
326 public static function setDefaultOperator($operator)
328 self::_getInstance()->_defaultOperator = $operator;
332 * Get default boolean operator
336 public static function getDefaultOperator()
338 return self::_getInstance()->_defaultOperator;
342 * Turn on 'suppress query parser exceptions' mode.
344 public static function suppressQueryParsingExceptions()
346 self::_getInstance()->_suppressQueryParsingExceptions = true;
349 * Turn off 'suppress query parser exceptions' mode.
351 public static function dontSuppressQueryParsingExceptions()
353 self::_getInstance()->_suppressQueryParsingExceptions = false;
356 * Check 'suppress query parser exceptions' mode.
359 public static function queryParsingExceptionsSuppressed()
361 return self::_getInstance()->_suppressQueryParsingExceptions;
367 * Parses a query string
369 * @param string $strQuery
370 * @param string $encoding
371 * @return Zend_Search_Lucene_Search_Query
372 * @throws Zend_Search_Lucene_Search_QueryParserException
374 public static function parse($strQuery, $encoding = null)
376 self::_getInstance();
378 // Reset FSM if previous parse operation didn't return it into a correct state
379 self::$_instance->reset();
381 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
383 self::$_instance->_encoding = ($encoding !== null) ? $encoding : self::$_instance->_defaultEncoding;
384 self::$_instance->_lastToken = null;
385 self::$_instance->_context = new Zend_Search_Lucene_Search_QueryParserContext(self::$_instance->_encoding);
386 self::$_instance->_contextStack = array();
387 self::$_instance->_tokens = self::$_instance->_lexer->tokenize($strQuery, self::$_instance->_encoding);
390 if (count(self::$_instance->_tokens) == 0) {
391 return new Zend_Search_Lucene_Search_Query_Insignificant();
395 foreach (self::$_instance->_tokens as $token) {
397 self::$_instance->_currentToken = $token;
398 self::$_instance->process($token->type);
400 self::$_instance->_lastToken = $token;
401 } catch (Exception $e) {
402 if (strpos($e->getMessage(), 'There is no any rule for') !== false) {
403 throw new Zend_Search_Lucene_Search_QueryParserException( 'Syntax error at char position ' . $token->position . '.' );
410 if (count(self::$_instance->_contextStack) != 0) {
411 throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing.' );
414 return self::$_instance->_context->getQuery();
415 } catch (Zend_Search_Lucene_Search_QueryParserException $e) {
416 if (self::$_instance->_suppressQueryParsingExceptions) {
417 $queryTokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($strQuery, self::$_instance->_encoding);
419 $query = new Zend_Search_Lucene_Search_Query_MultiTerm();
420 $termsSign = (self::$_instance->_defaultOperator == self::B_AND) ? true /* required term */ :
421 null /* optional term */;
423 foreach ($queryTokens as $token) {
424 $query->addTerm(new Zend_Search_Lucene_Index_Term($token->getTermText()), $termsSign);
435 /*********************************************************************
436 * Actions implementation
438 * Actions affect on recognized lexemes list
439 *********************************************************************/
442 * Add term to a query
444 public function addTermEntry()
446 $entry = new Zend_Search_Lucene_Search_QueryEntry_Term($this->_currentToken->text, $this->_context->getField());
447 $this->_context->addEntry($entry);
451 * Add phrase to a query
453 public function addPhraseEntry()
455 $entry = new Zend_Search_Lucene_Search_QueryEntry_Phrase($this->_currentToken->text, $this->_context->getField());
456 $this->_context->addEntry($entry);
462 public function setField()
464 $this->_context->setNextEntryField($this->_currentToken->text);
470 public function setSign()
472 $this->_context->setNextEntrySign($this->_currentToken->type);
477 * Process fuzzy search/proximity modifier - '~'
479 public function processFuzzyProximityModifier()
481 $this->_context->processFuzzyProximityModifier();
485 * Process modifier parameter
487 * @throws Zend_Search_Lucene_Exception
489 public function processModifierParameter()
491 if ($this->_lastToken === null) {
492 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
493 throw new Zend_Search_Lucene_Search_QueryParserException('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' );
496 switch ($this->_lastToken->type) {
497 case Zend_Search_Lucene_Search_QueryToken::TT_FUZZY_PROX_MARK:
498 $this->_context->processFuzzyProximityModifier($this->_currentToken->text);
501 case Zend_Search_Lucene_Search_QueryToken::TT_BOOSTING_MARK:
502 $this->_context->boost($this->_currentToken->text);
506 // It's not a user input exception
507 require_once 'Zend/Search/Lucene/Exception.php';
508 throw new Zend_Search_Lucene_Exception('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' );
516 public function subqueryStart()
518 $this->_contextStack[] = $this->_context;
519 $this->_context = new Zend_Search_Lucene_Search_QueryParserContext($this->_encoding, $this->_context->getField());
525 public function subqueryEnd()
527 if (count($this->_contextStack) == 0) {
528 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
529 throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing. Char position ' . $this->_currentToken->position . '.' );
532 $query = $this->_context->getQuery();
533 $this->_context = array_pop($this->_contextStack);
535 $this->_context->addEntry(new Zend_Search_Lucene_Search_QueryEntry_Subquery($query));
539 * Process logical operator
541 public function logicalOperator()
543 $this->_context->addLogicalOperator($this->_currentToken->type);
547 * Process first range query term (opened interval)
549 public function openedRQFirstTerm()
551 $this->_rqFirstTerm = $this->_currentToken->text;
555 * Process last range query term (opened interval)
557 * @throws Zend_Search_Lucene_Search_QueryParserException
559 public function openedRQLastTerm()
561 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding);
562 if (count($tokens) > 1) {
563 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
564 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
565 } else if (count($tokens) == 1) {
566 $from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
571 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding);
572 if (count($tokens) > 1) {
573 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
574 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
575 } else if (count($tokens) == 1) {
576 $to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
581 if ($from === null && $to === null) {
582 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
583 throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term');
586 $rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, false);
587 $entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery);
588 $this->_context->addEntry($entry);
592 * Process first range query term (closed interval)
594 public function closedRQFirstTerm()
596 $this->_rqFirstTerm = $this->_currentToken->text;
600 * Process last range query term (closed interval)
602 * @throws Zend_Search_Lucene_Search_QueryParserException
604 public function closedRQLastTerm()
606 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding);
607 if (count($tokens) > 1) {
608 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
609 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
610 } else if (count($tokens) == 1) {
611 $from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
616 $tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding);
617 if (count($tokens) > 1) {
618 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
619 throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
620 } else if (count($tokens) == 1) {
621 $to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
626 if ($from === null && $to === null) {
627 require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
628 throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term');
631 $rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, true);
632 $entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery);
633 $this->_context->addEntry($entry);