mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-24 17:09:48 +00:00
Fixes query_string query equals timezone check (#29406)
* Fixes query_string query equals timezone check This change fixes a bug where two `QueryStringQueryBuilder`s were found to be equal if they had the same timezone set even if the query string in the builders were different Closes #29403 * Adds mutate function to QueryStringQueryBuilderTests * iter
This commit is contained in:
parent
d649449d37
commit
55c8e80532
@ -42,7 +42,6 @@ import org.joda.time.DateTimeZone;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -358,7 +357,7 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float tieBreaker() {
|
public Float tieBreaker() {
|
||||||
return this.tieBreaker;
|
return this.tieBreaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,6 +388,22 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
|
|||||||
this.analyzer = analyzer;
|
this.analyzer = analyzer;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The optional analyzer used to analyze the query string. Note, if a field has search analyzer
|
||||||
|
* defined for it, then it will be used automatically. Defaults to the smart search analyzer.
|
||||||
|
*/
|
||||||
|
public String analyzer() {
|
||||||
|
return analyzer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The optional analyzer used to analyze the query string for phrase searches. Note, if a field has search (quote) analyzer
|
||||||
|
* defined for it, then it will be used automatically. Defaults to the smart search analyzer.
|
||||||
|
*/
|
||||||
|
public String quoteAnalyzer() {
|
||||||
|
return quoteAnalyzer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The optional analyzer used to analyze the query string for phrase searches. Note, if a field has search (quote) analyzer
|
* The optional analyzer used to analyze the query string for phrase searches. Note, if a field has search (quote) analyzer
|
||||||
@ -884,9 +899,10 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
|
|||||||
Objects.equals(tieBreaker, other.tieBreaker) &&
|
Objects.equals(tieBreaker, other.tieBreaker) &&
|
||||||
Objects.equals(rewrite, other.rewrite) &&
|
Objects.equals(rewrite, other.rewrite) &&
|
||||||
Objects.equals(minimumShouldMatch, other.minimumShouldMatch) &&
|
Objects.equals(minimumShouldMatch, other.minimumShouldMatch) &&
|
||||||
Objects.equals(lenient, other.lenient) &&
|
Objects.equals(lenient, other.lenient) &&
|
||||||
timeZone == null ? other.timeZone == null : other.timeZone != null &&
|
Objects.equals(
|
||||||
Objects.equals(timeZone.getID(), other.timeZone.getID()) &&
|
timeZone == null ? null : timeZone.getID(),
|
||||||
|
other.timeZone == null ? null : other.timeZone.getID()) &&
|
||||||
Objects.equals(escape, other.escape) &&
|
Objects.equals(escape, other.escape) &&
|
||||||
Objects.equals(maxDeterminizedStates, other.maxDeterminizedStates) &&
|
Objects.equals(maxDeterminizedStates, other.maxDeterminizedStates) &&
|
||||||
Objects.equals(autoGenerateSynonymsPhraseQuery, other.autoGenerateSynonymsPhraseQuery) &&
|
Objects.equals(autoGenerateSynonymsPhraseQuery, other.autoGenerateSynonymsPhraseQuery) &&
|
||||||
|
@ -66,7 +66,9 @@ import org.joda.time.DateTimeZone;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder;
|
import static org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
|
||||||
@ -172,6 +174,206 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
|
|||||||
return queryStringQueryBuilder;
|
return queryStringQueryBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryStringQueryBuilder mutateInstance(QueryStringQueryBuilder instance) throws IOException {
|
||||||
|
String query = instance.queryString();
|
||||||
|
String defaultField = instance.defaultField();
|
||||||
|
Map<String, Float> fields = instance.fields();
|
||||||
|
Operator operator = instance.defaultOperator();
|
||||||
|
Fuzziness fuzziness = instance.fuzziness();
|
||||||
|
String analyzer = instance.analyzer();
|
||||||
|
String quoteAnalyzer = instance.quoteAnalyzer();
|
||||||
|
Boolean allowLeadingWildCard = instance.allowLeadingWildcard();
|
||||||
|
Boolean analyzeWildcard = instance.analyzeWildcard();
|
||||||
|
int maxDeterminizedStates = instance.maxDeterminizedStates();
|
||||||
|
boolean enablePositionIncrements = instance.enablePositionIncrements();
|
||||||
|
boolean escape = instance.escape();
|
||||||
|
int phraseSlop = instance.phraseSlop();
|
||||||
|
int fuzzyMaxExpansions = instance.fuzzyMaxExpansions();
|
||||||
|
int fuzzyPrefixLength = instance.fuzzyPrefixLength();
|
||||||
|
String fuzzyRewrite = instance.fuzzyRewrite();
|
||||||
|
String rewrite = instance.rewrite();
|
||||||
|
String quoteFieldSuffix = instance.quoteFieldSuffix();
|
||||||
|
Float tieBreaker = instance.tieBreaker();
|
||||||
|
String minimumShouldMatch = instance.minimumShouldMatch();
|
||||||
|
String timeZone = instance.timeZone() == null ? null : instance.timeZone().getID();
|
||||||
|
boolean autoGenerateSynonymsPhraseQuery = instance.autoGenerateSynonymsPhraseQuery();
|
||||||
|
boolean fuzzyTranspositions = instance.fuzzyTranspositions();
|
||||||
|
|
||||||
|
switch (between(0, 23)) {
|
||||||
|
case 0:
|
||||||
|
query = query + " foo";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (defaultField == null) {
|
||||||
|
defaultField = randomAlphaOfLengthBetween(1, 10);
|
||||||
|
} else {
|
||||||
|
defaultField = defaultField + randomAlphaOfLength(5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fields = new HashMap<>(fields);
|
||||||
|
fields.put(randomAlphaOfLength(10), 1.0f);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
operator = randomValueOtherThan(operator, () -> randomFrom(Operator.values()));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
fuzziness = randomValueOtherThan(fuzziness, () -> randomFrom(Fuzziness.AUTO, Fuzziness.ZERO, Fuzziness.ONE, Fuzziness.TWO));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if (analyzer == null) {
|
||||||
|
analyzer = randomAnalyzer();
|
||||||
|
} else {
|
||||||
|
analyzer = null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
if (quoteAnalyzer == null) {
|
||||||
|
quoteAnalyzer = randomAnalyzer();
|
||||||
|
} else {
|
||||||
|
quoteAnalyzer = null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
if (allowLeadingWildCard == null) {
|
||||||
|
allowLeadingWildCard = randomBoolean();
|
||||||
|
} else {
|
||||||
|
allowLeadingWildCard = randomBoolean() ? null : (allowLeadingWildCard == false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
if (analyzeWildcard == null) {
|
||||||
|
analyzeWildcard = randomBoolean();
|
||||||
|
} else {
|
||||||
|
analyzeWildcard = randomBoolean() ? null : (analyzeWildcard == false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
maxDeterminizedStates += 5;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
enablePositionIncrements = (enablePositionIncrements == false);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
escape = (escape == false);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
phraseSlop += 5;
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
fuzzyMaxExpansions += 5;
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
fuzzyPrefixLength += 5;
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
if (fuzzyRewrite == null) {
|
||||||
|
fuzzyRewrite = getRandomRewriteMethod();
|
||||||
|
} else {
|
||||||
|
fuzzyRewrite = null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
if (rewrite == null) {
|
||||||
|
rewrite = getRandomRewriteMethod();
|
||||||
|
} else {
|
||||||
|
rewrite = null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
if (quoteFieldSuffix == null) {
|
||||||
|
quoteFieldSuffix = randomAlphaOfLengthBetween(1, 3);
|
||||||
|
} else {
|
||||||
|
quoteFieldSuffix = quoteFieldSuffix + randomAlphaOfLength(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
if (tieBreaker == null) {
|
||||||
|
tieBreaker = randomFloat();
|
||||||
|
} else {
|
||||||
|
tieBreaker += 0.05f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
if (minimumShouldMatch == null) {
|
||||||
|
minimumShouldMatch = randomMinimumShouldMatch();
|
||||||
|
} else {
|
||||||
|
minimumShouldMatch = null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
if (timeZone == null) {
|
||||||
|
timeZone = randomDateTimeZone().getID();
|
||||||
|
} else {
|
||||||
|
if (randomBoolean()) {
|
||||||
|
timeZone = null;
|
||||||
|
} else {
|
||||||
|
timeZone = randomValueOtherThan(timeZone, () -> randomDateTimeZone().getID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 21:
|
||||||
|
autoGenerateSynonymsPhraseQuery = (autoGenerateSynonymsPhraseQuery == false);
|
||||||
|
break;
|
||||||
|
case 22:
|
||||||
|
fuzzyTranspositions = (fuzzyTranspositions == false);
|
||||||
|
break;
|
||||||
|
case 23:
|
||||||
|
return changeNameOrBoost(instance);
|
||||||
|
default:
|
||||||
|
throw new AssertionError("Illegal randomisation branch");
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryStringQueryBuilder newInstance = new QueryStringQueryBuilder(query);
|
||||||
|
if (defaultField != null) {
|
||||||
|
newInstance.defaultField(defaultField);
|
||||||
|
}
|
||||||
|
newInstance.fields(fields);
|
||||||
|
newInstance.defaultOperator(operator);
|
||||||
|
newInstance.fuzziness(fuzziness);
|
||||||
|
if (analyzer != null) {
|
||||||
|
newInstance.analyzer(analyzer);
|
||||||
|
}
|
||||||
|
if (quoteAnalyzer != null) {
|
||||||
|
newInstance.quoteAnalyzer(quoteAnalyzer);
|
||||||
|
}
|
||||||
|
if (allowLeadingWildCard != null) {
|
||||||
|
newInstance.allowLeadingWildcard(allowLeadingWildCard);
|
||||||
|
}
|
||||||
|
if (analyzeWildcard != null) {
|
||||||
|
newInstance.analyzeWildcard(analyzeWildcard);
|
||||||
|
}
|
||||||
|
newInstance.maxDeterminizedStates(maxDeterminizedStates);
|
||||||
|
newInstance.enablePositionIncrements(enablePositionIncrements);
|
||||||
|
newInstance.escape(escape);
|
||||||
|
newInstance.phraseSlop(phraseSlop);
|
||||||
|
newInstance.fuzzyMaxExpansions(fuzzyMaxExpansions);
|
||||||
|
newInstance.fuzzyPrefixLength(fuzzyPrefixLength);
|
||||||
|
if (fuzzyRewrite != null) {
|
||||||
|
newInstance.fuzzyRewrite(fuzzyRewrite);
|
||||||
|
}
|
||||||
|
if (rewrite != null) {
|
||||||
|
newInstance.rewrite(rewrite);
|
||||||
|
}
|
||||||
|
if (quoteFieldSuffix != null) {
|
||||||
|
newInstance.quoteFieldSuffix(quoteFieldSuffix);
|
||||||
|
}
|
||||||
|
if (tieBreaker != null) {
|
||||||
|
newInstance.tieBreaker(tieBreaker);
|
||||||
|
}
|
||||||
|
if (minimumShouldMatch != null) {
|
||||||
|
newInstance.minimumShouldMatch(minimumShouldMatch);
|
||||||
|
}
|
||||||
|
if (timeZone != null) {
|
||||||
|
newInstance.timeZone(timeZone);
|
||||||
|
}
|
||||||
|
newInstance.autoGenerateSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery);
|
||||||
|
newInstance.fuzzyTranspositions(fuzzyTranspositions);
|
||||||
|
|
||||||
|
return newInstance;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doAssertLuceneQuery(QueryStringQueryBuilder queryBuilder,
|
protected void doAssertLuceneQuery(QueryStringQueryBuilder queryBuilder,
|
||||||
Query query, SearchContext context) throws IOException {
|
Query query, SearchContext context) throws IOException {
|
||||||
@ -182,6 +384,16 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
|
|||||||
.or(instanceOf(MatchNoDocsQuery.class)));
|
.or(instanceOf(MatchNoDocsQuery.class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests fix for https://github.com/elastic/elasticsearch/issues/29403
|
||||||
|
public void testTimezoneEquals() {
|
||||||
|
QueryStringQueryBuilder builder1 = new QueryStringQueryBuilder("bar");
|
||||||
|
QueryStringQueryBuilder builder2 = new QueryStringQueryBuilder("foo");
|
||||||
|
assertNotEquals(builder1, builder2);
|
||||||
|
builder1.timeZone("Europe/London");
|
||||||
|
builder2.timeZone("Europe/London");
|
||||||
|
assertNotEquals(builder1, builder2);
|
||||||
|
}
|
||||||
|
|
||||||
public void testIllegalArguments() {
|
public void testIllegalArguments() {
|
||||||
expectThrows(IllegalArgumentException.class, () -> new QueryStringQueryBuilder((String) null));
|
expectThrows(IllegalArgumentException.class, () -> new QueryStringQueryBuilder((String) null));
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
package org.elasticsearch.test;
|
package org.elasticsearch.test;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.io.JsonStringEncoder;
|
import com.fasterxml.jackson.core.io.JsonStringEncoder;
|
||||||
|
|
||||||
import org.apache.lucene.search.BoostQuery;
|
import org.apache.lucene.search.BoostQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
@ -55,7 +56,6 @@ import org.elasticsearch.common.unit.Fuzziness;
|
|||||||
import org.elasticsearch.common.xcontent.DeprecationHandler;
|
import org.elasticsearch.common.xcontent.DeprecationHandler;
|
||||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContent;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentGenerator;
|
import org.elasticsearch.common.xcontent.XContentGenerator;
|
||||||
@ -742,10 +742,14 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
|
|||||||
for (int runs = 0; runs < NUMBER_OF_TESTQUERIES; runs++) {
|
for (int runs = 0; runs < NUMBER_OF_TESTQUERIES; runs++) {
|
||||||
// TODO we only change name and boost, we should extend by any sub-test supplying a "mutate" method that randomly changes one
|
// TODO we only change name and boost, we should extend by any sub-test supplying a "mutate" method that randomly changes one
|
||||||
// aspect of the object under test
|
// aspect of the object under test
|
||||||
checkEqualsAndHashCode(createTestQueryBuilder(), this::copyQuery, this::changeNameOrBoost);
|
checkEqualsAndHashCode(createTestQueryBuilder(), this::copyQuery, this::mutateInstance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public QB mutateInstance(QB instance) throws IOException {
|
||||||
|
return changeNameOrBoost(instance);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic test that checks that the <code>Strings.toString()</code> method
|
* Generic test that checks that the <code>Strings.toString()</code> method
|
||||||
* renders the XContent correctly.
|
* renders the XContent correctly.
|
||||||
@ -761,7 +765,7 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private QB changeNameOrBoost(QB original) throws IOException {
|
protected QB changeNameOrBoost(QB original) throws IOException {
|
||||||
QB secondQuery = copyQuery(original);
|
QB secondQuery = copyQuery(original);
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
secondQuery.queryName(secondQuery.queryName() == null ? randomAlphaOfLengthBetween(1, 30) : secondQuery.queryName()
|
secondQuery.queryName(secondQuery.queryName() == null ? randomAlphaOfLengthBetween(1, 30) : secondQuery.queryName()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user