Browse Source

Allow overriding all-field leniency when `lenient` option is specified

As part of #20925 and #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.
Lee Hinman 9 years ago
parent
commit
11da09e9bc

+ 2 - 2
core/src/main/java/org/elasticsearch/index/query/QueryStringQueryBuilder.java

@@ -964,8 +964,8 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
                         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);
 

+ 18 - 4
core/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java

@@ -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();
@@ -162,6 +164,9 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
             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
@@ -188,6 +193,9 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
             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
@@ -315,6 +323,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
     /** Specifies whether query parsing should be lenient. Defaults to false. */
     public SimpleQueryStringBuilder lenient(boolean lenient) {
         this.settings.lenient(lenient);
+        this.lenientSet = true;
         return this;
     }
 
@@ -372,7 +381,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
                         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()) {
@@ -444,7 +453,9 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
 
         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());
@@ -473,7 +484,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
         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;
@@ -565,7 +576,10 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
         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);
     }

+ 8 - 1
core/src/test/java/org/elasticsearch/search/query/QueryStringIT.java

@@ -255,6 +255,14 @@ public class QueryStringIT extends ESIntegTestCase {
                 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<>();
@@ -263,5 +271,4 @@ public class QueryStringIT extends ESIntegTestCase {
         }
         assertThat(hitIds, containsInAnyOrder(ids));
     }
-
 }

+ 12 - 0
core/src/test/java/org/elasticsearch/search/query/SimpleQueryStringIT.java

@@ -564,6 +564,18 @@ public class SimpleQueryStringIT extends ESIntegTestCase {
         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<>();

+ 2 - 2
docs/reference/search/validate.asciidoc

@@ -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
 
@@ -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