mirror of https://github.com/apache/lucene.git
LUCENE-7878: Fix query builder to keep the SHOULD clause that wraps multi-word synonyms
This commit is contained in:
parent
1744fa254a
commit
0c683305a4
|
@ -144,6 +144,8 @@ Bug Fixes
|
|||
that these points are visited in ascending order. The memory index doesn't do this and this can result in document
|
||||
with multiple points that should match to not match. (Martijn van Groningen)
|
||||
|
||||
* LUCENE-7878: Fix query builder to keep the SHOULD clause that wraps multi-word synonyms. (Jim Ferenczi)
|
||||
|
||||
Other
|
||||
|
||||
* LUCENE-7800: Remove code that potentially rethrows checked exceptions
|
||||
|
|
|
@ -538,11 +538,7 @@ public class QueryBuilder {
|
|||
builder.add(queryPos, operator);
|
||||
}
|
||||
}
|
||||
BooleanQuery bq = builder.build();
|
||||
if (bq.clauses().size() == 1) {
|
||||
return bq.clauses().get(0).getQuery();
|
||||
}
|
||||
return bq;
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -178,32 +178,36 @@ public class TestQueryBuilder extends LuceneTestCase {
|
|||
.build();
|
||||
Query syn2 = new TermQuery(new Term("field", "cavy"));
|
||||
|
||||
BooleanQuery expectedGraphQuery = new BooleanQuery.Builder()
|
||||
BooleanQuery synQuery = new BooleanQuery.Builder()
|
||||
.add(syn1, BooleanClause.Occur.SHOULD)
|
||||
.add(syn2, BooleanClause.Occur.SHOULD)
|
||||
.build();
|
||||
|
||||
BooleanQuery expectedGraphQuery = new BooleanQuery.Builder()
|
||||
.add(synQuery, occur)
|
||||
.build();
|
||||
|
||||
QueryBuilder queryBuilder = new QueryBuilder(new MockSynonymAnalyzer());
|
||||
assertEquals(expectedGraphQuery, queryBuilder.createBooleanQuery("field", "guinea pig", occur));
|
||||
|
||||
BooleanQuery expectedBooleanQuery = new BooleanQuery.Builder()
|
||||
.add(expectedGraphQuery, occur)
|
||||
.add(synQuery, occur)
|
||||
.add(new TermQuery(new Term("field", "story")), occur)
|
||||
.build();
|
||||
assertEquals(expectedBooleanQuery, queryBuilder.createBooleanQuery("field", "guinea pig story", occur));
|
||||
|
||||
expectedBooleanQuery = new BooleanQuery.Builder()
|
||||
.add(new TermQuery(new Term("field", "the")), occur)
|
||||
.add(expectedGraphQuery, occur)
|
||||
.add(synQuery, occur)
|
||||
.add(new TermQuery(new Term("field", "story")), occur)
|
||||
.build();
|
||||
assertEquals(expectedBooleanQuery, queryBuilder.createBooleanQuery("field", "the guinea pig story", occur));
|
||||
|
||||
expectedBooleanQuery = new BooleanQuery.Builder()
|
||||
.add(new TermQuery(new Term("field", "the")), occur)
|
||||
.add(expectedGraphQuery, occur)
|
||||
.add(synQuery, occur)
|
||||
.add(new TermQuery(new Term("field", "story")), occur)
|
||||
.add(expectedGraphQuery, occur)
|
||||
.add(synQuery, occur)
|
||||
.build();
|
||||
assertEquals(expectedBooleanQuery, queryBuilder.createBooleanQuery("field", "the guinea pig story guinea pig", occur));
|
||||
}
|
||||
|
@ -217,32 +221,36 @@ public class TestQueryBuilder extends LuceneTestCase {
|
|||
.add(new Term("field", "pig"))
|
||||
.build();
|
||||
Query syn2 = new TermQuery(new Term("field", "cavy"));
|
||||
BooleanQuery expectedGraphQuery = new BooleanQuery.Builder()
|
||||
|
||||
BooleanQuery synQuery = new BooleanQuery.Builder()
|
||||
.add(syn1, BooleanClause.Occur.SHOULD)
|
||||
.add(syn2, BooleanClause.Occur.SHOULD)
|
||||
.build();
|
||||
BooleanQuery expectedGraphQuery = new BooleanQuery.Builder()
|
||||
.add(synQuery, occur)
|
||||
.build();
|
||||
QueryBuilder queryBuilder = new QueryBuilder(new MockSynonymAnalyzer());
|
||||
queryBuilder.setAutoGenerateMultiTermSynonymsPhraseQuery(true);
|
||||
assertEquals(expectedGraphQuery, queryBuilder.createBooleanQuery("field", "guinea pig", occur));
|
||||
|
||||
BooleanQuery expectedBooleanQuery = new BooleanQuery.Builder()
|
||||
.add(expectedGraphQuery, occur)
|
||||
.add(synQuery, occur)
|
||||
.add(new TermQuery(new Term("field", "story")), occur)
|
||||
.build();
|
||||
assertEquals(expectedBooleanQuery, queryBuilder.createBooleanQuery("field", "guinea pig story", occur));
|
||||
|
||||
expectedBooleanQuery = new BooleanQuery.Builder()
|
||||
.add(new TermQuery(new Term("field", "the")), occur)
|
||||
.add(expectedGraphQuery, occur)
|
||||
.add(synQuery, occur)
|
||||
.add(new TermQuery(new Term("field", "story")), occur)
|
||||
.build();
|
||||
assertEquals(expectedBooleanQuery, queryBuilder.createBooleanQuery("field", "the guinea pig story", occur));
|
||||
|
||||
expectedBooleanQuery = new BooleanQuery.Builder()
|
||||
.add(new TermQuery(new Term("field", "the")), occur)
|
||||
.add(expectedGraphQuery, occur)
|
||||
.add(synQuery, occur)
|
||||
.add(new TermQuery(new Term("field", "story")), occur)
|
||||
.add(expectedGraphQuery, occur)
|
||||
.add(synQuery, occur)
|
||||
.build();
|
||||
assertEquals(expectedBooleanQuery, queryBuilder.createBooleanQuery("field", "the guinea pig story guinea pig", occur));
|
||||
}
|
||||
|
|
|
@ -351,7 +351,7 @@ public class TestMultiFieldQueryParser extends LuceneTestCase {
|
|||
assertEquals("Synonym(b:dog b:dogs) Synonym(t:dog t:dogs)", q.toString());
|
||||
q = parser.parse("guinea pig");
|
||||
assertFalse(parser.getSplitOnWhitespace());
|
||||
assertEquals("((+b:guinea +b:pig) (+t:guinea +t:pig)) (b:cavy t:cavy)", q.toString());
|
||||
assertEquals("((+b:guinea +b:pig) b:cavy) ((+t:guinea +t:pig) t:cavy)", q.toString());
|
||||
parser.setSplitOnWhitespace(true);
|
||||
q = parser.parse("guinea pig");
|
||||
assertEquals("(b:guinea t:guinea) (b:pig t:pig)", q.toString());
|
||||
|
|
|
@ -522,8 +522,10 @@ public class TestQueryParser extends QueryParserTestBase {
|
|||
.build();
|
||||
|
||||
BooleanQuery graphQuery = new BooleanQuery.Builder()
|
||||
.add(guineaPig, BooleanClause.Occur.SHOULD)
|
||||
.add(cavy, BooleanClause.Occur.SHOULD)
|
||||
.add(new BooleanQuery.Builder()
|
||||
.add(guineaPig, BooleanClause.Occur.SHOULD)
|
||||
.add(cavy, BooleanClause.Occur.SHOULD)
|
||||
.build(), BooleanClause.Occur.SHOULD)
|
||||
.build();
|
||||
assertEquals(graphQuery, dumb.parse("guinea pig"));
|
||||
|
||||
|
@ -541,11 +543,32 @@ public class TestQueryParser extends QueryParserTestBase {
|
|||
QueryParser smart = new SmartQueryParser();
|
||||
smart.setSplitOnWhitespace(false);
|
||||
graphQuery = new BooleanQuery.Builder()
|
||||
.add(guineaPig, BooleanClause.Occur.SHOULD)
|
||||
.add(cavy, BooleanClause.Occur.SHOULD)
|
||||
.add(new BooleanQuery.Builder()
|
||||
.add(guineaPig, BooleanClause.Occur.SHOULD)
|
||||
.add(cavy, BooleanClause.Occur.SHOULD)
|
||||
.build(), BooleanClause.Occur.SHOULD)
|
||||
.build();
|
||||
assertEquals(graphQuery, smart.parse("guinea pig"));
|
||||
assertEquals(phraseGuineaPig, smart.parse("\"guinea pig\""));
|
||||
|
||||
// with the AND operator
|
||||
dumb.setDefaultOperator(Operator.AND);
|
||||
BooleanQuery graphAndQuery = new BooleanQuery.Builder()
|
||||
.add(new BooleanQuery.Builder()
|
||||
.add(guineaPig, BooleanClause.Occur.SHOULD)
|
||||
.add(cavy, BooleanClause.Occur.SHOULD)
|
||||
.build(), BooleanClause.Occur.MUST)
|
||||
.build();
|
||||
assertEquals(graphAndQuery, dumb.parse("guinea pig"));
|
||||
|
||||
graphAndQuery = new BooleanQuery.Builder()
|
||||
.add(new BooleanQuery.Builder()
|
||||
.add(guineaPig, BooleanClause.Occur.SHOULD)
|
||||
.add(cavy, BooleanClause.Occur.SHOULD)
|
||||
.build(), BooleanClause.Occur.MUST)
|
||||
.add(cavy, BooleanClause.Occur.MUST)
|
||||
.build();
|
||||
assertEquals(graphAndQuery, dumb.parse("guinea pig cavy"));
|
||||
}
|
||||
|
||||
public void testEnableGraphQueries() throws Exception {
|
||||
|
@ -616,30 +639,30 @@ public class TestQueryParser extends QueryParserTestBase {
|
|||
assertQueryEquals("guinea /pig/", a, "guinea /pig/");
|
||||
|
||||
// Operators should not interrupt multiword analysis if not don't associate
|
||||
assertQueryEquals("(guinea pig)", a, "(+guinea +pig) cavy");
|
||||
assertQueryEquals("+(guinea pig)", a, "+((+guinea +pig) cavy)");
|
||||
assertQueryEquals("-(guinea pig)", a, "-((+guinea +pig) cavy)");
|
||||
assertQueryEquals("!(guinea pig)", a, "-((+guinea +pig) cavy)");
|
||||
assertQueryEquals("NOT (guinea pig)", a, "-((+guinea +pig) cavy)");
|
||||
assertQueryEquals("(guinea pig)^2", a, "((+guinea +pig) cavy)^2.0");
|
||||
assertQueryEquals("(guinea pig)", a, "((+guinea +pig) cavy)");
|
||||
assertQueryEquals("+(guinea pig)", a, "+(((+guinea +pig) cavy))");
|
||||
assertQueryEquals("-(guinea pig)", a, "-(((+guinea +pig) cavy))");
|
||||
assertQueryEquals("!(guinea pig)", a, "-(((+guinea +pig) cavy))");
|
||||
assertQueryEquals("NOT (guinea pig)", a, "-(((+guinea +pig) cavy))");
|
||||
assertQueryEquals("(guinea pig)^2", a, "(((+guinea +pig) cavy))^2.0");
|
||||
|
||||
assertQueryEquals("field:(guinea pig)", a, "(+guinea +pig) cavy");
|
||||
assertQueryEquals("field:(guinea pig)", a, "((+guinea +pig) cavy)");
|
||||
|
||||
assertQueryEquals("+small guinea pig", a, "+small (+guinea +pig) cavy");
|
||||
assertQueryEquals("-small guinea pig", a, "-small (+guinea +pig) cavy");
|
||||
assertQueryEquals("!small guinea pig", a, "-small (+guinea +pig) cavy");
|
||||
assertQueryEquals("NOT small guinea pig", a, "-small (+guinea +pig) cavy");
|
||||
assertQueryEquals("small* guinea pig", a, "small* (+guinea +pig) cavy");
|
||||
assertQueryEquals("small? guinea pig", a, "small? (+guinea +pig) cavy");
|
||||
assertQueryEquals("\"small\" guinea pig", a, "small (+guinea +pig) cavy");
|
||||
assertQueryEquals("+small guinea pig", a, "+small ((+guinea +pig) cavy)");
|
||||
assertQueryEquals("-small guinea pig", a, "-small ((+guinea +pig) cavy)");
|
||||
assertQueryEquals("!small guinea pig", a, "-small ((+guinea +pig) cavy)");
|
||||
assertQueryEquals("NOT small guinea pig", a, "-small ((+guinea +pig) cavy)");
|
||||
assertQueryEquals("small* guinea pig", a, "small* ((+guinea +pig) cavy)");
|
||||
assertQueryEquals("small? guinea pig", a, "small? ((+guinea +pig) cavy)");
|
||||
assertQueryEquals("\"small\" guinea pig", a, "small ((+guinea +pig) cavy)");
|
||||
|
||||
assertQueryEquals("guinea pig +running", a, "(+guinea +pig) cavy +running");
|
||||
assertQueryEquals("guinea pig -running", a, "(+guinea +pig) cavy -running");
|
||||
assertQueryEquals("guinea pig !running", a, "(+guinea +pig) cavy -running");
|
||||
assertQueryEquals("guinea pig NOT running", a, "(+guinea +pig) cavy -running");
|
||||
assertQueryEquals("guinea pig running*", a, "(+guinea +pig) cavy running*");
|
||||
assertQueryEquals("guinea pig running?", a, "(+guinea +pig) cavy running?");
|
||||
assertQueryEquals("guinea pig \"running\"", a, "(+guinea +pig) cavy running");
|
||||
assertQueryEquals("guinea pig +running", a, "((+guinea +pig) cavy) +running");
|
||||
assertQueryEquals("guinea pig -running", a, "((+guinea +pig) cavy) -running");
|
||||
assertQueryEquals("guinea pig !running", a, "((+guinea +pig) cavy) -running");
|
||||
assertQueryEquals("guinea pig NOT running", a, "((+guinea +pig) cavy) -running");
|
||||
assertQueryEquals("guinea pig running*", a, "((+guinea +pig) cavy) running*");
|
||||
assertQueryEquals("guinea pig running?", a, "((+guinea +pig) cavy) running?");
|
||||
assertQueryEquals("guinea pig \"running\"", a, "((+guinea +pig) cavy) running");
|
||||
|
||||
assertQueryEquals("\"guinea pig\"~2", a, "spanOr([spanNear([guinea, pig], 0, true), cavy])");
|
||||
|
||||
|
@ -744,14 +767,16 @@ public class TestQueryParser extends QueryParserTestBase {
|
|||
BooleanQuery guineaPig = synonym.build();
|
||||
|
||||
BooleanQuery graphQuery = new BooleanQuery.Builder()
|
||||
.add(guineaPig, BooleanClause.Occur.SHOULD)
|
||||
.add(cavy, BooleanClause.Occur.SHOULD)
|
||||
.build();;
|
||||
.add(new BooleanQuery.Builder()
|
||||
.add(guineaPig, BooleanClause.Occur.SHOULD)
|
||||
.add(cavy, BooleanClause.Occur.SHOULD)
|
||||
.build(), BooleanClause.Occur.SHOULD)
|
||||
.build();
|
||||
assertEquals(graphQuery, parser.parse("guinea pig"));
|
||||
|
||||
boolean oldSplitOnWhitespace = splitOnWhitespace;
|
||||
splitOnWhitespace = QueryParser.DEFAULT_SPLIT_ON_WHITESPACE;
|
||||
assertQueryEquals("guinea pig", new MockSynonymAnalyzer(), "(+guinea +pig) cavy");
|
||||
assertQueryEquals("guinea pig", new MockSynonymAnalyzer(), "((+guinea +pig) cavy)");
|
||||
splitOnWhitespace = oldSplitOnWhitespace;
|
||||
}
|
||||
|
||||
|
|
|
@ -1787,7 +1787,7 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
|
|||
try (SolrQueryRequest req = req(params)) {
|
||||
QParser qParser = QParser.getParser("text:grackle", "edismax", req); // "text" has autoGeneratePhraseQueries="true"
|
||||
Query q = qParser.getQuery();
|
||||
assertEquals("+(text:\"crow blackbird\" text:grackl)", q.toString());
|
||||
assertEquals("+((text:\"crow blackbird\" text:grackl))", q.toString());
|
||||
}
|
||||
}
|
||||
try (SolrQueryRequest req = req(sowTrueParams)) {
|
||||
|
@ -1799,7 +1799,7 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
|
|||
try (SolrQueryRequest req = req(params)) {
|
||||
QParser qParser = QParser.getParser("text_sw:grackle", "edismax", req); // "text_sw" doesn't specify autoGeneratePhraseQueries => default false
|
||||
Query q = qParser.getQuery();
|
||||
assertEquals("+((+text_sw:crow +text_sw:blackbird) text_sw:grackl)", q.toString());
|
||||
assertEquals("+(((+text_sw:crow +text_sw:blackbird) text_sw:grackl))", q.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1809,8 +1809,8 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
|
|||
try (SolrQueryRequest req = req(params)) {
|
||||
QParser qParser = QParser.getParser("grackle", "edismax", req);
|
||||
Query q = qParser.getQuery();
|
||||
assertEquals("+((text:\"crow blackbird\" text:grackl)"
|
||||
+ " | ((+text_sw:crow +text_sw:blackbird) text_sw:grackl))",
|
||||
assertEquals("+(((text:\"crow blackbird\" text:grackl))"
|
||||
+ " | (((+text_sw:crow +text_sw:blackbird) text_sw:grackl)))",
|
||||
q.toString());
|
||||
|
||||
qParser = QParser.getParser("grackle wi fi", "edismax", req);
|
||||
|
@ -1825,13 +1825,13 @@ public class TestExtendedDismaxParser extends SolrTestCaseJ4 {
|
|||
QParser qParser = QParser.getParser("grackle", "edismax", req);
|
||||
Query q = qParser.getQuery();
|
||||
assertEquals("+(spanOr([spanNear([text:crow, text:blackbird], 0, true), text:grackl])"
|
||||
+ " | ((+text_sw:crow +text_sw:blackbird) text_sw:grackl))",
|
||||
+ " | (((+text_sw:crow +text_sw:blackbird) text_sw:grackl)))",
|
||||
q.toString());
|
||||
|
||||
qParser = QParser.getParser("grackle wi fi", "edismax", req);
|
||||
q = qParser.getQuery();
|
||||
assertEquals("+((spanOr([spanNear([text:crow, text:blackbird], 0, true), text:grackl])"
|
||||
+ " | ((+text_sw:crow +text_sw:blackbird) text_sw:grackl)) (text:wi | text_sw:wi) (text:fi | text_sw:fi))",
|
||||
+ " | (((+text_sw:crow +text_sw:blackbird) text_sw:grackl))) (text:wi | text_sw:wi) (text:fi | text_sw:fi))",
|
||||
q.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1007,7 +1007,7 @@ public class TestSolrQueryParser extends SolrTestCaseJ4 {
|
|||
QParser qParser = QParser.getParser("text:grackle", req); // "text" has autoGeneratePhraseQueries="true"
|
||||
qParser.setParams(sowFalseParams);
|
||||
Query q = qParser.getQuery();
|
||||
assertEquals("text:\"crow blackbird\" text:grackl", q.toString());
|
||||
assertEquals("(text:\"crow blackbird\" text:grackl)", q.toString());
|
||||
}
|
||||
|
||||
QParser qParser = QParser.getParser("text:grackle", req);
|
||||
|
@ -1019,7 +1019,7 @@ public class TestSolrQueryParser extends SolrTestCaseJ4 {
|
|||
qParser = QParser.getParser("text_sw:grackle", req); // "text_sw" doesn't specify autoGeneratePhraseQueries => default false
|
||||
qParser.setParams(params);
|
||||
q = qParser.getQuery();
|
||||
assertEquals("(+text_sw:crow +text_sw:blackbird) text_sw:grackl", q.toString());
|
||||
assertEquals("((+text_sw:crow +text_sw:blackbird) text_sw:grackl)", q.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue