Merge pull request #17776 from jimferenczi/simple_query_string_wildcard
Apply the default operator on analyzed wildcard in simple_query_string builder
This commit is contained in:
commit
4575d79522
|
@ -502,7 +502,6 @@
|
||||||
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]QueryBuilders.java" checks="LineLength" />
|
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]QueryBuilders.java" checks="LineLength" />
|
||||||
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]QueryShardContext.java" checks="LineLength" />
|
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]QueryShardContext.java" checks="LineLength" />
|
||||||
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]QueryValidationException.java" checks="LineLength" />
|
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]QueryValidationException.java" checks="LineLength" />
|
||||||
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]SimpleQueryParser.java" checks="LineLength" />
|
|
||||||
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]support[/\\]InnerHitsQueryParserHelper.java" checks="LineLength" />
|
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]support[/\\]InnerHitsQueryParserHelper.java" checks="LineLength" />
|
||||||
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]support[/\\]QueryParsers.java" checks="LineLength" />
|
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]support[/\\]QueryParsers.java" checks="LineLength" />
|
||||||
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]search[/\\]MatchQuery.java" checks="LineLength" />
|
<suppress files="core[/\\]src[/\\]main[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]search[/\\]MatchQuery.java" checks="LineLength" />
|
||||||
|
|
|
@ -530,19 +530,23 @@ public class MapperQueryParser extends QueryParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tlist.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (tlist.size() == 1 && tlist.get(0).size() == 1) {
|
if (tlist.size() == 1 && tlist.get(0).size() == 1) {
|
||||||
return super.getPrefixQuery(field, tlist.get(0).get(0));
|
return super.getPrefixQuery(field, tlist.get(0).get(0));
|
||||||
} else {
|
}
|
||||||
|
|
||||||
// build a boolean query with prefix on the last position only.
|
// build a boolean query with prefix on the last position only.
|
||||||
List<BooleanClause> clauses = new ArrayList<>();
|
List<BooleanClause> clauses = new ArrayList<>();
|
||||||
for (int pos = 0; pos < tlist.size(); pos++) {
|
for (int pos = 0; pos < tlist.size(); pos++) {
|
||||||
List<String> plist = tlist.get(pos);
|
List<String> plist = tlist.get(pos);
|
||||||
boolean isLastPos = (pos == tlist.size()-1);
|
boolean isLastPos = (pos == tlist.size() - 1);
|
||||||
Query posQuery;
|
Query posQuery;
|
||||||
if (plist.size() == 1) {
|
if (plist.size() == 1) {
|
||||||
if (isLastPos) {
|
if (isLastPos) {
|
||||||
posQuery = getPrefixQuery(field, plist.get(0));
|
posQuery = super.getPrefixQuery(field, plist.get(0));
|
||||||
} else {
|
} else {
|
||||||
posQuery = newTermQuery(new Term(field, plist.get(0)));
|
posQuery = newTermQuery(new Term(field, plist.get(0)));
|
||||||
}
|
}
|
||||||
|
@ -556,7 +560,7 @@ public class MapperQueryParser extends QueryParser {
|
||||||
} else {
|
} else {
|
||||||
List<BooleanClause> innerClauses = new ArrayList<>();
|
List<BooleanClause> innerClauses = new ArrayList<>();
|
||||||
for (String token : plist) {
|
for (String token : plist) {
|
||||||
innerClauses.add(new BooleanClause(getPrefixQuery(field, token),
|
innerClauses.add(new BooleanClause(super.getPrefixQuery(field, token),
|
||||||
BooleanClause.Occur.SHOULD));
|
BooleanClause.Occur.SHOULD));
|
||||||
}
|
}
|
||||||
posQuery = getBooleanQueryCoordDisabled(innerClauses);
|
posQuery = getBooleanQueryCoordDisabled(innerClauses);
|
||||||
|
@ -566,7 +570,6 @@ public class MapperQueryParser extends QueryParser {
|
||||||
}
|
}
|
||||||
return getBooleanQuery(clauses);
|
return getBooleanQuery(clauses);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Query getWildcardQuery(String field, String termStr) throws ParseException {
|
protected Query getWildcardQuery(String field, String termStr) throws ParseException {
|
||||||
|
|
|
@ -19,9 +19,9 @@
|
||||||
package org.elasticsearch.index.query;
|
package org.elasticsearch.index.query;
|
||||||
|
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
import org.apache.lucene.analysis.CachingTokenFilter;
|
|
||||||
import org.apache.lucene.analysis.TokenStream;
|
import org.apache.lucene.analysis.TokenStream;
|
||||||
import org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute;
|
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
||||||
|
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.BooleanClause;
|
import org.apache.lucene.search.BooleanClause;
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
|
@ -29,13 +29,15 @@ import org.apache.lucene.search.BoostQuery;
|
||||||
import org.apache.lucene.search.FuzzyQuery;
|
import org.apache.lucene.search.FuzzyQuery;
|
||||||
import org.apache.lucene.search.PrefixQuery;
|
import org.apache.lucene.search.PrefixQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.search.SynonymQuery;
|
||||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper class for Lucene's SimpleQueryParser that allows us to redefine
|
* Wrapper class for Lucene's SimpleQueryParser that allows us to redefine
|
||||||
|
@ -47,7 +49,8 @@ public class SimpleQueryParser extends org.apache.lucene.queryparser.simple.Simp
|
||||||
private QueryShardContext context;
|
private QueryShardContext context;
|
||||||
|
|
||||||
/** Creates a new parser with custom flags used to enable/disable certain features. */
|
/** Creates a new parser with custom flags used to enable/disable certain features. */
|
||||||
public SimpleQueryParser(Analyzer analyzer, Map<String, Float> weights, int flags, Settings settings, QueryShardContext context) {
|
public SimpleQueryParser(Analyzer analyzer, Map<String, Float> weights, int flags,
|
||||||
|
Settings settings, QueryShardContext context) {
|
||||||
super(analyzer, weights, flags);
|
super(analyzer, weights, flags);
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -167,62 +170,79 @@ public class SimpleQueryParser extends org.apache.lucene.queryparser.simple.Simp
|
||||||
/**
|
/**
|
||||||
* Analyze the given string using its analyzer, constructing either a
|
* Analyze the given string using its analyzer, constructing either a
|
||||||
* {@code PrefixQuery} or a {@code BooleanQuery} made up
|
* {@code PrefixQuery} or a {@code BooleanQuery} made up
|
||||||
* of {@code PrefixQuery}s
|
* of {@code TermQuery}s and {@code PrefixQuery}s
|
||||||
*/
|
*/
|
||||||
private Query newPossiblyAnalyzedQuery(String field, String termStr) {
|
private Query newPossiblyAnalyzedQuery(String field, String termStr) {
|
||||||
|
List<List<String>> tlist = new ArrayList<> ();
|
||||||
|
// get Analyzer from superclass and tokenize the term
|
||||||
try (TokenStream source = getAnalyzer().tokenStream(field, termStr)) {
|
try (TokenStream source = getAnalyzer().tokenStream(field, termStr)) {
|
||||||
// Use the analyzer to get all the tokens, and then build a TermQuery,
|
source.reset();
|
||||||
// PhraseQuery, or nothing based on the term count
|
List<String> currentPos = new ArrayList<>();
|
||||||
CachingTokenFilter buffer = new CachingTokenFilter(source);
|
CharTermAttribute termAtt = source.addAttribute(CharTermAttribute.class);
|
||||||
buffer.reset();
|
PositionIncrementAttribute posAtt = source.addAttribute(PositionIncrementAttribute.class);
|
||||||
|
|
||||||
TermToBytesRefAttribute termAtt = null;
|
|
||||||
int numTokens = 0;
|
|
||||||
boolean hasMoreTokens = false;
|
|
||||||
termAtt = buffer.getAttribute(TermToBytesRefAttribute.class);
|
|
||||||
if (termAtt != null) {
|
|
||||||
try {
|
try {
|
||||||
hasMoreTokens = buffer.incrementToken();
|
boolean hasMoreTokens = source.incrementToken();
|
||||||
while (hasMoreTokens) {
|
while (hasMoreTokens) {
|
||||||
numTokens++;
|
if (currentPos.isEmpty() == false && posAtt.getPositionIncrement() > 0) {
|
||||||
hasMoreTokens = buffer.incrementToken();
|
tlist.add(currentPos);
|
||||||
|
currentPos = new ArrayList<>();
|
||||||
|
}
|
||||||
|
currentPos.add(termAtt.toString());
|
||||||
|
hasMoreTokens = source.incrementToken();
|
||||||
|
}
|
||||||
|
if (currentPos.isEmpty() == false) {
|
||||||
|
tlist.add(currentPos);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
// TODO: we should not ignore the exception and return a prefix query with the original term ?
|
||||||
}
|
|
||||||
|
|
||||||
// rewind buffer
|
|
||||||
buffer.reset();
|
|
||||||
|
|
||||||
if (numTokens == 0) {
|
|
||||||
return null;
|
|
||||||
} else if (numTokens == 1) {
|
|
||||||
try {
|
|
||||||
boolean hasNext = buffer.incrementToken();
|
|
||||||
assert hasNext == true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
// safe to ignore, because we know the number of tokens
|
|
||||||
}
|
|
||||||
return new PrefixQuery(new Term(field, BytesRef.deepCopyOf(termAtt.getBytesRef())));
|
|
||||||
} else {
|
|
||||||
BooleanQuery.Builder bq = new BooleanQuery.Builder();
|
|
||||||
for (int i = 0; i < numTokens; i++) {
|
|
||||||
try {
|
|
||||||
boolean hasNext = buffer.incrementToken();
|
|
||||||
assert hasNext == true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
// safe to ignore, because we know the number of tokens
|
|
||||||
}
|
|
||||||
bq.add(new BooleanClause(new PrefixQuery(new Term(field, BytesRef.deepCopyOf(termAtt.getBytesRef()))), BooleanClause.Occur.SHOULD));
|
|
||||||
}
|
|
||||||
return bq.build();
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Bail on any exceptions, going with a regular prefix query
|
// Bail on any exceptions, going with a regular prefix query
|
||||||
return new PrefixQuery(new Term(field, termStr));
|
return new PrefixQuery(new Term(field, termStr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tlist.size() == 0) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tlist.size() == 1 && tlist.get(0).size() == 1) {
|
||||||
|
return new PrefixQuery(new Term(field, tlist.get(0).get(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a boolean query with prefix on the last position only.
|
||||||
|
BooleanQuery.Builder builder = new BooleanQuery.Builder();
|
||||||
|
for (int pos = 0; pos < tlist.size(); pos++) {
|
||||||
|
List<String> plist = tlist.get(pos);
|
||||||
|
boolean isLastPos = (pos == tlist.size()-1);
|
||||||
|
Query posQuery;
|
||||||
|
if (plist.size() == 1) {
|
||||||
|
if (isLastPos) {
|
||||||
|
posQuery = new PrefixQuery(new Term(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 {
|
||||||
|
BooleanQuery.Builder innerBuilder = new BooleanQuery.Builder();
|
||||||
|
for (String token : plist) {
|
||||||
|
innerBuilder.add(new BooleanClause(new PrefixQuery(new Term(field, token)),
|
||||||
|
BooleanClause.Occur.SHOULD));
|
||||||
|
}
|
||||||
|
posQuery = innerBuilder.setDisableCoord(true).build();
|
||||||
|
}
|
||||||
|
builder.add(new BooleanClause(posQuery, getDefaultOperator()));
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class encapsulating the settings for the SimpleQueryString query, with
|
* Class encapsulating the settings for the SimpleQueryString query, with
|
||||||
* their default values
|
* their default values
|
||||||
|
|
|
@ -645,13 +645,6 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
|
||||||
assertThat(termQuery.getTerm().text().toLowerCase(Locale.ROOT), equalTo(value.toLowerCase(Locale.ROOT)));
|
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.
|
* Test serialization and deserialization of the test query.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.index.query;
|
||||||
|
|
||||||
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
|
import org.apache.lucene.analysis.TokenFilter;
|
||||||
|
import org.apache.lucene.analysis.TokenStream;
|
||||||
|
import org.apache.lucene.analysis.Tokenizer;
|
||||||
|
import org.apache.lucene.analysis.standard.StandardTokenizer;
|
||||||
|
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
||||||
|
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class MockRepeatAnalyzer extends Analyzer {
|
||||||
|
private static class MockRepeatFilter extends TokenFilter {
|
||||||
|
CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
|
||||||
|
PositionIncrementAttribute posIncAtt = addAttribute(PositionIncrementAttribute.class);
|
||||||
|
String repeat;
|
||||||
|
|
||||||
|
public MockRepeatFilter(TokenStream input) {
|
||||||
|
super(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean incrementToken() throws IOException {
|
||||||
|
if (repeat != null) {
|
||||||
|
// add repeat token
|
||||||
|
clearAttributes();
|
||||||
|
termAtt.setEmpty().append(repeat);
|
||||||
|
posIncAtt.setPositionIncrement(0);
|
||||||
|
repeat = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.incrementToken()) {
|
||||||
|
repeat = termAtt.toString();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TokenStreamComponents createComponents(String fieldName) {
|
||||||
|
Tokenizer tokenizer = new StandardTokenizer();
|
||||||
|
TokenStream repeatFilter = new MockRepeatFilter(tokenizer);
|
||||||
|
return new TokenStreamComponents(tokenizer, repeatFilter);
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,8 @@ package org.elasticsearch.index.query;
|
||||||
|
|
||||||
import org.apache.lucene.document.IntPoint;
|
import org.apache.lucene.document.IntPoint;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
|
import org.apache.lucene.queryparser.classic.MapperQueryParser;
|
||||||
|
import org.apache.lucene.queryparser.classic.QueryParserSettings;
|
||||||
import org.apache.lucene.search.BooleanClause;
|
import org.apache.lucene.search.BooleanClause;
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
import org.apache.lucene.search.BoostQuery;
|
import org.apache.lucene.search.BoostQuery;
|
||||||
|
@ -32,13 +34,18 @@ import org.apache.lucene.search.PhraseQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.RegexpQuery;
|
import org.apache.lucene.search.RegexpQuery;
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
|
import org.apache.lucene.search.SynonymQuery;
|
||||||
|
import org.apache.lucene.search.PrefixQuery;
|
||||||
|
import org.apache.lucene.search.MultiTermQuery;
|
||||||
import org.apache.lucene.util.automaton.TooComplexToDeterminizeException;
|
import org.apache.lucene.util.automaton.TooComplexToDeterminizeException;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.lucene.all.AllTermQuery;
|
import org.elasticsearch.common.lucene.all.AllTermQuery;
|
||||||
|
import org.elasticsearch.common.unit.Fuzziness;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
|
||||||
|
@ -298,32 +305,70 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
|
||||||
assertTermOrBoostQuery(disjuncts.get(1), STRING_FIELD_NAME_2, "test", 1.0f);
|
assertTermOrBoostQuery(disjuncts.get(1), STRING_FIELD_NAME_2, "test", 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testToQueryPrefixQuery() throws Exception {
|
public void testToQueryWildcarQuery() throws Exception {
|
||||||
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
||||||
for (Operator op : Operator.values()) {
|
for (Operator op : Operator.values()) {
|
||||||
Query query = queryStringQuery("foo-bar-foobar*")
|
BooleanClause.Occur defaultOp = op.toBooleanClauseOccur();
|
||||||
.defaultField(STRING_FIELD_NAME)
|
MapperQueryParser queryParser = new MapperQueryParser(createShardContext());
|
||||||
.analyzeWildcard(true)
|
QueryParserSettings settings = new QueryParserSettings("first foo-bar-foobar* last");
|
||||||
.analyzer("standard")
|
settings.defaultField(STRING_FIELD_NAME);
|
||||||
.defaultOperator(op)
|
settings.fieldsAndWeights(Collections.emptyMap());
|
||||||
.toQuery(createShardContext());
|
settings.analyzeWildcard(true);
|
||||||
assertThat(query, instanceOf(BooleanQuery.class));
|
settings.fuzziness(Fuzziness.AUTO);
|
||||||
BooleanQuery bq = (BooleanQuery) query;
|
settings.rewriteMethod(MultiTermQuery.CONSTANT_SCORE_REWRITE);
|
||||||
assertThat(bq.clauses().size(), equalTo(3));
|
settings.defaultOperator(op.toQueryParserOperator());
|
||||||
String[] expectedTerms = new String[]{"foo", "bar", "foobar"};
|
queryParser.reset(settings);
|
||||||
for (int i = 0; i < bq.clauses().size(); i++) {
|
Query query = queryParser.parse("first foo-bar-foobar* last");
|
||||||
BooleanClause clause = bq.clauses().get(i);
|
Query expectedQuery =
|
||||||
if (i != bq.clauses().size() - 1) {
|
new BooleanQuery.Builder()
|
||||||
assertTermQuery(clause.getQuery(), STRING_FIELD_NAME, expectedTerms[i]);
|
.add(new BooleanClause(new TermQuery(new Term(STRING_FIELD_NAME, "first")), defaultOp))
|
||||||
} else {
|
.add(new BooleanQuery.Builder()
|
||||||
assertPrefixQuery(clause.getQuery(), STRING_FIELD_NAME, expectedTerms[i]);
|
.add(new BooleanClause(new TermQuery(new Term(STRING_FIELD_NAME, "foo")), defaultOp))
|
||||||
}
|
.add(new BooleanClause(new TermQuery(new Term(STRING_FIELD_NAME, "bar")), defaultOp))
|
||||||
if (op == Operator.AND) {
|
.add(new BooleanClause(new PrefixQuery(new Term(STRING_FIELD_NAME, "foobar")), defaultOp))
|
||||||
assertThat(clause.getOccur(), equalTo(BooleanClause.Occur.MUST));
|
.build(), defaultOp)
|
||||||
} else {
|
.add(new BooleanClause(new TermQuery(new Term(STRING_FIELD_NAME, "last")), defaultOp))
|
||||||
assertThat(clause.getOccur(), equalTo(BooleanClause.Occur.SHOULD));
|
.build();
|
||||||
|
assertThat(query, Matchers.equalTo(expectedQuery));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testToQueryWilcardQueryWithSynonyms() throws Exception {
|
||||||
|
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
|
||||||
|
for (Operator op : Operator.values()) {
|
||||||
|
BooleanClause.Occur defaultOp = op.toBooleanClauseOccur();
|
||||||
|
MapperQueryParser queryParser = new MapperQueryParser(createShardContext());
|
||||||
|
QueryParserSettings settings = new QueryParserSettings("first foo-bar-foobar* last");
|
||||||
|
settings.defaultField(STRING_FIELD_NAME);
|
||||||
|
settings.fieldsAndWeights(Collections.emptyMap());
|
||||||
|
settings.analyzeWildcard(true);
|
||||||
|
settings.fuzziness(Fuzziness.AUTO);
|
||||||
|
settings.rewriteMethod(MultiTermQuery.CONSTANT_SCORE_REWRITE);
|
||||||
|
settings.defaultOperator(op.toQueryParserOperator());
|
||||||
|
settings.forceAnalyzer(new MockRepeatAnalyzer());
|
||||||
|
queryParser.reset(settings);
|
||||||
|
Query query = queryParser.parse("first foo-bar-foobar* last");
|
||||||
|
|
||||||
|
Query expectedQuery = new BooleanQuery.Builder()
|
||||||
|
.add(new BooleanClause(new SynonymQuery(new Term(STRING_FIELD_NAME, "first"),
|
||||||
|
new Term(STRING_FIELD_NAME, "first")), defaultOp))
|
||||||
|
.add(new BooleanQuery.Builder()
|
||||||
|
.add(new BooleanClause(new SynonymQuery(new Term(STRING_FIELD_NAME, "foo"),
|
||||||
|
new Term(STRING_FIELD_NAME, "foo")), defaultOp))
|
||||||
|
.add(new BooleanClause(new SynonymQuery(new Term(STRING_FIELD_NAME, "bar"),
|
||||||
|
new Term(STRING_FIELD_NAME, "bar")), defaultOp))
|
||||||
|
.add(new BooleanQuery.Builder()
|
||||||
|
.add(new BooleanClause(new PrefixQuery(new Term(STRING_FIELD_NAME, "foobar")),
|
||||||
|
BooleanClause.Occur.SHOULD))
|
||||||
|
.add(new BooleanClause(new PrefixQuery(new Term(STRING_FIELD_NAME, "foobar")),
|
||||||
|
BooleanClause.Occur.SHOULD))
|
||||||
|
.setDisableCoord(true)
|
||||||
|
.build(), defaultOp)
|
||||||
|
.build(), defaultOp)
|
||||||
|
.add(new BooleanClause(new SynonymQuery(new Term(STRING_FIELD_NAME, "last"),
|
||||||
|
new Term(STRING_FIELD_NAME, "last")), defaultOp))
|
||||||
|
.build();
|
||||||
|
assertThat(query, Matchers.equalTo(expectedQuery));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.index.query;
|
||||||
|
|
||||||
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
|
import org.apache.lucene.analysis.standard.StandardAnalyzer;
|
||||||
|
import org.apache.lucene.index.Term;
|
||||||
|
import org.apache.lucene.search.Query;
|
||||||
|
import org.apache.lucene.search.TermQuery;
|
||||||
|
import org.apache.lucene.search.SynonymQuery;
|
||||||
|
import org.apache.lucene.search.PrefixQuery;
|
||||||
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
|
import org.apache.lucene.search.BooleanClause;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
|
public class SimpleQueryParserTests extends ESTestCase {
|
||||||
|
private static class MockSimpleQueryParser extends SimpleQueryParser {
|
||||||
|
public MockSimpleQueryParser(Analyzer analyzer, Map<String, Float> weights, int flags, Settings settings) {
|
||||||
|
super(analyzer, weights, flags, settings, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Query newTermQuery(Term term) {
|
||||||
|
return new TermQuery(term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAnalyzeWildcard() {
|
||||||
|
SimpleQueryParser.Settings settings = new SimpleQueryParser.Settings();
|
||||||
|
settings.analyzeWildcard(true);
|
||||||
|
Map<String, Float> weights = new HashMap<>();
|
||||||
|
weights.put("field1", 1.0f);
|
||||||
|
SimpleQueryParser parser = new MockSimpleQueryParser(new StandardAnalyzer(), weights, -1, settings);
|
||||||
|
for (Operator op : Operator.values()) {
|
||||||
|
BooleanClause.Occur defaultOp = op.toBooleanClauseOccur();
|
||||||
|
parser.setDefaultOperator(defaultOp);
|
||||||
|
Query query = parser.parse("first foo-bar-foobar* last");
|
||||||
|
Query expectedQuery =
|
||||||
|
new BooleanQuery.Builder()
|
||||||
|
.add(new BooleanClause(new TermQuery(new Term("field1", "first")), defaultOp))
|
||||||
|
.add(new BooleanQuery.Builder()
|
||||||
|
.add(new BooleanClause(new TermQuery(new Term("field1", "foo")), defaultOp))
|
||||||
|
.add(new BooleanClause(new TermQuery(new Term("field1", "bar")), defaultOp))
|
||||||
|
.add(new BooleanClause(new PrefixQuery(new Term("field1", "foobar")), defaultOp))
|
||||||
|
.build(), defaultOp)
|
||||||
|
.add(new BooleanClause(new TermQuery(new Term("field1", "last")), defaultOp))
|
||||||
|
.build();
|
||||||
|
assertThat(query, equalTo(expectedQuery));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAnalyzerWildcardWithSynonyms() {
|
||||||
|
SimpleQueryParser.Settings settings = new SimpleQueryParser.Settings();
|
||||||
|
settings.analyzeWildcard(true);
|
||||||
|
Map<String, Float> weights = new HashMap<>();
|
||||||
|
weights.put("field1", 1.0f);
|
||||||
|
SimpleQueryParser parser = new MockSimpleQueryParser(new MockRepeatAnalyzer(), weights, -1, settings);
|
||||||
|
|
||||||
|
for (Operator op : Operator.values()) {
|
||||||
|
BooleanClause.Occur defaultOp = op.toBooleanClauseOccur();
|
||||||
|
parser.setDefaultOperator(defaultOp);
|
||||||
|
Query query = parser.parse("first foo-bar-foobar* last");
|
||||||
|
|
||||||
|
Query expectedQuery = new BooleanQuery.Builder()
|
||||||
|
.add(new BooleanClause(new SynonymQuery(new Term("field1", "first"),
|
||||||
|
new Term("field1", "first")), defaultOp))
|
||||||
|
.add(new BooleanQuery.Builder()
|
||||||
|
.add(new BooleanClause(new SynonymQuery(new Term("field1", "foo"),
|
||||||
|
new Term("field1", "foo")), defaultOp))
|
||||||
|
.add(new BooleanClause(new SynonymQuery(new Term("field1", "bar"),
|
||||||
|
new Term("field1", "bar")), defaultOp))
|
||||||
|
.add(new BooleanQuery.Builder()
|
||||||
|
.add(new BooleanClause(new PrefixQuery(new Term("field1", "foobar")),
|
||||||
|
BooleanClause.Occur.SHOULD))
|
||||||
|
.add(new BooleanClause(new PrefixQuery(new Term("field1", "foobar")),
|
||||||
|
BooleanClause.Occur.SHOULD))
|
||||||
|
.setDisableCoord(true)
|
||||||
|
.build(), defaultOp)
|
||||||
|
.build(), defaultOp)
|
||||||
|
.add(new BooleanClause(new SynonymQuery(new Term("field1", "last"),
|
||||||
|
new Term("field1", "last")), defaultOp))
|
||||||
|
.build();
|
||||||
|
assertThat(query, equalTo(expectedQuery));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue