Skip to content

Commit

Permalink
Allow overriding all-field leniency when lenient option is specified
Browse files Browse the repository at this point in the history
As part of elastic#20925 and elastic#21341 we added an "all-fields" mode to the
`query_string` and `simple_query_string`. This would expand the query to
all fields and automatically set `lenient` to true.

However, we should still allow a user to override the `lenient` flag to
whichever value they desire, should they add it in the request. This
commit does that.
  • Loading branch information
dakrone committed Nov 22, 2016
1 parent 446037c commit 11da09e
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -964,8 +964,8 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
this.fieldsAndWeights.size() == 0)) {
// Use the automatically determined expansion of all queryable fields
resolvedFields = allQueryableDefaultFields(context);
// Automatically set leniency to "true" so mismatched fields don't cause exceptions
qpSettings.lenient(true);
// Automatically set leniency to "true" if unset so mismatched fields don't cause exceptions
qpSettings.lenient(lenient == null ? true : lenient);
} else {
qpSettings.defaultField(this.defaultField == null ? context.defaultField() : this.defaultField);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
private int flags = DEFAULT_FLAGS;
/** Flag specifying whether query should be forced to expand to all searchable fields */
private Boolean useAllFields;
/** Whether or not the lenient flag has been set or not */
private boolean lenientSet = false;

/** Further search settings needed by the ES specific query string parser only. */
private Settings settings = new Settings();
Expand Down Expand Up @@ -162,6 +164,9 @@ public SimpleQueryStringBuilder(StreamInput in) throws IOException {
in.readBoolean(); // lowercase_expanded_terms
}
settings.lenient(in.readBoolean());
if (in.getVersion().onOrAfter(V_5_1_0_UNRELEASED)) {
this.lenientSet = in.readBoolean();
}
settings.analyzeWildcard(in.readBoolean());
if (in.getVersion().before(V_5_1_0_UNRELEASED)) {
in.readString(); // locale
Expand All @@ -188,6 +193,9 @@ protected void doWriteTo(StreamOutput out) throws IOException {
out.writeBoolean(true); // lowercase_expanded_terms
}
out.writeBoolean(settings.lenient());
if (out.getVersion().onOrAfter(V_5_1_0_UNRELEASED)) {
out.writeBoolean(lenientSet);
}
out.writeBoolean(settings.analyzeWildcard());
if (out.getVersion().before(V_5_1_0_UNRELEASED)) {
out.writeString(Locale.ROOT.toLanguageTag()); // locale
Expand Down Expand Up @@ -315,6 +323,7 @@ public String quoteFieldSuffix() {
/** Specifies whether query parsing should be lenient. Defaults to false. */
public SimpleQueryStringBuilder lenient(boolean lenient) {
this.settings.lenient(lenient);
this.lenientSet = true;
return this;
}

Expand Down Expand Up @@ -372,7 +381,7 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
this.fieldsAndWeights.isEmpty())) {
resolvedFieldsAndWeights = QueryStringQueryBuilder.allQueryableDefaultFields(context);
// Need to use lenient mode when using "all-mode" so exceptions aren't thrown due to mismatched types
newSettings.lenient(true);
newSettings.lenient(lenientSet ? settings.lenient() : true);
} else {
// Use the default field if no fields specified
if (fieldsAndWeights.isEmpty()) {
Expand Down Expand Up @@ -444,7 +453,9 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep

builder.field(FLAGS_FIELD.getPreferredName(), flags);
builder.field(DEFAULT_OPERATOR_FIELD.getPreferredName(), defaultOperator.name().toLowerCase(Locale.ROOT));
builder.field(LENIENT_FIELD.getPreferredName(), settings.lenient());
if (lenientSet) {
builder.field(LENIENT_FIELD.getPreferredName(), settings.lenient());
}
builder.field(ANALYZE_WILDCARD_FIELD.getPreferredName(), settings.analyzeWildcard());
if (settings.quoteFieldSuffix() != null) {
builder.field(QUOTE_FIELD_SUFFIX_FIELD.getPreferredName(), settings.quoteFieldSuffix());
Expand Down Expand Up @@ -473,7 +484,7 @@ public static Optional<SimpleQueryStringBuilder> fromXContent(QueryParseContext
Operator defaultOperator = null;
String analyzerName = null;
int flags = SimpleQueryStringFlag.ALL.value();
boolean lenient = SimpleQueryStringBuilder.DEFAULT_LENIENT;
Boolean lenient = null;
boolean analyzeWildcard = SimpleQueryStringBuilder.DEFAULT_ANALYZE_WILDCARD;
String quoteFieldSuffix = null;
Boolean useAllFields = null;
Expand Down Expand Up @@ -565,7 +576,10 @@ public static Optional<SimpleQueryStringBuilder> fromXContent(QueryParseContext
SimpleQueryStringBuilder qb = new SimpleQueryStringBuilder(queryBody);
qb.boost(boost).fields(fieldsAndWeights).analyzer(analyzerName).queryName(queryName).minimumShouldMatch(minimumShouldMatch);
qb.flags(flags).defaultOperator(defaultOperator);
qb.lenient(lenient).analyzeWildcard(analyzeWildcard).boost(boost).quoteFieldSuffix(quoteFieldSuffix);
if (lenient != null) {
qb.lenient(lenient);
}
qb.analyzeWildcard(analyzeWildcard).boost(boost).quoteFieldSuffix(quoteFieldSuffix);
qb.useAllFields(useAllFields);
return Optional.of(qb);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,14 @@ public void testBooleanStrictQuery() throws Exception {
containsString("Can't parse boolean value [foo], expected [true] or [false]"));
}

public void testAllFieldsWithSpecifiedLeniency() throws IOException {
Exception e = expectThrows(Exception.class, () ->
client().prepareSearch("test").setQuery(
queryStringQuery("f_date:[now-2D TO now]").lenient(false)).get());
assertThat(ExceptionsHelper.detailedMessage(e),
containsString("unit [D] not supported for date math [-2D]"));
}

private void assertHits(SearchHits hits, String... ids) {
assertThat(hits.totalHits(), equalTo((long) ids.length));
Set<String> hitIds = new HashSet<>();
Expand All @@ -263,5 +271,4 @@ private void assertHits(SearchHits hits, String... ids) {
}
assertThat(hitIds, containsInAnyOrder(ids));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,18 @@ public void testPhraseQueryOnFieldWithNoPositions() throws Exception {
assertHitCount(resp, 1L);
}

public void testAllFieldsWithSpecifiedLeniency() throws IOException {
String indexBody = copyToStringFromClasspath("/org/elasticsearch/search/query/all-query-index.json");
prepareCreate("test").setSource(indexBody).get();
ensureGreen("test");

Exception e = expectThrows(Exception.class, () ->
client().prepareSearch("test").setQuery(
simpleQueryStringQuery("foo123").lenient(false)).get());
assertThat(ExceptionsHelper.detailedMessage(e),
containsString("NumberFormatException[For input string: \"foo123\"]"));
}

private void assertHits(SearchHits hits, String... ids) {
assertThat(hits.totalHits(), equalTo((long) ids.length));
Set<String> hitIds = new HashSet<>();
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/search/validate.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ due to dynamic mapping, and 'foo' does not correctly parse into a date:

[source,js]
--------------------------------------------------
GET twitter/tweet/_validate/query?q=post_date:foo
GET twitter/tweet/_validate/query?q=post_date:foo%5d
--------------------------------------------------
// CONSOLE

Expand All @@ -102,7 +102,7 @@ about why a query failed:

[source,js]
--------------------------------------------------
GET twitter/tweet/_validate/query?q=post_date:foo&explain=true
GET twitter/tweet/_validate/query?q=post_date:foo%5d&explain=true
--------------------------------------------------
// CONSOLE

Expand Down

0 comments on commit 11da09e

Please sign in to comment.