package org.apache.lucene.queryparser.flexible.aqp;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.standard.StandardQueryParser;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.Operator;
import org.apache.lucene.queryparser.flexible.aqp.AqpQueryParser;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
/**
* This test case is a copy of the core Lucene query parser test, it was adapted
* to use new QueryParserHelper instead of the old query parser.
*
* Tests QueryParser.
*/
public class TestAqpSLGSimple extends AqpTestAbstractCase {
private boolean verbose = true;
private int originalMaxClauses;
@Override
public void setUp() throws Exception {
super.setUp();
originalMaxClauses = BooleanQuery.getMaxClauseCount();
setGrammarName("StandardLuceneGrammar");
}
public void testBooleanQuery() throws Exception {
WhitespaceAnalyzer analyzer = new WhitespaceAnalyzer();
AqpQueryParser qp = getParser(analyzer);
StandardQueryParser sp = (StandardQueryParser) getParser(analyzer, true);
// DEFAULT OPERATOR IS AND
qp.setDefaultOperator(Operator.AND);
sp.setDefaultOperator(Operator.AND);
// test the clause rewriting/optimization
Query q = qp.parse("a -(-(+(-(x)^0.6))^0.2)^0.3", "");
assertQueryMatch(qp, "a -(-(+(-(x)^0.6))^0.2)^0.3", "", "+a -(x)^0.3");
assertQueryMatch(qp, "-(-(+(-(x)^0.6))^0.2)^0.3", "", "(x)^0.3"); // not
// minus,
// because
// that is
// not
// allowed
assertQueryMatch(qp, "-(-(+(-(x)^0.6))^0.2)^", "", "(x)^1.0"); // because defualt
// boost is 1.0f
assertQueryMatch(qp, "-(-(+(-(x)^))^0.2)^0.1", "", "(x)^0.1"); // because
// defualt
// boost is
// 1.0f
Query qa = sp.parse("kahnn-strauss", "x");
Query qb = qp.parse("kahnn-strauss", "x");
assertQueryMatch(qp, "kahnn-strauss", "x", qa.toString());
qa = sp.parse("a \\\"b \\\"c d", "x");
qb = qp.parse("a \\\"b \\\"c d", "x");
assertQueryMatch(qp, "a \\\"b \\\"c d", "x", qa.toString());
qa = sp.parse("\"a \\\"b c\\\" d\"", "x");
qb = qp.parse("\"a \\\"b c\\\" d\"", "x");
assertQueryMatch(qp, "\"a \\\"b c\\\" d\"", "x", qa.toString());
assertQueryMatch(qp, "+(-(-(-(x)^0.6))^0.2)^", "field", "(field:x)^1.0");
assertQueryMatch(qp, "+(-(-(-(x)^0.6))^0.2)^0.5", "field", "(field:x)^0.5");
// the first element will be positive, because the negative X NOT Y
// is currently implemented that way (the first must return something)
// TODO: this should be:
// "((+field:a +field:b)^0.8) -((+field:x +field:y)^0.2)"
assertQueryMatch(qp, "(+(-(a b)))^0.8 OR -(x y)^0.2", "field",
"+(+field:a +field:b)^0.8 -(+field:x +field:y)^0.2");
assertQueryMatch(qp, "(+(-(a b)))^0.8 AND -(x y)^0.2", "field",
"+(+field:a +field:b)^0.8 -(+field:x +field:y)^0.2");
assertQueryMatch(qp, "(+(-(a b)))^0.8 -(x y)", "field",
"+(+field:a +field:b)^0.8 -(+field:x +field:y)");
// or does -(x y) have different semantics? ... -field:x -field:y
// +((-(+field:a +field:b))^0.8) -field:x -field:y
assertQueryMatch(qp, "+((+(-(a b)))^0.8)^0.7 OR -(x y)^0.2", "field",
"+(+field:a +field:b)^0.7 -(+field:x +field:y)^0.2");
assertQueryMatch(qp, "+title:(dog cat)", "field", "+title:dog +title:cat");
assertQueryMatch(qp, "title:(+dog -cat)", "field", "+title:dog -title:cat");
qp.setAllowLeadingWildcard(true);
assertQueryMatch(qp, "\\*", "field", "field:*");
qp.setAllowLeadingWildcard(false);
assertQueryMatch(qp, "term~", "field", "field:term~2");
assertQueryMatch(qp, "term~1", "field", "field:term~1");
assertQueryMatch(qp, "term~2", "field", "field:term~2");
qp.setAllowSlowFuzzy(true);
assertQueryMatch(qp, "term~", "field", "field:term~0.5");
assertQueryMatch(qp, "term~0.1", "field", "field:term~0.1");
assertQueryMatch(qp, "term~0.2", "field", "field:term~0.2");
qp.setAllowSlowFuzzy(false);
assertQueryMatch(qp, "something", "field", "field:something");
assertQueryMatch(qp, "x:something", "field", "x:something");
assertQueryMatch(qp, "x:\"something else\"", "field",
"x:\"something else\"");
assertQueryMatch(qp, "x:\"someth*\"", "field", "x:someth*");
assertQueryMatch(qp, "x:\"someth?ng\"", "field", "x:someth?ng");
assertQueryMatch(qp, "A AND B C AND D", "field",
"+field:A +field:B +field:C +field:D");
assertQueryMatch(qp, "A AND B C AND D OR E", "field",
"+(+field:A +field:B) +((+field:C +field:D) field:E)");
assertQueryMatch(qp, "one OR +two", "f", "f:one +f:two");
assertQueryMatch(qp, "one OR two NOT three", "field",
"field:one (+field:two -field:three)");
assertQueryMatch(qp, "one OR (two AND three) NOT four", "field",
"field:one (+(+field:two +field:three) -field:four)");
assertQueryMatch(qp, "-one -two", "field", "-field:one -field:two");
assertQueryMatch(qp, "x:one NOT y:two -three^0.5", "field",
"+(+x:one -y:two) -(field:three)^0.5");
qp.setAllowSlowFuzzy(true);
assertQueryMatch(qp, "one NOT two -three~0.2", "field",
"+(+field:one -field:two) -field:three~0.2");
assertQueryMatch(qp, "one NOT two NOT three~0.2", "field",
"+field:one -field:two -field:three~0.2");
assertQueryMatch(qp, "one two^0.5 three~0.2", "field",
"+field:one +(field:two)^0.5 +field:three~0.2");
qp.setAllowSlowFuzzy(false);
assertQueryMatch(qp, "one NOT two -three~0.2", "field",
"+(+field:one -field:two) -field:three~2");
assertQueryMatch(qp, "one NOT two NOT three~0.2", "field",
"+field:one -field:two -field:three~2");
assertQueryMatch(qp, "one two^0.5 three~0.2", "field",
"+field:one +(field:two)^0.5 +field:three~2");
q = qp.parse("one (two three)^0.8", "field");
// I know where the problem is: builder does not have access
// to the config, so that when a default operator is changed
// *after* the parser was instantiated, the builder behaves
// the old way(s) -- this is a bigger problem, and I didn't
// want to change the flex parser API
// patch is in LUCENE-5014, I'll uncomment it here just to
// not have to change the BooleanQueryNodeBuilder class
//((QueryTreeBuilder) qp.getQueryBuilder()).setBuilder(BooleanQueryNode.class, new BooleanQueryNodeBuilder(BooleanClause.Occur.MUST));
//qa = qp.parse("one (two three)^0.8", "field");
//assertQueryMatch(qp, "one (two three)^0.8", "field",
// "+field:one +((+field:two +field:three)^0.8)");
//assertQueryMatch(qp, "one (x:two three)^0.8", "field",
// "+field:one +((+x:two +field:three)^0.8)");
// TODO: the original value was -((+one:two +one:three)^0.8)
// but that is not a valid Lucene query (or is it?)
assertQueryMatch(qp, "-one:(two three)^0.8", "field",
"(+one:two +one:three)^0.8");
assertQueryMatch(qp, "one:(two three)^0.8", "field",
"(+one:two +one:three)^0.8");
assertQueryMatch(qp, "+one:(two three)^0.8", "field",
"(+one:two +one:three)^0.8");
assertQueryMatch(qp, "[one TO five]", "field", "field:[one TO five]");
assertQueryMatch(qp, "z:[one TO five]", "field", "z:[one TO five]");
assertQueryMatch(qp, "{one TO five}", "field", "field:{one TO five}");
assertQueryMatch(qp, "z:{one TO five}", "field", "z:{one TO five}");
assertQueryMatch(qp, "z:{\"one\" TO \"five\"}", "field", "z:{one TO five}");
assertQueryMatch(qp, "z:{one TO *}", "field", "z:{one TO *}");
assertQueryMatch(qp, "this +(that)", "field", "+field:this +field:that");
assertQueryMatch(qp, "(this) (that)", "field", "+field:this +field:that");
assertQueryMatch(qp, "this ((((+(that))))) ", "field",
"+field:this +field:that");
assertQueryMatch(qp, "this (+(that)^0.7)", "field",
"+field:this +(field:that)^0.7");
assertQueryMatch(qp, "this (+(that thus)^0.7)", "field",
"+field:this +(+field:that +field:thus)^0.7");
assertQueryMatch(qp, "this (-(+(that thus))^0.7)", "field",
"+field:this -(+field:that +field:thus)^0.7");
assertQueryMatch(qp, "this (+(-(+(-(that thus))^0.1))^0.3)", "field",
"+field:this +(+field:that +field:thus)^0.3");
BooleanQuery.setMaxClauseCount(2);
try {
qp = getParser(new WhitespaceAnalyzer());
qp.parse("one two three", "field");
fail("ParseException expected due to too many boolean clauses");
} catch (QueryNodeException expected) {
// too many boolean clauses, so ParseException is expected
}
assertQueryMatch(qp, "*:*", "field", "*:*");
qp.setAllowLeadingWildcard(true);
assertQueryMatch(qp, "*", "field", "field:*");
assertQueryMatch(qp, "field:*", "field", "field:*");
}
}