diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml
index 28bbe3ef5b7..557ffbcb298 100644
--- a/buildSrc/src/main/resources/checkstyle_suppressions.xml
+++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml
@@ -14,7 +14,6 @@
files start to pass. -->
-
@@ -1121,7 +1120,6 @@
-
diff --git a/core/src/main/java/org/apache/lucene/queryparser/classic/MapperQueryParser.java b/core/src/main/java/org/apache/lucene/queryparser/classic/MapperQueryParser.java
index 0a3e08ed4a6..411f22043bd 100644
--- a/core/src/main/java/org/apache/lucene/queryparser/classic/MapperQueryParser.java
+++ b/core/src/main/java/org/apache/lucene/queryparser/classic/MapperQueryParser.java
@@ -22,6 +22,7 @@ package org.apache.lucene.queryparser.classic;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
+import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
@@ -32,6 +33,7 @@ import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.MultiPhraseQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SynonymQuery;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.automaton.RegExp;
import org.elasticsearch.common.lucene.search.Queries;
@@ -105,7 +107,8 @@ public class MapperQueryParser extends QueryParser {
}
/**
- * We override this one so we can get the fuzzy part to be treated as string, so people can do: "age:10~5" or "timestamp:2012-10-10~5d"
+ * We override this one so we can get the fuzzy part to be treated as string,
+ * so people can do: "age:10~5" or "timestamp:2012-10-10~5d"
*/
@Override
Query handleBareFuzzy(String qfield, Token fuzzySlop, String termImage) throws ParseException {
@@ -277,7 +280,8 @@ public class MapperQueryParser extends QueryParser {
}
@Override
- protected Query getRangeQuery(String field, String part1, String part2, boolean startInclusive, boolean endInclusive) throws ParseException {
+ protected Query getRangeQuery(String field, String part1, String part2,
+ boolean startInclusive, boolean endInclusive) throws ParseException {
if ("*".equals(part1)) {
part1 = null;
}
@@ -324,7 +328,8 @@ public class MapperQueryParser extends QueryParser {
}
}
- private Query getRangeQuerySingle(String field, String part1, String part2, boolean startInclusive, boolean endInclusive) {
+ private Query getRangeQuerySingle(String field, String part1, String part2,
+ boolean startInclusive, boolean endInclusive) {
currentFieldType = context.fieldMapper(field);
if (currentFieldType != null) {
if (lowercaseExpandedTerms && currentFieldType.tokenized()) {
@@ -335,8 +340,10 @@ public class MapperQueryParser extends QueryParser {
try {
Query rangeQuery;
if (currentFieldType instanceof DateFieldMapper.DateFieldType && settings.timeZone() != null) {
- DateFieldMapper.DateFieldType dateFieldType = (DateFieldMapper.DateFieldType) this.currentFieldType;
- rangeQuery = dateFieldType.rangeQuery(part1, part2, startInclusive, endInclusive, settings.timeZone(), null);
+ DateFieldMapper.DateFieldType dateFieldType =
+ (DateFieldMapper.DateFieldType) this.currentFieldType;
+ rangeQuery = dateFieldType.rangeQuery(part1, part2, startInclusive, endInclusive,
+ settings.timeZone(), null);
} else {
rangeQuery = currentFieldType.rangeQuery(part1, part2, startInclusive, endInclusive);
}
@@ -393,7 +400,8 @@ public class MapperQueryParser extends QueryParser {
currentFieldType = context.fieldMapper(field);
if (currentFieldType != null) {
try {
- return currentFieldType.fuzzyQuery(termStr, Fuzziness.build(minSimilarity), fuzzyPrefixLength, settings.fuzzyMaxExpansions(), FuzzyQuery.defaultTranspositions);
+ return currentFieldType.fuzzyQuery(termStr, Fuzziness.build(minSimilarity),
+ fuzzyPrefixLength, settings.fuzzyMaxExpansions(), FuzzyQuery.defaultTranspositions);
} catch (RuntimeException e) {
if (settings.lenient()) {
return null;
@@ -408,7 +416,8 @@ public class MapperQueryParser extends QueryParser {
protected Query newFuzzyQuery(Term term, float minimumSimilarity, int prefixLength) {
String text = term.text();
int numEdits = FuzzyQuery.floatToEdits(minimumSimilarity, text.codePointCount(0, text.length()));
- FuzzyQuery query = new FuzzyQuery(term, numEdits, prefixLength, settings.fuzzyMaxExpansions(), FuzzyQuery.defaultTranspositions);
+ FuzzyQuery query = new FuzzyQuery(term, numEdits, prefixLength,
+ settings.fuzzyMaxExpansions(), FuzzyQuery.defaultTranspositions);
QueryParsers.setRewriteMethod(query, settings.fuzzyRewriteMethod());
return query;
}
@@ -487,7 +496,7 @@ public class MapperQueryParser extends QueryParser {
if (!settings.analyzeWildcard()) {
return super.getPrefixQuery(field, termStr);
}
- List tlist;
+ List > tlist;
// get Analyzer from superclass and tokenize the term
TokenStream source = null;
try {
@@ -498,7 +507,9 @@ public class MapperQueryParser extends QueryParser {
return super.getPrefixQuery(field, termStr);
}
tlist = new ArrayList<>();
+ List currentPos = new ArrayList<>();
CharTermAttribute termAtt = source.addAttribute(CharTermAttribute.class);
+ PositionIncrementAttribute posAtt = source.addAttribute(PositionIncrementAttribute.class);
while (true) {
try {
@@ -506,7 +517,14 @@ public class MapperQueryParser extends QueryParser {
} catch (IOException e) {
break;
}
- tlist.add(termAtt.toString());
+ if (currentPos.isEmpty() == false && posAtt.getPositionIncrement() > 0) {
+ tlist.add(currentPos);
+ currentPos = new ArrayList<>();
+ }
+ currentPos.add(termAtt.toString());
+ }
+ if (currentPos.isEmpty() == false) {
+ tlist.add(currentPos);
}
} finally {
if (source != null) {
@@ -514,15 +532,41 @@ public class MapperQueryParser extends QueryParser {
}
}
- if (tlist.size() == 1) {
- return super.getPrefixQuery(field, tlist.get(0));
+
+ if (tlist.size() == 1 && tlist.get(0).size() == 1) {
+ return super.getPrefixQuery(field, tlist.get(0).get(0));
} else {
- // build a boolean query with prefix on each one...
+ // build a boolean query with prefix on the last position only.
List clauses = new ArrayList<>();
- for (String token : tlist) {
- clauses.add(new BooleanClause(super.getPrefixQuery(field, token), BooleanClause.Occur.SHOULD));
+ for (int pos = 0; pos < tlist.size(); pos++) {
+ List plist = tlist.get(pos);
+ boolean isLastPos = (pos == tlist.size()-1);
+ Query posQuery;
+ if (plist.size() == 1) {
+ if (isLastPos) {
+ posQuery = getPrefixQuery(field, plist.get(0));
+ } else {
+ posQuery = newTermQuery(new Term(field, plist.get(0)));
+ }
+ } else if (isLastPos == false) {
+ // build a synonym query for terms in the same position.
+ Term[] terms = new Term[plist.size()];
+ for (int i = 0; i < plist.size(); i++) {
+ terms[i] = new Term(field, plist.get(i));
+ }
+ posQuery = new SynonymQuery(terms);
+ } else {
+ List innerClauses = new ArrayList<>();
+ for (String token : plist) {
+ innerClauses.add(new BooleanClause(getPrefixQuery(field, token),
+ BooleanClause.Occur.SHOULD));
+ }
+ posQuery = getBooleanQueryCoordDisabled(innerClauses);
+ }
+ clauses.add(new BooleanClause(posQuery,
+ getDefaultOperator() == Operator.AND ? BooleanClause.Occur.MUST : BooleanClause.Occur.SHOULD));
}
- return getBooleanQueryCoordDisabled(clauses);
+ return getBooleanQuery(clauses);
}
}
@@ -724,7 +768,8 @@ public class MapperQueryParser extends QueryParser {
}
Query query = null;
if (currentFieldType.tokenized() == false) {
- query = currentFieldType.regexpQuery(termStr, RegExp.ALL, maxDeterminizedStates, multiTermRewriteMethod, context);
+ query = currentFieldType.regexpQuery(termStr, RegExp.ALL,
+ maxDeterminizedStates, multiTermRewriteMethod, context);
}
if (query == null) {
query = super.getRegexpQuery(field, termStr);
@@ -741,7 +786,7 @@ public class MapperQueryParser extends QueryParser {
setAnalyzer(oldAnalyzer);
}
}
-
+
/**
* @deprecated review all use of this, don't rely on coord
*/
diff --git a/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java b/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java
index 0dc43e5c22e..be2f7697a68 100644
--- a/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java
+++ b/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java
@@ -24,6 +24,7 @@ import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.io.JsonStringEncoder;
import org.apache.lucene.search.BoostQuery;
+import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.spans.SpanBoostQuery;
@@ -637,6 +638,13 @@ public abstract class AbstractQueryTestCase>
assertThat(termQuery.getTerm().text().toLowerCase(Locale.ROOT), equalTo(value.toLowerCase(Locale.ROOT)));
}
+ protected static void assertPrefixQuery(Query query, String field, String value) {
+ assertThat(query, instanceOf(PrefixQuery.class));
+ PrefixQuery prefixQuery = (PrefixQuery) query;
+ assertThat(prefixQuery.getPrefix().field(), equalTo(field));
+ assertThat(prefixQuery.getPrefix().text(), equalTo(value));
+ }
+
/**
* Test serialization and deserialization of the test query.
*/
diff --git a/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java
index 6b549464bdc..4cb31bd2a20 100644
--- a/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java
+++ b/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java
@@ -58,7 +58,8 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase 0);
- Query query = queryStringQuery("\"term1 term2\"").defaultField(STRING_FIELD_NAME).phraseSlop(3).toQuery(createShardContext());
+ Query query = queryStringQuery("\"term1 term2\"")
+ .defaultField(STRING_FIELD_NAME)
+ .phraseSlop(3)
+ .toQuery(createShardContext());
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
DisjunctionMaxQuery disjunctionMaxQuery = (DisjunctionMaxQuery) query;
assertThat(disjunctionMaxQuery.getDisjuncts().size(), equalTo(1));
@@ -204,7 +209,8 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase 0);
- Query query = queryStringQuery("test1 test2").field(STRING_FIELD_NAME).useDisMax(false).toQuery(createShardContext());
+ Query query = queryStringQuery("test1 test2").field(STRING_FIELD_NAME)
+ .useDisMax(false)
+ .toQuery(createShardContext());
assertThat(query, instanceOf(BooleanQuery.class));
BooleanQuery bQuery = (BooleanQuery) query;
assertThat(bQuery.clauses().size(), equalTo(2));
- assertThat(assertBooleanSubQuery(query, TermQuery.class, 0).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test1")));
- assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test2")));
+ assertThat(assertBooleanSubQuery(query, TermQuery.class, 0).getTerm(),
+ equalTo(new Term(STRING_FIELD_NAME, "test1")));
+ assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(),
+ equalTo(new Term(STRING_FIELD_NAME, "test2")));
}
public void testToQueryMultipleFieldsBooleanQuery() throws Exception {
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
- Query query = queryStringQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).useDisMax(false).toQuery(createShardContext());
+ Query query = queryStringQuery("test").field(STRING_FIELD_NAME)
+ .field(STRING_FIELD_NAME_2)
+ .useDisMax(false)
+ .toQuery(createShardContext());
assertThat(query, instanceOf(BooleanQuery.class));
BooleanQuery bQuery = (BooleanQuery) query;
assertThat(bQuery.clauses().size(), equalTo(2));
- assertThat(assertBooleanSubQuery(query, TermQuery.class, 0).getTerm(), equalTo(new Term(STRING_FIELD_NAME, "test")));
- assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "test")));
+ assertThat(assertBooleanSubQuery(query, TermQuery.class, 0).getTerm(),
+ equalTo(new Term(STRING_FIELD_NAME, "test")));
+ assertThat(assertBooleanSubQuery(query, TermQuery.class, 1).getTerm(),
+ equalTo(new Term(STRING_FIELD_NAME_2, "test")));
}
public void testToQueryMultipleFieldsDisMaxQuery() throws Exception {
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
- Query query = queryStringQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2).useDisMax(true).toQuery(createShardContext());
+ Query query = queryStringQuery("test").field(STRING_FIELD_NAME).field(STRING_FIELD_NAME_2)
+ .useDisMax(true)
+ .toQuery(createShardContext());
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
DisjunctionMaxQuery disMaxQuery = (DisjunctionMaxQuery) query;
List disjuncts = disMaxQuery.getDisjuncts();
@@ -260,13 +277,18 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase 0);
- Query query = queryStringQuery("test").field(STRING_FIELD_NAME, 2.2f).field(STRING_FIELD_NAME_2).useDisMax(true).toQuery(createShardContext());
+ Query query = queryStringQuery("test").field(STRING_FIELD_NAME, 2.2f)
+ .field(STRING_FIELD_NAME_2)
+ .useDisMax(true)
+ .toQuery(createShardContext());
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
DisjunctionMaxQuery disMaxQuery = (DisjunctionMaxQuery) query;
List disjuncts = disMaxQuery.getDisjuncts();
@@ -274,9 +296,40 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase 0);
+ for (Operator op : Operator.values()) {
+ Query query = queryStringQuery("foo-bar-foobar*")
+ .defaultField(STRING_FIELD_NAME)
+ .analyzeWildcard(true)
+ .analyzer("standard")
+ .defaultOperator(op)
+ .toQuery(createShardContext());
+ assertThat(query, instanceOf(BooleanQuery.class));
+ BooleanQuery bq = (BooleanQuery) query;
+ assertThat(bq.clauses().size(), equalTo(3));
+ String[] expectedTerms = new String[]{"foo", "bar", "foobar"};
+ for (int i = 0; i < bq.clauses().size(); i++) {
+ BooleanClause clause = bq.clauses().get(i);
+ if (i != bq.clauses().size() - 1) {
+ assertTermQuery(clause.getQuery(), STRING_FIELD_NAME, expectedTerms[i]);
+ } else {
+ assertPrefixQuery(clause.getQuery(), STRING_FIELD_NAME, expectedTerms[i]);
+ }
+ if (op == Operator.AND) {
+ assertThat(clause.getOccur(), equalTo(BooleanClause.Occur.MUST));
+ } else {
+ assertThat(clause.getOccur(), equalTo(BooleanClause.Occur.SHOULD));
+ }
+ }
+ }
+ }
+
public void testToQueryRegExpQuery() throws Exception {
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
- Query query = queryStringQuery("/foo*bar/").defaultField(STRING_FIELD_NAME).maxDeterminizedStates(5000).toQuery(createShardContext());
+ Query query = queryStringQuery("/foo*bar/").defaultField(STRING_FIELD_NAME)
+ .maxDeterminizedStates(5000)
+ .toQuery(createShardContext());
assertThat(query, instanceOf(RegexpQuery.class));
RegexpQuery regexpQuery = (RegexpQuery) query;
assertTrue(regexpQuery.toString().contains("/foo*bar/"));
@@ -344,7 +397,8 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase 0);
- QueryStringQueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder("\"test phrase\"~2").field(STRING_FIELD_NAME, 5f);
+ QueryStringQueryBuilder queryStringQueryBuilder =
+ new QueryStringQueryBuilder("\"test phrase\"~2").field(STRING_FIELD_NAME, 5f);
Query query = queryStringQueryBuilder.toQuery(createShardContext());
assertThat(query, instanceOf(DisjunctionMaxQuery.class));
DisjunctionMaxQuery disjunctionMaxQuery = (DisjunctionMaxQuery) query;