├── .gitignore ├── .travis.yml ├── CHANGES.rst ├── LICENSE.txt ├── MANIFEST.in ├── Makefile ├── README.rst ├── lucenequery ├── ElasticsearchGrammar.g4 ├── StandardLuceneGrammar.g4 ├── __init__.py ├── dialects.py └── prefixfields.py ├── setup.cfg ├── setup.py ├── string_trees.json ├── test_java_queryparser.js ├── test_java_queryparser_examples.json ├── test_lucenequery.py ├── tox.ini └── travis-antlr4.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .tox 3 | __pycache__ 4 | *.egg-info 5 | *.pyc 6 | bin 7 | dist 8 | include 9 | lib 10 | pip-selfcheck.json 11 | pyvenv.cfg 12 | lucenequery/*Grammar*.py 13 | lucenequery/*Grammar*.tokens 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: false 3 | cache: 4 | directories: 5 | - $HOME/antlr4 6 | 7 | env: 8 | - TOXENV=py27 9 | - TOXENV=py34 10 | - TOXENV=pypy 11 | 12 | install: 13 | - bash travis-antlr4.sh 14 | - export PATH="$HOME/antlr4/bin:$PATH" 15 | - antlr4 16 | - make 17 | - travis_retry pip install -U setuptools 18 | - travis_retry pip install tox 19 | - travis_retry tox --notest 20 | 21 | script: 22 | - tox 23 | -------------------------------------------------------------------------------- /CHANGES.rst: -------------------------------------------------------------------------------- 1 | Changes 2 | ======= 3 | 4 | 0.1 (2016-03-02) 5 | ---------------- 6 | 7 | * prefixfields function for modifying field names in query. 8 | 9 | * ElasticsearchGrammar extending StandardLuceneGrammar. 10 | 11 | * Import MontySolr's StandardLuceneGrammar, converting from ANTLR 3 to ANTLR 4 and adapting to Python. 12 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2016 Laurence Rowe, 2011-2015 Roman Chyla 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | include CHANGES.rst 3 | include LICENSE.txt 4 | include lucenequery/*Grammar*.tokens 5 | include lucenequery/*Grammar*.py 6 | include lucenequery/*Grammar*.g4 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: ElasticsearchGrammar StandardLuceneGrammar 2 | 3 | StandardLuceneGrammar: 4 | cd lucenequery && antlr4 StandardLuceneGrammar.g4 5 | 6 | ElasticsearchGrammar: StandardLuceneGrammar 7 | cd lucenequery && antlr4 ElasticsearchGrammar.g4 8 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | lucenequery 3 | =========== 4 | 5 | Parse queries in Lucene and Elasticsearch syntaxes. 6 | -------------------------------------------------------------------------------- /lucenequery/ElasticsearchGrammar.g4: -------------------------------------------------------------------------------- 1 | grammar ElasticsearchGrammar; 2 | import StandardLuceneGrammar; 3 | 4 | // Elasticsearch extends the standard grammar. 5 | // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html 6 | 7 | options { 8 | language = Python2; 9 | } 10 | 11 | range_term 12 | : 13 | two_sided_range_term 14 | | one_sided_range_term 15 | ; 16 | 17 | one_sided_range_term 18 | : 19 | op=(GT|GTE|LT|LTE) 20 | val=range_value 21 | ; 22 | 23 | GT : '>' ; 24 | GTE : '>=' ; 25 | LT : '<' ; 26 | LTE : '<=' ; 27 | -------------------------------------------------------------------------------- /lucenequery/StandardLuceneGrammar.g4: -------------------------------------------------------------------------------- 1 | grammar StandardLuceneGrammar; 2 | 3 | // 4 | // This is a re-implementation of the standard lucene syntax with ANTLR4 5 | // http://lucene.apache.org/core/4_3_0/queryparser/index.html 6 | // 7 | // The query syntax is complete and supports the same features as the 8 | // original parser written in JCC. The advantage of this grammar is that it 9 | // is 'pluggable' into Lucene's modern flexible parser, so that you can 10 | // add custom logic on top of the 'rigid' query syntax. Besides...the grammar 11 | // is not that 'rigid' - you can modify the grammar and easily recompile. 12 | // 13 | // # run this commad inside antlrqueryparser 14 | // 15 | // $ ant generate-antlr -Dgrammar=MyNewGrammar 16 | // 17 | // # or if you want to test things, do: 18 | // 19 | // $ ant try-view -Dgrammar=MyNewGrammar -Dquery="foo AND bar" 20 | // 21 | // 22 | // Implementation note: I have tried hard to avoid putting language specific details 23 | // into the grammar, unfortunately this was not always possible. But it is kept 24 | // at minimum. You can generate parser code in your language of choice 25 | // if you change the following: 26 | // 27 | // options : 28 | // language= 29 | // superClass= the default is to subclass 'UnforgivingParser', this java class 30 | // lives in the package oal.queryparser.flixible.aqp.parser 31 | // and its purpose is to bark everytime when an exception 32 | // happens (otherwise, ANTLR tries to recover from some situations 33 | // -- you may want to remove this definition, or add your own 34 | // error recovery logic there) 35 | // 36 | // @header: this adds the java declaration to the generated parser file, 37 | // feel free to remove (if you want to test the grammar using 38 | // ANTLRWorks, you want to remove it) 39 | // @lexer::header: dtto but for lexer 40 | // @lexer::members: again, necessary for being strict and prevent error 41 | // recovery, but this applies only to lexer errors. 42 | // 43 | // One last note - if you want to implement your own error recovery, have a look 44 | // at the generated java class 45 | // 46 | // oal.queryparser.flixible.aqp.parser.SyntaxParser.java 47 | // 48 | // There we are raising parse exception as well 49 | // 50 | 51 | options { 52 | language = Python2; 53 | } 54 | 55 | tokens { 56 | OPERATOR, 57 | ATOM, 58 | MODIFIER, 59 | TMODIFIER, 60 | CLAUSE, 61 | FIELD, 62 | FUZZY, 63 | BOOST, 64 | QNORMAL, 65 | QPHRASE, 66 | QPHRASETRUNC, 67 | QTRUNCATED, 68 | QRANGEIN, 69 | QRANGEEX, 70 | QANYTHING, 71 | QDATE 72 | } 73 | 74 | mainQ : 75 | sep? clause=clauseDefault sep? EOF 76 | ; 77 | 78 | clauseDefault 79 | : 80 | //m:(a b AND c OR d OR e) 81 | // without duplicating the rules (but it allows recursion) 82 | clauseOr (sep? clauseOr)* 83 | ; 84 | 85 | clauseOr 86 | : clauseAnd (or_ clauseAnd)* 87 | ; 88 | 89 | clauseAnd 90 | : clauseNot (and_ clauseNot)* 91 | ; 92 | 93 | clauseNot 94 | : clauseBasic (not_ clauseBasic)* 95 | ; 96 | 97 | clauseBasic 98 | : 99 | sep? modifier? LPAREN clauseDefault sep? RPAREN term_modifier? 100 | | sep? atom 101 | ; 102 | 103 | atom 104 | : 105 | modifier? field multi_value term_modifier? 106 | | modifier? field? value term_modifier? 107 | ; 108 | 109 | field 110 | : 111 | TERM_NORMAL COLON sep? 112 | ; 113 | 114 | value 115 | : 116 | range_term 117 | | normal 118 | | truncated 119 | | quoted 120 | | quoted_truncated 121 | | QMARK 122 | | anything 123 | | STAR 124 | ; 125 | 126 | anything 127 | : 128 | STAR COLON STAR 129 | ; 130 | 131 | two_sided_range_term 132 | : 133 | start_type=(LBRACK|LCURLY) 134 | sep? 135 | (a=range_value) 136 | sep? 137 | ( TO? sep? b=range_value sep? )? 138 | end_type=(RBRACK|RCURLY) 139 | ; 140 | 141 | range_term 142 | : 143 | two_sided_range_term 144 | ; 145 | 146 | range_value 147 | : 148 | truncated 149 | | quoted 150 | | quoted_truncated 151 | | date 152 | | normal 153 | | STAR 154 | ; 155 | 156 | multi_value 157 | : 158 | LPAREN clauseDefault sep? RPAREN 159 | ; 160 | 161 | normal 162 | : 163 | TERM_NORMAL 164 | | NUMBER 165 | ; 166 | 167 | truncated 168 | : 169 | TERM_TRUNCATED 170 | ; 171 | 172 | quoted_truncated 173 | : 174 | PHRASE_ANYTHING 175 | ; 176 | 177 | quoted : 178 | PHRASE 179 | ; 180 | 181 | modifier: 182 | PLUS 183 | | MINUS; 184 | 185 | 186 | term_modifier : 187 | boost fuzzy? 188 | | fuzzy boost? 189 | ; 190 | 191 | boost : 192 | (CARAT) // set the default value 193 | (NUMBER)? //replace the default with user input 194 | ; 195 | 196 | fuzzy : 197 | (TILDE) // set the default value 198 | (NUMBER)? //replace the default with user input 199 | ; 200 | 201 | not_ : 202 | sep? AND sep? NOT 203 | | sep? NOT 204 | ; 205 | 206 | and_ : 207 | sep? AND 208 | ; 209 | 210 | or_ : 211 | sep? OR 212 | ; 213 | 214 | date : 215 | DATE_TOKEN 216 | ; 217 | 218 | /* ================================================================ 219 | * = LEXER = 220 | * ================================================================ 221 | */ 222 | 223 | LPAREN : '('; 224 | 225 | RPAREN : ')'; 226 | 227 | LBRACK : '['; 228 | 229 | RBRACK : ']'; 230 | 231 | COLON : ':' ; //this must NOT be fragment 232 | 233 | PLUS : '+' ; 234 | 235 | MINUS : ('-'|'!'); 236 | 237 | STAR : '*' ; 238 | 239 | QMARK : '?'+ ; 240 | 241 | fragment VBAR : '|' ; 242 | 243 | fragment AMPER : '&' ; 244 | 245 | LCURLY : '{' ; 246 | 247 | RCURLY : '}' ; 248 | 249 | CARAT : '^' (INT+ ('.' INT+)?)?; 250 | 251 | TILDE : '~' (INT+ ('.' INT+)?)?; 252 | 253 | DQUOTE 254 | : '\"'; 255 | 256 | SQUOTE 257 | : '\''; 258 | 259 | TO : 'TO'; 260 | 261 | /* We want to be case insensitive */ 262 | AND : (('a' | 'A') ('n' | 'N') ('d' | 'D') | (AMPER AMPER?)) ; 263 | OR : (('o' | 'O') ('r' | 'R') | (VBAR VBAR?)); 264 | NOT : ('n' | 'N') ('o' | 'O') ('t' | 'T'); 265 | 266 | sep : WS+; 267 | 268 | WS : ( ' ' 269 | | '\t' 270 | | '\r' 271 | | '\n' 272 | | '\u3000' 273 | ) 274 | ; 275 | 276 | /* 277 | fragment TERM_CHAR : 278 | ~(' ' | '\t' | '\n' | '\r' | '\u3000' 279 | | '\\' | '\'' | '\"' 280 | | '(' | ')' | '[' | ']' | '{' | '}' 281 | | '+' | '-' | '!' | ':' | '~' | '^' 282 | | '*' | '|' | '&' | '?' | '\\\"' | '/' //this line is not present in lucene StandardParser.jj 283 | ); 284 | */ 285 | 286 | fragment INT: '0' .. '9'; 287 | 288 | fragment ESC_CHAR: '\\' .; 289 | 290 | fragment TERM_START_CHAR 291 | : 292 | (~(' ' | '\t' | '\n' | '\r' | '\u3000' 293 | | '\'' | '\"' 294 | | '(' | ')' | '[' | ']' | '{' | '}' 295 | | '+' | '-' | '!' | ':' | '~' | '^' 296 | | '?' | '*' | '\\' 297 | ) 298 | | ESC_CHAR ); 299 | 300 | fragment TERM_CHAR 301 | : 302 | (TERM_START_CHAR | '-' | '+') 303 | ; 304 | 305 | NUMBER 306 | : 307 | INT+ ('.' INT+)? 308 | ; 309 | 310 | DATE_TOKEN 311 | : 312 | INT INT? ('/'|'-'|'.') INT INT? ('/'|'-'|'.') INT INT (INT INT)? 313 | ; 314 | 315 | TERM_NORMAL 316 | : 317 | TERM_START_CHAR ( TERM_CHAR )* 318 | ; 319 | 320 | TERM_TRUNCATED: 321 | (STAR|QMARK) (TERM_CHAR+ (QMARK|STAR))+ (TERM_CHAR)* 322 | | TERM_START_CHAR (TERM_CHAR* (QMARK|STAR))+ (TERM_CHAR)* 323 | | (STAR|QMARK) TERM_CHAR+ 324 | ; 325 | 326 | PHRASE 327 | : 328 | DQUOTE (ESC_CHAR|~('\"'|'\\'|'?'|'*'))+ DQUOTE 329 | ; 330 | 331 | PHRASE_ANYTHING : 332 | DQUOTE (ESC_CHAR|~('\"'|'\\'))+ DQUOTE 333 | ; 334 | -------------------------------------------------------------------------------- /lucenequery/__init__.py: -------------------------------------------------------------------------------- 1 | import antlr4 2 | 3 | 4 | def parse(query, dialect=None): 5 | if dialect is None: 6 | from . import dialects 7 | dialect = getattr(dialects, 'standard') 8 | lexer = dialect.lexer(antlr4.InputStream(query)) 9 | stream = antlr4.CommonTokenStream(lexer) 10 | parser = dialect.parser(stream) 11 | parser._errHandler = antlr4.BailErrorStrategy() 12 | tree = parser.mainQ() 13 | return tree.clause 14 | -------------------------------------------------------------------------------- /lucenequery/dialects.py: -------------------------------------------------------------------------------- 1 | from .StandardLuceneGrammarLexer import StandardLuceneGrammarLexer 2 | from .StandardLuceneGrammarListener import StandardLuceneGrammarListener 3 | from .StandardLuceneGrammarParser import StandardLuceneGrammarParser 4 | from .ElasticsearchGrammarLexer import ElasticsearchGrammarLexer 5 | from .ElasticsearchGrammarListener import ElasticsearchGrammarListener 6 | from .ElasticsearchGrammarParser import ElasticsearchGrammarParser 7 | from collections import namedtuple 8 | 9 | Dialect = namedtuple('Dialect', ['lexer', 'listener', 'parser']) 10 | 11 | standard = Dialect( 12 | lexer=StandardLuceneGrammarLexer, 13 | listener=StandardLuceneGrammarListener, 14 | parser=StandardLuceneGrammarParser, 15 | ) 16 | 17 | elasticsearch = Dialect( 18 | lexer=ElasticsearchGrammarLexer, 19 | listener=ElasticsearchGrammarListener, 20 | parser=ElasticsearchGrammarParser, 21 | ) 22 | -------------------------------------------------------------------------------- /lucenequery/prefixfields.py: -------------------------------------------------------------------------------- 1 | from . import parse 2 | from .StandardLuceneGrammarListener import StandardLuceneGrammarListener 3 | import antlr4 4 | 5 | 6 | class PrefixFieldsListener(StandardLuceneGrammarListener): 7 | def __init__(self, prefix): 8 | super(PrefixFieldsListener, self).__init__() 9 | self.field_prefix = prefix 10 | 11 | def exitField(self, ctx): 12 | term = ctx.getChild(0) 13 | term.symbol.text = self.field_prefix + term.symbol.text 14 | 15 | 16 | def prefixfields(prefix, query, dialect=None): 17 | clause = parse(query, dialect=dialect) 18 | walker = antlr4.ParseTreeWalker() 19 | walker.walk(PrefixFieldsListener(prefix), clause) 20 | return clause 21 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal = 1 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | from setuptools import setup 3 | 4 | here = os.path.abspath(os.path.dirname(__file__)) 5 | README = open(os.path.join(here, 'README.rst')).read() 6 | CHANGES = open(os.path.join(here, 'CHANGES.rst')).read() 7 | 8 | setup( 9 | name='lucenequery', 10 | version='0.1', 11 | description='Parse queries in Lucene and Elasticsearch syntaxes', 12 | long_description=README + '\n\n' + CHANGES, 13 | classifiers=[ 14 | "Intended Audience :: Developers", 15 | "Programming Language :: Python", 16 | "Programming Language :: Python :: 2.7", 17 | "Programming Language :: Python :: 3", 18 | "Programming Language :: Python :: 3.4", 19 | "Programming Language :: Python :: 3.5", 20 | "Programming Language :: Python :: Implementation :: CPython", 21 | "Programming Language :: Python :: Implementation :: PyPy", 22 | "License :: OSI Approved :: Apache Software License", 23 | ], 24 | packages=['lucenequery'], 25 | author='Laurence Rowe', 26 | author_email='laurence@lrowe.co.uk', 27 | url='http://github.com/lrowe/lucenequery', 28 | license='Apache', 29 | extras_require={ 30 | ':python_version<"3.0"': ['antlr4-python2-runtime'], 31 | ':python_version>="3.0"': ['antlr4-python3-runtime'], 32 | }, 33 | ) 34 | -------------------------------------------------------------------------------- /string_trees.json: -------------------------------------------------------------------------------- 1 | { 2 | "atom": { 3 | "\" this \"": "(MODIFIER (TMODIFIER (FIELD (QPHRASE \" this \"))))", 4 | "\"*te*t\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASETRUNC \"*te*t\"))))", 5 | "\"*te*t*\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASETRUNC \"*te*t*\"))))", 6 | "\"+() AND that\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASE \"+() AND that\"))))", 7 | "\"?te*t?\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASETRUNC \"?te*t?\"))))", 8 | "\"a \\\"b c\\\" d\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASE \"a \\\"b c\\\" d\"))))", 9 | "\"a \\+b c d\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASE \"a \\+b c d\"))))", 10 | "\"func(*) AND that\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASETRUNC \"func(*) AND that\"))))", 11 | "\"jakarta apache\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASE \"jakarta apache\"))))", 12 | "\"jakarta apache\"^10": "(MODIFIER (TMODIFIER (BOOST ^10) FUZZY (FIELD (QPHRASE \"jakarta apache\"))))", 13 | "\"jakarta apache\"^10~": "(MODIFIER (TMODIFIER (BOOST ^10) (FUZZY ~) (FIELD (QPHRASE \"jakarta apache\"))))", 14 | "\"jakarta apache\"^10~0.6": "(MODIFIER (TMODIFIER (BOOST ^10) (FUZZY ~0.6) (FIELD (QPHRASE \"jakarta apache\"))))", 15 | "\"jakarta apache\"~10": "(MODIFIER (TMODIFIER BOOST (FUZZY ~10) (FIELD (QPHRASE \"jakarta apache\"))))", 16 | "\"jakarta apache\"~10^": "(MODIFIER (TMODIFIER (BOOST ^) (FUZZY ~10) (FIELD (QPHRASE \"jakarta apache\"))))", 17 | "\"jakarta apache\"~10^0.6": "(MODIFIER (TMODIFIER (BOOST ^0.6) (FUZZY ~10) (FIELD (QPHRASE \"jakarta apache\"))))", 18 | "\"te*?t\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASETRUNC \"te*?t\"))))", 19 | "\"te*t\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASETRUNC \"te*t\"))))", 20 | "\"te??t\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASETRUNC \"te??t\"))))", 21 | "\"te?t\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASETRUNC \"te?t\"))))", 22 | "\"test*\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASETRUNC \"test*\"))))", 23 | "\"text\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASE \"text\"))))", 24 | "\"this \"": "(MODIFIER (TMODIFIER (FIELD (QPHRASE \"this \"))))", 25 | "\"this \" ": "(MODIFIER (TMODIFIER (FIELD (QPHRASE \"this \"))))", 26 | "\"this\"": "(MODIFIER (TMODIFIER (FIELD (QPHRASE \"this\"))))", 27 | "*": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *))))", 28 | "*:*": "(MODIFIER (TMODIFIER (FIELD (QANYTHING *))))", 29 | "*t": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *t))))", 30 | "*t*": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *t*))))", 31 | "*t*\\a": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *t*\\a))))", 32 | "*t*a": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *t*a))))", 33 | "*t*a*": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *t*a*))))", 34 | "*t*a\\*": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *t*a\\*))))", 35 | "*t*a\\?": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *t*a\\?))))", 36 | "*t?": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *t?))))", 37 | "*t?a": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *t?a))))", 38 | "*t\\*a": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *t\\*a))))", 39 | "*te*t": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *te*t))))", 40 | "*te*t*": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED *te*t*))))", 41 | "+field:": false, 42 | "+field: {this TO that}": "(MODIFIER + (TMODIFIER (FIELD field (QRANGEEX (QNORMAL this) (QNORMAL that)))))", 43 | "+field:(-one +two three)": "(CLAUSE (MODIFIER + (TMODIFIER (FIELD field (DEFOP (MODIFIER - (TMODIFIER (FIELD (QNORMAL one)))) (MODIFIER + (TMODIFIER (FIELD (QNORMAL two)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL three)))))))))", 44 | "+field:[ this TO that ]": "(MODIFIER + (TMODIFIER (FIELD field (QRANGEIN (QNORMAL this) (QNORMAL that)))))", 45 | "+field:[this TO that]": "(MODIFIER + (TMODIFIER (FIELD field (QRANGEIN (QNORMAL this) (QNORMAL that)))))", 46 | "+field:{this TO that}": "(MODIFIER + (TMODIFIER (FIELD field (QRANGEEX (QNORMAL this) (QNORMAL that)))))", 47 | "+m:(a b c)": "(CLAUSE (MODIFIER + (TMODIFIER (FIELD m (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL a)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL b)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL c)))))))))", 48 | "+value": "(MODIFIER + (TMODIFIER (FIELD (QNORMAL value))))", 49 | "-field:(-one +two three)": "(CLAUSE (MODIFIER - (TMODIFIER (FIELD field (DEFOP (MODIFIER - (TMODIFIER (FIELD (QNORMAL one)))) (MODIFIER + (TMODIFIER (FIELD (QNORMAL two)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL three)))))))))", 50 | "-m:(a b NEAR c d AND e)": "(CLAUSE (MODIFIER - (TMODIFIER (FIELD m (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL a)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL b)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL NEAR)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL c)))) (AND (MODIFIER (TMODIFIER (FIELD (QNORMAL d)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL e))))))))))", 51 | "-value": "(MODIFIER - (TMODIFIER (FIELD (QNORMAL value))))", 52 | "0.9999": "(MODIFIER (TMODIFIER (FIELD (QNORMAL 0.9999))))", 53 | "00000000.9999": "(MODIFIER (TMODIFIER (FIELD (QNORMAL 00000000.9999))))", 54 | "9999": "(MODIFIER (TMODIFIER (FIELD (QNORMAL 9999))))", 55 | "9999.1": "(MODIFIER (TMODIFIER (FIELD (QNORMAL 9999.1))))", 56 | "?": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED ?))))", 57 | "?t": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED ?t))))", 58 | "?t*": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED ?t*))))", 59 | "?t?": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED ?t?))))", 60 | "?te*t?": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED ?te*t?))))", 61 | "[\"#$%^&\" TO \"&*()\"]": "(MODIFIER (TMODIFIER (FIELD (QRANGEIN (QPHRASE \"#$%^&\") (QPHRASETRUNC \"&*()\")))))", 62 | "[\"this\" TO \"that*\"]": "(MODIFIER (TMODIFIER (FIELD (QRANGEIN (QPHRASE \"this\") (QPHRASETRUNC \"that*\")))))", 63 | "[* 20030101]^0.5~": "(MODIFIER (TMODIFIER (BOOST ^0.5) (FUZZY ~) (FIELD (QRANGEIN (QANYTHING *) (QNORMAL 20030101)))))", 64 | "[* TO 20030101]": "(MODIFIER (TMODIFIER (FIELD (QRANGEIN (QANYTHING *) (QNORMAL 20030101)))))", 65 | "[* TO this]": "(MODIFIER (TMODIFIER (FIELD (QRANGEIN (QANYTHING *) (QNORMAL this)))))", 66 | "[* this]": "(MODIFIER (TMODIFIER (FIELD (QRANGEIN (QANYTHING *) (QNORMAL this)))))", 67 | "[20020101 *]^0.5~": "(MODIFIER (TMODIFIER (BOOST ^0.5) (FUZZY ~) (FIELD (QRANGEIN (QNORMAL 20020101) (QANYTHING *)))))", 68 | "[20020101 TO *]^0.5": "(MODIFIER (TMODIFIER (BOOST ^0.5) FUZZY (FIELD (QRANGEIN (QNORMAL 20020101) (QANYTHING *)))))", 69 | "[20020101 TO 20030101]": "(MODIFIER (TMODIFIER (FIELD (QRANGEIN (QNORMAL 20020101) (QNORMAL 20030101)))))", 70 | "[20020101 TO 20030101]^0.5": "(MODIFIER (TMODIFIER (BOOST ^0.5) FUZZY (FIELD (QRANGEIN (QNORMAL 20020101) (QNORMAL 20030101)))))", 71 | "[20020101 TO 20030101]^0.5~": "(MODIFIER (TMODIFIER (BOOST ^0.5) (FUZZY ~) (FIELD (QRANGEIN (QNORMAL 20020101) (QNORMAL 20030101)))))", 72 | "[]": false, 73 | "[this TO *]": "(MODIFIER (TMODIFIER (FIELD (QRANGEIN (QNORMAL this) (QANYTHING *)))))", 74 | "[this TO that]": "(MODIFIER (TMODIFIER (FIELD (QRANGEIN (QNORMAL this) (QNORMAL that)))))", 75 | "[this that]": "(MODIFIER (TMODIFIER (FIELD (QRANGEIN (QNORMAL this) (QNORMAL that)))))", 76 | "[this]": "(MODIFIER (TMODIFIER (FIELD (QRANGEIN (QNORMAL this) (QANYTHING *)))))", 77 | "\\(1\\+1\\)\\:2": "(MODIFIER (TMODIFIER (FIELD (QNORMAL \\(1\\+1\\)\\:2))))", 78 | "\\*t": "(MODIFIER (TMODIFIER (FIELD (QNORMAL \\*t))))", 79 | "a\\\\\\+b": "(MODIFIER (TMODIFIER (FIELD (QNORMAL a\\\\\\+b))))", 80 | "a\\u0062c": "(MODIFIER (TMODIFIER (FIELD (QNORMAL a\\u0062c))))", 81 | "escape:(\\+\\-\\&\\&\\|\\|\\!\\(\\)\\{\\}\\[\\]\\^\"\\~\\*\\?\\:\\)": false, 82 | "field: (one)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD field (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL one)))))))))", 83 | "field:( one )": "(CLAUSE (MODIFIER (TMODIFIER (FIELD field (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL one)))))))))", 84 | "field:(one +two -three)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD field (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL one)))) (MODIFIER + (TMODIFIER (FIELD (QNORMAL two)))) (MODIFIER - (TMODIFIER (FIELD (QNORMAL three)))))))))", 85 | "field:(one two three)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD field (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL one)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL two)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL three)))))))))", 86 | "field:(one)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD field (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL one)))))))))", 87 | "foo:*": "(MODIFIER (TMODIFIER (FIELD foo (QTRUNCATED *))))", 88 | "m:(+a b c)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD m (DEFOP (MODIFIER + (TMODIFIER (FIELD (QNORMAL a)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL b)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL c)))))))))", 89 | "m:(-a +b c)^0.6": "(CLAUSE (MODIFIER (TMODIFIER (BOOST ^0.6) FUZZY (FIELD m (DEFOP (MODIFIER - (TMODIFIER (FIELD (QNORMAL a)))) (MODIFIER + (TMODIFIER (FIELD (QNORMAL b)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL c)))))))))", 90 | "m:(a b NEAR c d AND e)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD m (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL a)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL b)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL NEAR)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL c)))) (AND (MODIFIER (TMODIFIER (FIELD (QNORMAL d)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL e))))))))))", 91 | "m:(a b NEAR c)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD m (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL a)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL b)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL NEAR)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL c)))))))))", 92 | "m:(a b c OR d NOT e)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD m (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL a)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL b)))) (OR (MODIFIER (TMODIFIER (FIELD (QNORMAL c)))) (NOT (MODIFIER (TMODIFIER (FIELD (QNORMAL d)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL e)))))))))))", 93 | "m:(a b c OR d)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD m (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL a)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL b)))) (OR (MODIFIER (TMODIFIER (FIELD (QNORMAL c)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL d))))))))))", 94 | "m:(a b c or d)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD m (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL a)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL b)))) (OR (MODIFIER (TMODIFIER (FIELD (QNORMAL c)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL d))))))))))", 95 | "m:(a b c)": "(CLAUSE (MODIFIER (TMODIFIER (FIELD m (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL a)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL b)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL c)))))))))", 96 | "roam^": "(MODIFIER (TMODIFIER (BOOST ^) FUZZY (FIELD (QNORMAL roam))))", 97 | "roam^0.8": "(MODIFIER (TMODIFIER (BOOST ^0.8) FUZZY (FIELD (QNORMAL roam))))", 98 | "roam^0.899999999": "(MODIFIER (TMODIFIER (BOOST ^0.899999999) FUZZY (FIELD (QNORMAL roam))))", 99 | "roam^0.899999999~0.5": "(MODIFIER (TMODIFIER (BOOST ^0.899999999) (FUZZY ~0.5) (FIELD (QNORMAL roam))))", 100 | "roam^0.8~": "(MODIFIER (TMODIFIER (BOOST ^0.8) (FUZZY ~) (FIELD (QNORMAL roam))))", 101 | "roam^8": "(MODIFIER (TMODIFIER (BOOST ^8) FUZZY (FIELD (QNORMAL roam))))", 102 | "roam^~": "(MODIFIER (TMODIFIER (BOOST ^) (FUZZY ~) (FIELD (QNORMAL roam))))", 103 | "roam~": "(MODIFIER (TMODIFIER BOOST (FUZZY ~) (FIELD (QNORMAL roam))))", 104 | "roam~0.8": "(MODIFIER (TMODIFIER BOOST (FUZZY ~0.8) (FIELD (QNORMAL roam))))", 105 | "roam~0.899999999": "(MODIFIER (TMODIFIER BOOST (FUZZY ~0.899999999) (FIELD (QNORMAL roam))))", 106 | "roam~0.899999999^0.5": "(MODIFIER (TMODIFIER (BOOST ^0.5) (FUZZY ~0.899999999) (FIELD (QNORMAL roam))))", 107 | "roam~0.8^": "(MODIFIER (TMODIFIER (BOOST ^) (FUZZY ~0.8) (FIELD (QNORMAL roam))))", 108 | "roam~8": "(MODIFIER (TMODIFIER BOOST (FUZZY ~8) (FIELD (QNORMAL roam))))", 109 | "roam~^": "(MODIFIER (TMODIFIER (BOOST ^) (FUZZY ~) (FIELD (QNORMAL roam))))", 110 | "t*a": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED t*a))))", 111 | "t*a?": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED t*a?))))", 112 | "t*a?a": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED t*a?a))))", 113 | "te*?t": true, 114 | "te*t": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED te*t))))", 115 | "te??t": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED te??t))))", 116 | "te?t": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED te?t))))", 117 | "test*": "(MODIFIER (TMODIFIER (FIELD (QTRUNCATED test*))))", 118 | "th\\*is": "(MODIFIER (TMODIFIER (FIELD (QNORMAL th\\*is))))", 119 | "this": "(MODIFIER (TMODIFIER (FIELD (QNORMAL this))))", 120 | "this0.9": "(MODIFIER (TMODIFIER (FIELD (QNORMAL this0.9))))", 121 | "this999": "(MODIFIER (TMODIFIER (FIELD (QNORMAL this999))))", 122 | "this^ 5": "(MODIFIER (TMODIFIER (BOOST ^) FUZZY (FIELD (QNORMAL this))))", 123 | "this^5~ 9": "(MODIFIER (TMODIFIER (BOOST ^5) (FUZZY ~) (FIELD (QNORMAL this))))", 124 | "title:(+return +\"pink panther\")": "(CLAUSE (MODIFIER (TMODIFIER (FIELD title (DEFOP (MODIFIER + (TMODIFIER (FIELD (QNORMAL return)))) (MODIFIER + (TMODIFIER (FIELD (QPHRASE \"pink panther\")))))))))", 125 | "title:[20020101 TO 20030101]": "(MODIFIER (TMODIFIER (FIELD title (QRANGEIN (QNORMAL 20020101) (QNORMAL 20030101)))))", 126 | "title:[20020101 TO 20030101]^0.5": "(MODIFIER (TMODIFIER (BOOST ^0.5) FUZZY (FIELD title (QRANGEIN (QNORMAL 20020101) (QNORMAL 20030101)))))", 127 | "title:[20020101 TO 20030101]^0.5~": "(MODIFIER (TMODIFIER (BOOST ^0.5) (FUZZY ~) (FIELD title (QRANGEIN (QNORMAL 20020101) (QNORMAL 20030101)))))", 128 | "title:{20020101 TO 20030101}": "(MODIFIER (TMODIFIER (FIELD title (QRANGEEX (QNORMAL 20020101) (QNORMAL 20030101)))))", 129 | "title:{20020101 TO 20030101}^0.5": "(MODIFIER (TMODIFIER (BOOST ^0.5) FUZZY (FIELD title (QRANGEEX (QNORMAL 20020101) (QNORMAL 20030101)))))", 130 | "title:{20020101 TO 20030101}^0.5~": "(MODIFIER (TMODIFIER (BOOST ^0.5) (FUZZY ~) (FIELD title (QRANGEEX (QNORMAL 20020101) (QNORMAL 20030101)))))", 131 | "title:{Aida TO Carmen}": "(MODIFIER (TMODIFIER (FIELD title (QRANGEEX (QNORMAL Aida) (QNORMAL Carmen)))))", 132 | "{\"#$%^&\" TO \"&*()\"}": "(MODIFIER (TMODIFIER (FIELD (QRANGEEX (QPHRASE \"#$%^&\") (QPHRASETRUNC \"&*()\")))))", 133 | "{\"this\" TO \"that*\"}": "(MODIFIER (TMODIFIER (FIELD (QRANGEEX (QPHRASE \"this\") (QPHRASETRUNC \"that*\")))))", 134 | "{* 20030101}^0.5~": "(MODIFIER (TMODIFIER (BOOST ^0.5) (FUZZY ~) (FIELD (QRANGEEX (QANYTHING *) (QNORMAL 20030101)))))", 135 | "{* TO 20030101}^0.5": "(MODIFIER (TMODIFIER (BOOST ^0.5) FUZZY (FIELD (QRANGEEX (QANYTHING *) (QNORMAL 20030101)))))", 136 | "{* TO this}": "(MODIFIER (TMODIFIER (FIELD (QRANGEEX (QANYTHING *) (QNORMAL this)))))", 137 | "{* this}": "(MODIFIER (TMODIFIER (FIELD (QRANGEEX (QANYTHING *) (QNORMAL this)))))", 138 | "{20020101 *}^0.5~": "(MODIFIER (TMODIFIER (BOOST ^0.5) (FUZZY ~) (FIELD (QRANGEEX (QNORMAL 20020101) (QANYTHING *)))))", 139 | "{20020101 TO *}": "(MODIFIER (TMODIFIER (FIELD (QRANGEEX (QNORMAL 20020101) (QANYTHING *)))))", 140 | "{20020101 TO 20030101}": "(MODIFIER (TMODIFIER (FIELD (QRANGEEX (QNORMAL 20020101) (QNORMAL 20030101)))))", 141 | "{20020101 TO 20030101}^0.5": "(MODIFIER (TMODIFIER (BOOST ^0.5) FUZZY (FIELD (QRANGEEX (QNORMAL 20020101) (QNORMAL 20030101)))))", 142 | "{20020101 TO 20030101}^0.5~": "(MODIFIER (TMODIFIER (BOOST ^0.5) (FUZZY ~) (FIELD (QRANGEEX (QNORMAL 20020101) (QNORMAL 20030101)))))", 143 | "{this TO *}": "(MODIFIER (TMODIFIER (FIELD (QRANGEEX (QNORMAL this) (QANYTHING *)))))", 144 | "{this TO that}": "(MODIFIER (TMODIFIER (FIELD (QRANGEEX (QNORMAL this) (QNORMAL that)))))", 145 | "{this that}": "(MODIFIER (TMODIFIER (FIELD (QRANGEEX (QNORMAL this) (QNORMAL that)))))", 146 | "{}": false 147 | }, 148 | "mainQ": { 149 | "\"jakarta apache\" AND \"Apache Lucene\"": "(DEFOP (AND (MODIFIER (TMODIFIER (FIELD (QPHRASE \"jakarta apache\")))) (MODIFIER (TMODIFIER (FIELD (QPHRASE \"Apache Lucene\"))))))", 150 | "\"jakarta apache\" NOT \"Apache Lucene\"": "(DEFOP (NOT (MODIFIER (TMODIFIER (FIELD (QPHRASE \"jakarta apache\")))) (MODIFIER (TMODIFIER (FIELD (QPHRASE \"Apache Lucene\"))))))", 151 | "\"jakarta apache\" OR jakarta": "(DEFOP (OR (MODIFIER (TMODIFIER (FIELD (QPHRASE \"jakarta apache\")))) (MODIFIER (TMODIFIER (FIELD (QNORMAL jakarta))))))", 152 | "\"jakarta apache\"^4 \"Apache Lucene\"": "(DEFOP (MODIFIER (TMODIFIER (BOOST ^4) FUZZY (FIELD (QPHRASE \"jakarta apache\")))) (MODIFIER (TMODIFIER (FIELD (QPHRASE \"Apache Lucene\")))))", 153 | "(jakarta OR apache) AND website": "(DEFOP (AND (OR (MODIFIER (TMODIFIER (FIELD (QNORMAL jakarta)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL apache))))) (MODIFIER (TMODIFIER (FIELD (QNORMAL website))))))", 154 | "(this) ((((((that))))))": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))))", 155 | "(this) (that)": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))))", 156 | "+jakarta lucene": "(DEFOP (MODIFIER + (TMODIFIER (FIELD (QNORMAL jakarta)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL lucene)))))", 157 | "jakarta^4 apache": "(DEFOP (MODIFIER (TMODIFIER (BOOST ^4) FUZZY (FIELD (QNORMAL jakarta)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL apache)))))", 158 | "this ((((+(that)))))": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (CLAUSE (MODIFIER + (TMODIFIER (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))))))))", 159 | "this ((that))": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))))", 160 | "this (+(((+(that))))": false, 161 | "this (+(((+(that)))))": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (CLAUSE (MODIFIER + (TMODIFIER (DEFOP (CLAUSE (MODIFIER + (TMODIFIER (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))))))))))))", 162 | "this (+(that)^7)": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (CLAUSE (MODIFIER + (TMODIFIER (BOOST ^7) FUZZY (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))))))))", 163 | "this (++(((+(that)))))": false, 164 | "this (that)": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))))", 165 | "this +((((+(that)))))": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (CLAUSE (MODIFIER + (TMODIFIER (DEFOP (CLAUSE (MODIFIER + (TMODIFIER (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))))))))))))", 166 | "this +(+((((that)))))": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (CLAUSE (MODIFIER + (TMODIFIER (DEFOP (CLAUSE (MODIFIER + (TMODIFIER (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))))))))))))", 167 | "this +(that thus)^7": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (CLAUSE (MODIFIER + (TMODIFIER (BOOST ^7) FUZZY (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL thus)))))))))", 168 | "this +(that)": "(DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL this)))) (CLAUSE (MODIFIER + (TMODIFIER (DEFOP (MODIFIER (TMODIFIER (FIELD (QNORMAL that)))))))))", 169 | "title:\"X x\" AND text:go title:\"x y\" AND A": "(DEFOP (AND (MODIFIER (TMODIFIER (FIELD title (QPHRASE \"X x\")))) (MODIFIER (TMODIFIER (FIELD text (QNORMAL go))))) (AND (MODIFIER (TMODIFIER (FIELD title (QPHRASE \"x y\")))) (MODIFIER (TMODIFIER (FIELD (QNORMAL A))))))", 170 | "title:X Y Z": "(DEFOP (MODIFIER (TMODIFIER (FIELD title (QNORMAL X)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL Y)))) (MODIFIER (TMODIFIER (FIELD (QNORMAL Z)))))" 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /test_java_queryparser.js: -------------------------------------------------------------------------------- 1 | // jrunscript -cp "/usr/local/Cellar/elasticsearch/1.7.2/libexec/lucene-queryparser-4.10.4.jar:/usr/local/Cellar/elasticsearch/1.7.2/libexec/lucene-core-4.10.4.jar" -f test_java_queryparser.js 2 | 3 | function openJsonFile(path) { 4 | var data = java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(path)); 5 | var str = new java.lang.String(data, 'utf-8'); 6 | return JSON.parse(str); 7 | } 8 | 9 | qp = new org.apache.lucene.queryparser.flexible.standard.StandardQueryParser() 10 | qp.setAllowLeadingWildcard(true); 11 | 12 | var examples = openJsonFile('test_java_queryparser_examples.json') 13 | 14 | var failures = 0; 15 | var results = {}; 16 | for (var query in examples) { 17 | var expect = examples[query]; 18 | var result; 19 | try { 20 | result = qp.parse(query, '_all').toString(); 21 | } catch (exc) { 22 | result = null; 23 | } 24 | results[query] = result; 25 | if (result !== expect) { 26 | print('FAIL ' + JSON.stringify(query) + ' GOT ' + JSON.stringify(result) + ' EXPECTED ' + JSON.stringify(expect)); 27 | failures++; 28 | } 29 | } 30 | 31 | print('Ran ' + Object.keys(examples).length + ' tests, ' + failures + ' failed.'); 32 | 33 | if (failures) { 34 | print(JSON.stringify(results, null, 4)); 35 | throw 'failed'; 36 | } 37 | -------------------------------------------------------------------------------- /test_java_queryparser_examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "9999": "_all:9999", 3 | "\" this \"": "_all: this ", 4 | "\"*te*t\"": "_all:*te*t", 5 | "\"*te*t*\"": "_all:*te*t*", 6 | "\"+() AND that\"": "_all:+() AND that", 7 | "\"?te*t?\"": "_all:?te*t?", 8 | "\"a \\\"b c\\\" d\"": "_all:a \"b c\" d", 9 | "\"a \\+b c d\"": "_all:a +b c d", 10 | "\"func(*) AND that\"": "_all:func(*) AND that", 11 | "\"jakarta apache\"": "_all:jakarta apache", 12 | "\"jakarta apache\"^10": "_all:jakarta apache^10.0", 13 | "\"jakarta apache\"^10~": null, 14 | "\"jakarta apache\"^10~0.6": null, 15 | "\"jakarta apache\"~10": "_all:jakarta apache", 16 | "\"jakarta apache\"~10^": null, 17 | "\"jakarta apache\"~10^0.6": "_all:jakarta apache^0.6", 18 | "\"te*?t\"": "_all:te*?t", 19 | "\"te*t\"": "_all:te*t", 20 | "\"te??t\"": "_all:te??t", 21 | "\"te?t\"": "_all:te?t", 22 | "\"test*\"": "_all:test*", 23 | "\"text\"": "_all:text", 24 | "\"this \"": "_all:this ", 25 | "\"this \" ": "_all:this ", 26 | "\"this\"": "_all:this", 27 | "*": "_all:*", 28 | "*:*": "*:*", 29 | "*t": "_all:*t", 30 | "*t*": "_all:*t*", 31 | "*t*\\a": "_all:*t*a", 32 | "*t*a": "_all:*t*a", 33 | "*t*a*": "_all:*t*a*", 34 | "*t*a\\*": "_all:*t*a*", 35 | "*t*a\\?": "_all:*t*a?", 36 | "*t?": "_all:*t?", 37 | "*t?a": "_all:*t?a", 38 | "*t\\*a": "_all:*t*a", 39 | "*te*t": "_all:*te*t", 40 | "*te*t*": "_all:*te*t*", 41 | "+field:": null, 42 | "+field: {this TO that}": "field:{this TO that}", 43 | "+field:(-one +two three)": "-field:one +field:two field:three", 44 | "+field:[ this TO that ]": "field:[this TO that]", 45 | "+field:[this TO that]": "field:[this TO that]", 46 | "+field:{this TO that}": "field:{this TO that}", 47 | "+m:(a b c)": "m:a m:b m:c", 48 | "+value": "_all:value", 49 | "-field:(-one +two three)": "-field:one +field:two field:three", 50 | "-m:(a b NEAR c d AND e)": "m:a m:b m:NEAR m:c +m:d +m:e", 51 | "-value": "_all:value", 52 | "0.9999": "_all:0.9999", 53 | "00000000.9999": "_all:00000000.9999", 54 | "9999.1": "_all:9999.1", 55 | "?": "_all:?", 56 | "?t": "_all:?t", 57 | "?t*": "_all:?t*", 58 | "?t?": "_all:?t?", 59 | "?te*t?": "_all:?te*t?", 60 | "[\"#$%^&\" TO \"&*()\"]": "_all:[#$%^& TO &*()]", 61 | "[\"this\" TO \"that*\"]": "_all:[this TO that*]", 62 | "[* 20030101]^0.5~": null, 63 | "[* TO 20030101]": "_all:[* TO 20030101]", 64 | "[* TO this]": "_all:[* TO this]", 65 | "[* this]": "_all:[* TO this]", 66 | "[20020101 *]^0.5~": null, 67 | "[20020101 TO *]^0.5": "_all:[20020101 TO *]^0.5", 68 | "[20020101 TO 20030101]": "_all:[20020101 TO 20030101]", 69 | "[20020101 TO 20030101]^0.5": "_all:[20020101 TO 20030101]^0.5", 70 | "[20020101 TO 20030101]^0.5~": null, 71 | "[]": null, 72 | "[this TO *]": "_all:[this TO *]", 73 | "[this TO that]": "_all:[this TO that]", 74 | "[this that]": "_all:[this TO that]", 75 | "[this]": null, 76 | "\\(1\\+1\\)\\:2": "_all:(1+1):2", 77 | "\\*t": "_all:*t", 78 | "a\\\\\\+b": "_all:a\\+b", 79 | "a\\u0062c": "_all:abc", 80 | "escape:(\\+\\-\\&\\&\\|\\|\\!\\(\\)\\{\\}\\[\\]\\^\"\\~\\*\\?\\:\\)": null, 81 | "field: (one)": "field:one", 82 | "field:( one )": "field:one", 83 | "field:(one +two -three)": "field:one +field:two -field:three", 84 | "field:(one two three)": "field:one field:two field:three", 85 | "field:(one)": "field:one", 86 | "foo:*": "foo:*", 87 | "m:(+a b c)": "+m:a m:b m:c", 88 | "m:(-a +b c)^0.6": "(-m:a +m:b m:c)^0.6", 89 | "m:(a b NEAR c d AND e)": "m:a m:b m:NEAR m:c +m:d +m:e", 90 | "m:(a b NEAR c)": "m:a m:b m:NEAR m:c", 91 | "m:(a b c OR d NOT e)": "m:a m:b m:c m:d -m:e", 92 | "m:(a b c OR d)": "m:a m:b m:c m:d", 93 | "m:(a b c or d)": "m:a m:b m:c m:or m:d", 94 | "m:(a b c)": "m:a m:b m:c", 95 | "roam^": null, 96 | "roam^0.8": "_all:roam^0.8", 97 | "roam^0.899999999": "_all:roam^0.9", 98 | "roam^0.899999999~0.5": "_all:roam~2^0.9", 99 | "roam^0.8~": "_all:roam~2^0.8", 100 | "roam^8": "_all:roam^8.0", 101 | "roam^~": null, 102 | "roam~": "_all:roam~2", 103 | "roam~0.8": "_all:roam~0", 104 | "roam~0.899999999": "_all:roam~0", 105 | "roam~0.899999999^0.5": "_all:roam~0^0.5", 106 | "roam~0.8^": null, 107 | "roam~8": "_all:roam~2", 108 | "roam~^": null, 109 | "t*a": "_all:t*a", 110 | "t*a?": "_all:t*a?", 111 | "t*a?a": "_all:t*a?a", 112 | "te*?t": "_all:te*?t", 113 | "te*t": "_all:te*t", 114 | "te??t": "_all:te??t", 115 | "te?t": "_all:te?t", 116 | "test*": "_all:test*", 117 | "th\\*is": "_all:th*is", 118 | "this": "_all:this", 119 | "this0.9": "_all:this0.9", 120 | "this999": "_all:this999", 121 | "this^ 5": null, 122 | "this^5~ 9": "_all:this~2^5.0 _all:9", 123 | "title:(+return +\"pink panther\")": "+title:return +title:pink panther", 124 | "title:[20020101 TO 20030101]": "title:[20020101 TO 20030101]", 125 | "title:[20020101 TO 20030101]^0.5": "title:[20020101 TO 20030101]^0.5", 126 | "title:[20020101 TO 20030101]^0.5~": null, 127 | "title:{20020101 TO 20030101}": "title:{20020101 TO 20030101}", 128 | "title:{20020101 TO 20030101}^0.5": "title:{20020101 TO 20030101}^0.5", 129 | "title:{20020101 TO 20030101}^0.5~": null, 130 | "title:{Aida TO Carmen}": "title:{aida TO carmen}", 131 | "{\"#$%^&\" TO \"&*()\"}": "_all:{#$%^& TO &*()}", 132 | "{\"this\" TO \"that*\"}": "_all:{this TO that*}", 133 | "{* 20030101}^0.5~": null, 134 | "{* TO 20030101}^0.5": "_all:{* TO 20030101}^0.5", 135 | "{* TO this}": "_all:{* TO this}", 136 | "{* this}": "_all:{* TO this}", 137 | "{20020101 *}^0.5~": null, 138 | "{20020101 TO *}": "_all:{20020101 TO *}", 139 | "{20020101 TO 20030101}": "_all:{20020101 TO 20030101}", 140 | "{20020101 TO 20030101}^0.5": "_all:{20020101 TO 20030101}^0.5", 141 | "{20020101 TO 20030101}^0.5~": null, 142 | "{this TO *}": "_all:{this TO *}", 143 | "{this TO that}": "_all:{this TO that}", 144 | "{this that}": "_all:{this TO that}", 145 | "{}": null, 146 | "\"jakarta apache\" AND \"Apache Lucene\"": "+_all:jakarta apache +_all:Apache Lucene", 147 | "\"jakarta apache\" NOT \"Apache Lucene\"": "_all:jakarta apache -_all:Apache Lucene", 148 | "\"jakarta apache\" OR jakarta": "_all:jakarta apache _all:jakarta", 149 | "\"jakarta apache\"^4 \"Apache Lucene\"": "_all:jakarta apache^4.0 _all:Apache Lucene", 150 | "(jakarta OR apache) AND website": "+(_all:jakarta _all:apache) +_all:website", 151 | "(this) ((((((that))))))": "_all:this _all:that", 152 | "(this) (that)": "_all:this _all:that", 153 | "+jakarta lucene": "+_all:jakarta _all:lucene", 154 | "jakarta^4 apache": "_all:jakarta^4.0 _all:apache", 155 | "this ((((+(that)))))": "_all:this _all:that", 156 | "this ((that))": "_all:this _all:that", 157 | "this (+(((+(that))))": null, 158 | "this (+(((+(that)))))": "_all:this _all:that", 159 | "this (+(that)^7)": "_all:this _all:that^7.0", 160 | "this (++(((+(that)))))": null, 161 | "this (that)": "_all:this _all:that", 162 | "this +((((+(that)))))": "_all:this +_all:that", 163 | "this +(+((((that)))))": "_all:this +_all:that", 164 | "this +(that thus)^7": "_all:this +((_all:that _all:thus)^7.0)", 165 | "this +(that)": "_all:this +_all:that", 166 | "title:\"X x\" AND text:go title:\"x y\" AND A": "+title:X x +text:go +title:x y +_all:A", 167 | "title:X Y Z": "title:X _all:Y _all:Z" 168 | } 169 | -------------------------------------------------------------------------------- /test_lucenequery.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import json 3 | import os.path 4 | here = os.path.abspath(os.path.dirname(__file__)) 5 | string_trees = json.load(open(os.path.join(here, 'string_trees.json'))) 6 | 7 | 8 | @pytest.fixture(params=['standard', 'elasticsearch']) 9 | def dialect(request): 10 | from lucenequery import dialects 11 | return getattr(dialects, request.param) 12 | 13 | 14 | @pytest.mark.parametrize(['query', 'result'], [ 15 | (query, result) 16 | for entry, tests in string_trees.items() 17 | for query, result in tests.items() 18 | if type(result) is type(u'') 19 | ]) 20 | def test_string_tree(dialect, query, result): 21 | from lucenequery import parse 22 | clause = parse(query, dialect=dialect) 23 | assert clause.getText() == query.strip() 24 | # `result` is the antlr3 rewritten tree, so just check it parses for now. 25 | clause.toStringTree(recog=clause.parser) 26 | 27 | 28 | @pytest.mark.parametrize('query', [ 29 | query 30 | for entry, tests in string_trees.items() 31 | for query, result in tests.items() 32 | if result is False 33 | ]) 34 | def test_parse_fail(dialect, query): 35 | from antlr4 import IllegalStateException 36 | from lucenequery import parse 37 | with pytest.raises(IllegalStateException): 38 | parse(query, dialect=dialect) 39 | 40 | 41 | @pytest.mark.parametrize('query', [ 42 | query 43 | for entry, tests in string_trees.items() 44 | for query, result in tests.items() 45 | if result is True 46 | ]) 47 | def test_parse_ok(dialect, query): 48 | from lucenequery import parse 49 | clause = parse(query, dialect=dialect) 50 | assert clause.getText() == query.strip() 51 | 52 | 53 | @pytest.mark.parametrize('query', [ 54 | 'age:<10', 55 | 'age:>10', 56 | 'age:<=10', 57 | 'age:>=10', 58 | 59 | ]) 60 | def test_one_sided_range(query): 61 | from lucenequery import parse 62 | from lucenequery import dialects 63 | clause = parse(query, dialect=dialects.elasticsearch) 64 | assert clause.getText() == query 65 | 66 | 67 | @pytest.mark.parametrize(['query', 'expect'], [ 68 | ('foo:bar', 'prefix.foo:bar'), 69 | ('foo:bar baz', 'prefix.foo:bar baz'), 70 | ('foo:bar AND (a:b OR c:d)', 71 | 'prefix.foo:bar AND (prefix.a:b OR prefix.c:d)'), 72 | ]) 73 | def test_prefixfields(dialect, query, expect): 74 | from lucenequery import dialects 75 | from lucenequery.prefixfields import prefixfields 76 | clause = prefixfields('prefix.', query, dialect=dialects.elasticsearch) 77 | assert clause.getText() == expect 78 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27,py35 3 | 4 | [testenv] 5 | deps=pytest 6 | commands=py.test {posargs} 7 | -------------------------------------------------------------------------------- /travis-antlr4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | if [ ! -e "$HOME/antlr4/bin/antlr4" ]; then 4 | mkdir -p "$HOME/antlr4/bin"; 5 | curl http://www.antlr.org/download/antlr-4.5.2-complete.jar -o "$HOME/antlr4/antlr-4.5.2-complete.jar"; 6 | cat <<'EOF' >"$HOME/antlr4/bin/antlr4" 7 | #!/bin/bash 8 | exec java -jar "$HOME/antlr4/antlr-4.5.2-complete.jar" "$@" 9 | EOF 10 | chmod +x "$HOME/antlr4/bin/antlr4"; 11 | else 12 | echo 'Using cached antlr4'; 13 | fi 14 | --------------------------------------------------------------------------------