From 7490304afc2639dd521740014219a55a6b88d7f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 16 Dec 2019 10:35:52 +0100 Subject: [PATCH 01/11] Make range query rounding consistent Currently the rounding for date math used in range queries behaves differently for `date` and `date_range` as explained in #50009. The behaviour on `date` fields is the one we document in https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html#range-query-date-math-rounding. This change adapts the rounding behaviour for RangeType.DATE so it uses the same logic as the `date` type. Closes #50009 --- .../rest-api-spec/test/range/10_basic.yml | 53 +++++++++++++++++++ .../elasticsearch/index/mapper/RangeType.java | 6 ++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/range/10_basic.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/range/10_basic.yml index 44c60cfe70b52..d630de417faf9 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/range/10_basic.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/range/10_basic.yml @@ -391,3 +391,56 @@ setup: body: { "size" : 0, "query" : { "range" : { "date_range" : { "gte": "2017-09-03", "lte" : "2017-09-04", "relation": "within" } } } } - match: { hits.total: 0 } + +--- +"Date range rounding": + + - do: + index: + index: test + id: 1 + body: { "date_range" : { "gte": "2019-12-14T12:00:00.000Z", "lte": "2019-12-14T13:00:00.000Z" } } + + - do: + index: + index: test + id: 2 + body: { "date_range" : { "gte": "2019-12-15T12:00:00.000Z", "lte": "2019-12-15T13:00:00.000Z" } } + + - do: + index: + index: test + id: 3 + body: { "date_range" : { "gte": "2019-12-16T12:00:00.000Z", "lte": "2019-12-16T13:00:00.000Z" } } + + + - do: + indices.refresh: {} + + - do: + search: + rest_total_hits_as_int: true + body: { "size" : 0, "query" : { "range" : { "date_range" : { "gt": "2019-12-15||/d", "relation": "within" } } } } + + - match: { hits.total: 1 } + + - do: + search: + rest_total_hits_as_int: true + body: { "size" : 0, "query" : { "range" : { "date_range" : { "gte": "2019-12-15||/d", "relation": "within" } } } } + + - match: { hits.total: 2 } + + - do: + search: + rest_total_hits_as_int: true + body: { "size" : 0, "query" : { "range" : { "date_range" : { "lt": "2019-12-15||/d", "relation": "within" } } } } + + - match: { hits.total: 1 } + + - do: + search: + rest_total_hits_as_int: true + body: { "size" : 0, "query" : { "range" : { "date_range" : { "lte": "2019-12-15||/d", "relation": "within" } } } } + + - match: { hits.total: 2 } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/RangeType.java b/server/src/main/java/org/elasticsearch/index/mapper/RangeType.java index 256325eba5974..8e62b8e9fb232 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/RangeType.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/RangeType.java @@ -232,12 +232,14 @@ public Query rangeQuery(String field, boolean hasDocValues, Object lowerTerm, Ob DateMathParser dateMathParser = (parser == null) ? DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.toDateMathParser() : parser; + boolean roundUp = includeLower == false; // using "gt" should round lower bound up Long low = lowerTerm == null ? Long.MIN_VALUE : dateMathParser.parse(lowerTerm instanceof BytesRef ? ((BytesRef) lowerTerm).utf8ToString() : lowerTerm.toString(), - context::nowInMillis, false, zone).toEpochMilli(); + context::nowInMillis, roundUp, zone).toEpochMilli(); + roundUp = includeUpper; // using "lte" should round upper bound up Long high = upperTerm == null ? Long.MAX_VALUE : dateMathParser.parse(upperTerm instanceof BytesRef ? ((BytesRef) upperTerm).utf8ToString() : upperTerm.toString(), - context::nowInMillis, false, zone).toEpochMilli(); + context::nowInMillis, roundUp, zone).toEpochMilli(); return super.rangeQuery(field, hasDocValues, low, high, includeLower, includeUpper, relation, zone, dateMathParser, context); From 07e673cff09bd150f70d322152366bf67690d2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 16 Dec 2019 17:32:20 +0100 Subject: [PATCH 02/11] Fixing tests --- .../rest-api-spec/test/range/10_basic.yml | 3 +++ .../RangeFieldQueryStringQueryBuilderTests.java | 5 +++-- .../index/mapper/RangeFieldTypeTests.java | 17 +++++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/range/10_basic.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/range/10_basic.yml index d630de417faf9..54eb84bc95f1e 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/range/10_basic.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/range/10_basic.yml @@ -394,6 +394,9 @@ setup: --- "Date range rounding": + - skip: + version: " - 7.99.99" + reason: "This part tests rounding behaviour changed in 8.0.0" - do: index: diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java index 535f27c5aa3db..d10b436f0897b 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java @@ -39,6 +39,7 @@ import java.io.IOException; import java.net.InetAddress; +import java.time.ZoneId; import static org.hamcrest.Matchers.either; import static org.hamcrest.core.IsInstanceOf.instanceOf; @@ -104,11 +105,11 @@ public void testDateRangeQuery() throws Exception { Query query = new QueryStringQueryBuilder(DATE_RANGE_FIELD_NAME + ":[2010-01-01 TO 2018-01-01]").toQuery(createShardContext()); Query range = LongRange.newIntersectsQuery(DATE_RANGE_FIELD_NAME, new long[]{ parser.parse("2010-01-01", () -> 0).toEpochMilli()}, - new long[]{ parser.parse("2018-01-01", () -> 0).toEpochMilli()}); + new long[]{ parser.parse("2018-01-01", () -> 0, true, (ZoneId) null).toEpochMilli()}); Query dv = RangeType.DATE.dvRangeQuery(DATE_RANGE_FIELD_NAME, BinaryDocValuesRangeQuery.QueryType.INTERSECTS, parser.parse("2010-01-01", () -> 0).toEpochMilli(), - parser.parse("2018-01-01", () -> 0).toEpochMilli(), true, true); + parser.parse("2018-01-02", () -> 0).toEpochMilli(), true, false); assertEquals(new IndexOrDocValuesQuery(range, dv), query); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java index 79ab18afbd590..dd59c1e9b401a 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java @@ -40,6 +40,7 @@ import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.index.IndexSettings; +import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType; import org.elasticsearch.index.mapper.RangeFieldMapper.RangeFieldType; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.test.IndexSettingsModule; @@ -162,7 +163,7 @@ public void testRangeQueryIntersectsAdjacentValues() throws Exception { assertThat(rangeQuery, instanceOf(IndexOrDocValuesQuery.class)); assertThat(((IndexOrDocValuesQuery) rangeQuery).getIndexQuery(), instanceOf(MatchNoDocsQuery.class)); } - + /** * check that we catch cases where the user specifies larger "from" than "to" value, not counting the include upper/lower settings */ @@ -231,14 +232,15 @@ private QueryShardContext createContext() { return new QueryShardContext(0, idxSettings, BigArrays.NON_RECYCLING_INSTANCE, null, null, null, null, null, xContentRegistry(), writableRegistry(), null, null, () -> nowInMillis, null, null); } - + public void testDateRangeQueryUsingMappingFormat() { QueryShardContext context = createContext(); RangeFieldType fieldType = new RangeFieldType(RangeType.DATE); fieldType.setName(FIELDNAME); fieldType.setIndexOptions(IndexOptions.DOCS); fieldType.setHasDocValues(false); - ShapeRelation relation = randomFrom(ShapeRelation.values()); + // don't use DISJOINT here because it doesn't work on date fields which we want to compare bounds with + ShapeRelation relation = randomValueOtherThan(ShapeRelation.DISJOINT,() -> randomFrom(ShapeRelation.values())); // dates will break the default format, month/day of month is turned around in the format final String from = "2016-15-06T15:29:50+08:00"; @@ -257,7 +259,14 @@ public void testDateRangeQueryUsingMappingFormat() { fieldType.setDateTimeFormatter(formatter); final Query query = fieldType.rangeQuery(from, to, true, true, relation, null, null, context); - assertEquals("field:", query.toString()); + assertEquals("field:", query.toString()); + + // compare lower and upper bounds with what we would get on a `date` field + DateFieldType dateFieldType = new DateFieldType(); + dateFieldType.setName(FIELDNAME); + dateFieldType.setDateTimeFormatter(formatter); + final Query queryOnDateField = dateFieldType.rangeQuery(from, to, true, true, relation, null, null, context); + assertEquals("field:[1465975790000 TO 1466062190999]", queryOnDateField.toString()); } private Query getExpectedRangeQuery(ShapeRelation relation, Object from, Object to, boolean includeLower, boolean includeUpper) { From 81586b6bde2b8af1b6e76a524c7b11056c9d06fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Tue, 17 Dec 2019 12:44:39 +0100 Subject: [PATCH 03/11] Add date vs. date_range field duelling test --- .../index/mapper/RangeFieldTypeTests.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java index dd59c1e9b401a..9de68cebf00f4 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java @@ -269,6 +269,52 @@ public void testDateRangeQueryUsingMappingFormat() { assertEquals("field:[1465975790000 TO 1466062190999]", queryOnDateField.toString()); } + /** + * We would like to ensure lower and upper bounds are consistent between queries on a `date` and a`date_range` + * field, so we randomize a few cases and compare the generated queries here + */ + public void testDateVsDateRangeBounds() { + QueryShardContext context = createContext(); + RangeFieldType fieldType = new RangeFieldType(RangeType.DATE); + fieldType.setName(FIELDNAME); + fieldType.setIndexOptions(IndexOptions.DOCS); + fieldType.setHasDocValues(false); + // don't use DISJOINT here because it doesn't work on date fields which we want to compare bounds with + ShapeRelation relation = randomValueOtherThan(ShapeRelation.DISJOINT, () -> randomFrom(ShapeRelation.values())); + + // date formatter that truncates seconds, so we get some rounding behavior + final DateFormatter formatter = DateFormatter.forPattern("yyyy-dd-MM'T'HH:mm"); + long lower = randomLongBetween(formatter.parseMillis("2000-01-01T00:00"), formatter.parseMillis("2020-01-01T00:00")); + long upper = randomLongBetween(lower + 1000, formatter.parseMillis("2020-01-01T00:00")); + + fieldType.setDateTimeFormatter(formatter); + String lowerAsString = formatter.formatMillis(lower); + String upperAsString = formatter.formatMillis(upper); + // also add date math rounding to days occasionally + if (randomBoolean()) { + lowerAsString = lowerAsString + "||/d"; + upperAsString = upperAsString + "||/d"; + } + boolean includeLower = randomBoolean(); + boolean includeUpper = randomBoolean(); + final Query query = fieldType.rangeQuery(lowerAsString, upperAsString, includeLower, includeUpper, relation, null, + null, context); + // The range is very encapsulated and hard to inspect. We use comparison on the "toString" output with some conversion. + // The query-as-string on the date range field looks like "field:" while + // the query on the date field is formatted like "field:[1465975790000 TO 1466062190999]" + String rangeFieldQueryString = query.toString(); + String expectedDateFieldString = rangeFieldQueryString.replace("field:", "").replace(" : ", + " TO "); + + // compare lower and upper bounds with what we would get on a `date` field + DateFieldType dateFieldType = new DateFieldType(); + dateFieldType.setName(FIELDNAME); + dateFieldType.setDateTimeFormatter(formatter); + final Query queryOnDateField = dateFieldType.rangeQuery(lowerAsString, upperAsString, includeLower, includeUpper, + relation, null, null, context); + assertEquals(expectedDateFieldString, queryOnDateField.toString()); + } + private Query getExpectedRangeQuery(ShapeRelation relation, Object from, Object to, boolean includeLower, boolean includeUpper) { switch (type) { case DATE: From 54ecc49c87534c752a1d837e8729aa97ff9745ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Tue, 17 Dec 2019 15:34:09 +0100 Subject: [PATCH 04/11] Add migration note --- docs/reference/migration/migrate_8_0/search.asciidoc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/reference/migration/migrate_8_0/search.asciidoc b/docs/reference/migration/migrate_8_0/search.asciidoc index c752b1ab8b393..d0ea64d000b3c 100644 --- a/docs/reference/migration/migrate_8_0/search.asciidoc +++ b/docs/reference/migration/migrate_8_0/search.asciidoc @@ -50,4 +50,12 @@ The vector functions of the form `function(query, doc['field'])` were deprecated in 7.6, and are now removed in 8.x. The form `function(query, 'field')` should be used instead. For example, `cosineSimilarity(query, doc['field'])` is replaced by -`cosineSimilarity(query, 'field')`. \ No newline at end of file +`cosineSimilarity(query, 'field')`. + +[float] +==== Consistent rounding of range queries on dates +`range` queries on `date` and `date_range` field behaved differently for some boundaries when using +date math or dates that didn't specify up to the last millisecond. While queries on `date` field rounded +up to the latest millisecond on `gt` and `lte` boundary definitions, the same queries on `date_range` +fields didn't do this. Starting with 8.0 the behavior is like documented in <> +for both cases. From 3cb66500e2511652c035b17ea1aecbc9aa43b872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 27 Jan 2020 16:45:32 +0100 Subject: [PATCH 05/11] Add test to check query string query bounds equality on date_range and date field --- .../RangeFieldQueryStringQueryBuilderTests.java | 13 +++++++++++++ .../index/mapper/RangeFieldTypeTests.java | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java index 6cd5847d98c90..3a2069a284fa7 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java @@ -111,6 +111,19 @@ public void testDateRangeQuery() throws Exception { parser.parse("2010-01-01", () -> 0).toEpochMilli(), parser.parse("2018-01-02", () -> 0).toEpochMilli(), true, false); assertEquals(new IndexOrDocValuesQuery(range, dv), query); + + // also make sure the produced bounds are the same as on a regular `date` field + DateFieldMapper.DateFieldType dateType = (DateFieldMapper.DateFieldType) context.fieldMapper(DATE_FIELD_NAME); + parser = dateType.dateMathParser; + Query queryOnDate = new QueryStringQueryBuilder(DATE_FIELD_NAME + ":[2010-01-01 TO 2018-01-01]").toQuery(createShardContext()); + + // The range is very encapsulated and hard to inspect. We use comparison on the "toString" output with some conversion. + // The query-as-string on the date range field looks like "mapped_date_range:" while + // the query on the date field is formatted like "mapped_date:[1465975790000 TO 1466062190999]" + String rangeFieldQueryString = query.toString(); + String expectedDateFieldString = rangeFieldQueryString.replace("mapped_date_range:", "") + .replace(" : ", " TO "); + assertEquals(expectedDateFieldString, queryOnDate.toString()); } public void testIPRangeQuery() throws Exception { diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java index 9de68cebf00f4..34376ea5b5cdf 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java @@ -19,6 +19,8 @@ package org.elasticsearch.index.mapper; +import com.carrotsearch.randomizedtesting.annotations.Repeat; + import org.apache.lucene.document.DoubleRange; import org.apache.lucene.document.FloatRange; import org.apache.lucene.document.InetAddressPoint; @@ -273,6 +275,7 @@ public void testDateRangeQueryUsingMappingFormat() { * We would like to ensure lower and upper bounds are consistent between queries on a `date` and a`date_range` * field, so we randomize a few cases and compare the generated queries here */ + @Repeat(iterations = 100) public void testDateVsDateRangeBounds() { QueryShardContext context = createContext(); RangeFieldType fieldType = new RangeFieldType(RangeType.DATE); @@ -293,6 +296,8 @@ public void testDateVsDateRangeBounds() { // also add date math rounding to days occasionally if (randomBoolean()) { lowerAsString = lowerAsString + "||/d"; + } + if (randomBoolean()) { upperAsString = upperAsString + "||/d"; } boolean includeLower = randomBoolean(); From 707cd33174cafeb949ef4daf18390a2ffd09e8e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 27 Jan 2020 16:55:23 +0100 Subject: [PATCH 06/11] Removing leftover repeats --- .../org/elasticsearch/index/mapper/RangeFieldTypeTests.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java index 34376ea5b5cdf..80bb732c37de1 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java @@ -19,8 +19,6 @@ package org.elasticsearch.index.mapper; -import com.carrotsearch.randomizedtesting.annotations.Repeat; - import org.apache.lucene.document.DoubleRange; import org.apache.lucene.document.FloatRange; import org.apache.lucene.document.InetAddressPoint; @@ -275,7 +273,6 @@ public void testDateRangeQueryUsingMappingFormat() { * We would like to ensure lower and upper bounds are consistent between queries on a `date` and a`date_range` * field, so we randomize a few cases and compare the generated queries here */ - @Repeat(iterations = 100) public void testDateVsDateRangeBounds() { QueryShardContext context = createContext(); RangeFieldType fieldType = new RangeFieldType(RangeType.DATE); From 0b17e045149b5e13beac5d48905a7343e1b7f885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 27 Jan 2020 20:37:24 +0100 Subject: [PATCH 07/11] Change migrate doc --- docs/reference/migration/migrate_8_0/search.asciidoc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/reference/migration/migrate_8_0/search.asciidoc b/docs/reference/migration/migrate_8_0/search.asciidoc index d0ea64d000b3c..aee6e4bbb78c6 100644 --- a/docs/reference/migration/migrate_8_0/search.asciidoc +++ b/docs/reference/migration/migrate_8_0/search.asciidoc @@ -53,9 +53,9 @@ deprecated in 7.6, and are now removed in 8.x. The form `cosineSimilarity(query, 'field')`. [float] -==== Consistent rounding of range queries on dates -`range` queries on `date` and `date_range` field behaved differently for some boundaries when using -date math or dates that didn't specify up to the last millisecond. While queries on `date` field rounded -up to the latest millisecond on `gt` and `lte` boundary definitions, the same queries on `date_range` -fields didn't do this. Starting with 8.0 the behavior is like documented in <> -for both cases. +==== Consistent rounding of range queries on `date_range` fields +`range` queries on `date_range` field currently can have slightly differently boundaries than their equivalent +query on a pure `date` field. This can e.g. happen when using date math or dates that don't specify up to the +last millisecond. While queries on `date` field round up to the latest millisecond for `gt` and `lte` boundaries, +the same queries on `date_range` fields didn't do this. The behavior is now the same for both field types like +documented in <>. From ac64badda1cacb5753541a12632c6bfec2a3a0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 27 Jan 2020 22:04:21 +0100 Subject: [PATCH 08/11] Rework tests so they don't rely on string comparison --- .../index/mapper/DateFieldMapper.java | 13 ++++---- .../query/DistanceFeatureQueryBuilder.java | 13 ++++---- .../functionscore/DecayFunctionBuilder.java | 2 +- ...angeFieldQueryStringQueryBuilderTests.java | 31 +++++++++-------- .../index/mapper/RangeFieldTypeTests.java | 33 +++++++++---------- .../DistanceFeatureQueryBuilderTests.java | 7 ++-- .../index/query/RangeQueryBuilderTests.java | 4 +-- 7 files changed, 53 insertions(+), 50 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java index 43762645190e0..b6881390dafe2 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java @@ -63,6 +63,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.function.LongSupplier; import static org.elasticsearch.common.time.DateUtils.toLong; @@ -371,7 +372,7 @@ public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower if (lowerTerm == null) { l = Long.MIN_VALUE; } else { - l = parseToLong(lowerTerm, !includeLower, timeZone, parser, context); + l = parseToLong(lowerTerm, !includeLower, timeZone, parser, context::nowInMillis); if (includeLower == false) { ++l; } @@ -379,7 +380,7 @@ public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower if (upperTerm == null) { u = Long.MAX_VALUE; } else { - u = parseToLong(upperTerm, includeUpper, timeZone, parser, context); + u = parseToLong(upperTerm, includeUpper, timeZone, parser, context::nowInMillis); if (includeUpper == false) { --u; } @@ -393,7 +394,7 @@ public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower } public long parseToLong(Object value, boolean roundUp, - @Nullable ZoneId zone, @Nullable DateMathParser forcedDateParser, QueryRewriteContext context) { + @Nullable ZoneId zone, @Nullable DateMathParser forcedDateParser, LongSupplier now) { DateMathParser dateParser = dateMathParser(); if (forcedDateParser != null) { dateParser = forcedDateParser; @@ -405,7 +406,7 @@ public long parseToLong(Object value, boolean roundUp, } else { strValue = value.toString(); } - Instant instant = dateParser.parse(strValue, context::nowInMillis, roundUp, zone); + Instant instant = dateParser.parse(strValue, now, roundUp, zone); return resolution.convert(instant); } @@ -419,7 +420,7 @@ public Relation isFieldWithinQuery(IndexReader reader, long fromInclusive = Long.MIN_VALUE; if (from != null) { - fromInclusive = parseToLong(from, !includeLower, timeZone, dateParser, context); + fromInclusive = parseToLong(from, !includeLower, timeZone, dateParser, context::nowInMillis); if (includeLower == false) { if (fromInclusive == Long.MAX_VALUE) { return Relation.DISJOINT; @@ -430,7 +431,7 @@ public Relation isFieldWithinQuery(IndexReader reader, long toInclusive = Long.MAX_VALUE; if (to != null) { - toInclusive = parseToLong(to, includeUpper, timeZone, dateParser, context); + toInclusive = parseToLong(to, includeUpper, timeZone, dateParser, context::nowInMillis); if (includeUpper == false) { if (toInclusive == Long.MIN_VALUE) { return Relation.DISJOINT; diff --git a/server/src/main/java/org/elasticsearch/index/query/DistanceFeatureQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/DistanceFeatureQueryBuilder.java index bdee4342923ba..ec7debe5b9348 100644 --- a/server/src/main/java/org/elasticsearch/index/query/DistanceFeatureQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/DistanceFeatureQueryBuilder.java @@ -30,16 +30,15 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.unit.DistanceUnit; +import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.unit.TimeValue; - import org.elasticsearch.index.mapper.DateFieldMapper; -import org.elasticsearch.index.mapper.MappedFieldType; -import org.elasticsearch.index.mapper.GeoPointFieldMapper.GeoPointFieldType; import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType; +import org.elasticsearch.index.mapper.GeoPointFieldMapper.GeoPointFieldType; +import org.elasticsearch.index.mapper.MappedFieldType; import java.io.IOException; import java.util.Objects; @@ -122,7 +121,7 @@ protected Query doToQuery(QueryShardContext context) throws IOException { } Object originObj = origin.origin(); if (fieldType instanceof DateFieldType) { - long originLong = ((DateFieldType) fieldType).parseToLong(originObj, true, null, null, context); + long originLong = ((DateFieldType) fieldType).parseToLong(originObj, true, null, null, context::nowInMillis); TimeValue pivotVal = TimeValue.parseTimeValue(pivot, DistanceFeatureQueryBuilder.class.getSimpleName() + ".pivot"); if (((DateFieldType) fieldType).resolution() == DateFieldMapper.Resolution.MILLISECONDS) { return LongPoint.newDistanceFeatureQuery(field, boost, originLong, pivotVal.getMillis()); @@ -213,7 +212,9 @@ Object origin() { @Override public final boolean equals(Object other) { - if ((other instanceof Origin) == false) return false; + if ((other instanceof Origin) == false) { + return false; + } Object otherOrigin = ((Origin) other).origin(); return this.origin().equals(otherOrigin); } diff --git a/server/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionBuilder.java b/server/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionBuilder.java index e31e646200a69..0b4177490b17b 100644 --- a/server/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionBuilder.java @@ -318,7 +318,7 @@ private AbstractDistanceScoreFunction parseDateVariable(XContentParser parser, Q if (originString == null) { origin = context.nowInMillis(); } else { - origin = ((DateFieldMapper.DateFieldType) dateFieldType).parseToLong(originString, false, null, null, context); + origin = ((DateFieldMapper.DateFieldType) dateFieldType).parseToLong(originString, false, null, null, context::nowInMillis); } if (scaleString == null) { diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java index 3a2069a284fa7..4733376c30da8 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldQueryStringQueryBuilderTests.java @@ -23,7 +23,9 @@ import org.apache.lucene.document.FloatRange; import org.apache.lucene.document.InetAddressRange; import org.apache.lucene.document.IntRange; +import org.apache.lucene.document.LongPoint; import org.apache.lucene.document.LongRange; +import org.apache.lucene.document.SortedNumericDocValuesField; import org.apache.lucene.queries.BinaryDocValuesRangeQuery; import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.PointRangeQuery; @@ -39,7 +41,6 @@ import java.io.IOException; import java.net.InetAddress; -import java.time.ZoneId; import static org.hamcrest.Matchers.either; import static org.hamcrest.core.IsInstanceOf.instanceOf; @@ -103,27 +104,29 @@ public void testDateRangeQuery() throws Exception { RangeFieldMapper.RangeFieldType type = (RangeFieldMapper.RangeFieldType) context.fieldMapper(DATE_RANGE_FIELD_NAME); DateMathParser parser = type.dateMathParser; Query query = new QueryStringQueryBuilder(DATE_RANGE_FIELD_NAME + ":[2010-01-01 TO 2018-01-01]").toQuery(createShardContext()); + String lowerBoundExact = "2010-01-01T00:00:00.000"; + String upperBoundExact = "2018-01-01T23:59:59.999"; Query range = LongRange.newIntersectsQuery(DATE_RANGE_FIELD_NAME, - new long[]{ parser.parse("2010-01-01", () -> 0).toEpochMilli()}, - new long[]{ parser.parse("2018-01-01", () -> 0, true, (ZoneId) null).toEpochMilli()}); + new long[]{ parser.parse(lowerBoundExact, () -> 0).toEpochMilli()}, + new long[]{ parser.parse(upperBoundExact, () -> 0).toEpochMilli()}); Query dv = RangeType.DATE.dvRangeQuery(DATE_RANGE_FIELD_NAME, BinaryDocValuesRangeQuery.QueryType.INTERSECTS, - parser.parse("2010-01-01", () -> 0).toEpochMilli(), - parser.parse("2018-01-02", () -> 0).toEpochMilli(), true, false); + parser.parse(lowerBoundExact, () -> 0).toEpochMilli(), + parser.parse(upperBoundExact, () -> 0).toEpochMilli(), true, true); assertEquals(new IndexOrDocValuesQuery(range, dv), query); // also make sure the produced bounds are the same as on a regular `date` field DateFieldMapper.DateFieldType dateType = (DateFieldMapper.DateFieldType) context.fieldMapper(DATE_FIELD_NAME); parser = dateType.dateMathParser; - Query queryOnDate = new QueryStringQueryBuilder(DATE_FIELD_NAME + ":[2010-01-01 TO 2018-01-01]").toQuery(createShardContext()); - - // The range is very encapsulated and hard to inspect. We use comparison on the "toString" output with some conversion. - // The query-as-string on the date range field looks like "mapped_date_range:" while - // the query on the date field is formatted like "mapped_date:[1465975790000 TO 1466062190999]" - String rangeFieldQueryString = query.toString(); - String expectedDateFieldString = rangeFieldQueryString.replace("mapped_date_range:", "") - .replace(" : ", " TO "); - assertEquals(expectedDateFieldString, queryOnDate.toString()); + Query queryOnDateField = new QueryStringQueryBuilder(DATE_FIELD_NAME + ":[2010-01-01 TO 2018-01-01]").toQuery(createShardContext()); + Query controlQuery = LongPoint.newRangeQuery(DATE_FIELD_NAME, + new long[]{ parser.parse(lowerBoundExact, () -> 0).toEpochMilli()}, + new long[]{ parser.parse(upperBoundExact, () -> 0).toEpochMilli()}); + + Query controlDv = SortedNumericDocValuesField.newSlowRangeQuery(DATE_FIELD_NAME, + parser.parse(lowerBoundExact, () -> 0).toEpochMilli(), + parser.parse(upperBoundExact, () -> 0).toEpochMilli()); + assertEquals(new IndexOrDocValuesQuery(controlQuery, controlDv), queryOnDateField); } public void testIPRangeQuery() throws Exception { diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java index 80bb732c37de1..893a909ece2c8 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RangeFieldTypeTests.java @@ -279,13 +279,11 @@ public void testDateVsDateRangeBounds() { fieldType.setName(FIELDNAME); fieldType.setIndexOptions(IndexOptions.DOCS); fieldType.setHasDocValues(false); - // don't use DISJOINT here because it doesn't work on date fields which we want to compare bounds with - ShapeRelation relation = randomValueOtherThan(ShapeRelation.DISJOINT, () -> randomFrom(ShapeRelation.values())); // date formatter that truncates seconds, so we get some rounding behavior final DateFormatter formatter = DateFormatter.forPattern("yyyy-dd-MM'T'HH:mm"); - long lower = randomLongBetween(formatter.parseMillis("2000-01-01T00:00"), formatter.parseMillis("2020-01-01T00:00")); - long upper = randomLongBetween(lower + 1000, formatter.parseMillis("2020-01-01T00:00")); + long lower = randomLongBetween(formatter.parseMillis("2000-01-01T00:00"), formatter.parseMillis("2010-01-01T00:00")); + long upper = randomLongBetween(formatter.parseMillis("2011-01-01T00:00"), formatter.parseMillis("2020-01-01T00:00")); fieldType.setDateTimeFormatter(formatter); String lowerAsString = formatter.formatMillis(lower); @@ -299,22 +297,23 @@ public void testDateVsDateRangeBounds() { } boolean includeLower = randomBoolean(); boolean includeUpper = randomBoolean(); - final Query query = fieldType.rangeQuery(lowerAsString, upperAsString, includeLower, includeUpper, relation, null, + final Query query = fieldType.rangeQuery(lowerAsString, upperAsString, includeLower, includeUpper, ShapeRelation.INTERSECTS, null, null, context); - // The range is very encapsulated and hard to inspect. We use comparison on the "toString" output with some conversion. - // The query-as-string on the date range field looks like "field:" while - // the query on the date field is formatted like "field:[1465975790000 TO 1466062190999]" - String rangeFieldQueryString = query.toString(); - String expectedDateFieldString = rangeFieldQueryString.replace("field:", "").replace(" : ", - " TO "); - // compare lower and upper bounds with what we would get on a `date` field + // get exact lower and upper bounds similar to what we would parse for `date` fields for same input strings DateFieldType dateFieldType = new DateFieldType(); - dateFieldType.setName(FIELDNAME); - dateFieldType.setDateTimeFormatter(formatter); - final Query queryOnDateField = dateFieldType.rangeQuery(lowerAsString, upperAsString, includeLower, includeUpper, - relation, null, null, context); - assertEquals(expectedDateFieldString, queryOnDateField.toString()); + long lowerBoundLong = dateFieldType.parseToLong(lowerAsString, !includeLower, null, formatter.toDateMathParser(), () -> 0); + if (includeLower == false) { + ++lowerBoundLong; + } + long upperBoundLong = dateFieldType.parseToLong(upperAsString, includeUpper, null, formatter.toDateMathParser(), () -> 0); + if (includeUpper == false) { + --upperBoundLong; + } + + // check that using this bounds we get similar query when constructing equivalent query on date_range field + Query range = LongRange.newIntersectsQuery(FIELDNAME, new long[] { lowerBoundLong }, new long[] { upperBoundLong }); + assertEquals(range, query); } private Query getExpectedRangeQuery(ShapeRelation relation, Object from, Object to, boolean includeLower, boolean includeUpper) { diff --git a/server/src/test/java/org/elasticsearch/index/query/DistanceFeatureQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/DistanceFeatureQueryBuilderTests.java index c1622057b6ba8..1bf9188b8577c 100644 --- a/server/src/test/java/org/elasticsearch/index/query/DistanceFeatureQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/DistanceFeatureQueryBuilderTests.java @@ -28,12 +28,11 @@ import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.index.mapper.DateFieldMapper; +import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType; import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.index.query.DistanceFeatureQueryBuilder.Origin; import org.elasticsearch.test.AbstractQueryTestCase; import org.joda.time.DateTime; -import org.elasticsearch.index.query.DistanceFeatureQueryBuilder.Origin; -import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType; - import java.io.IOException; import java.time.Instant; @@ -88,7 +87,7 @@ protected void doAssertLuceneQuery(DistanceFeatureQueryBuilder queryBuilder, } else { // if (fieldName.equals(DATE_FIELD_NAME)) MapperService mapperService = context.getMapperService(); DateFieldType fieldType = (DateFieldType) mapperService.fullName(fieldName); - long originLong = fieldType.parseToLong(origin, true, null, null, context); + long originLong = fieldType.parseToLong(origin, true, null, null, context::nowInMillis); TimeValue pivotVal = TimeValue.parseTimeValue(pivot, DistanceFeatureQueryBuilder.class.getSimpleName() + ".pivot"); long pivotLong; if (fieldType.resolution() == DateFieldMapper.Resolution.MILLISECONDS) { diff --git a/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java index a331d762cc37f..b94963165b45c 100644 --- a/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java @@ -170,12 +170,12 @@ protected void doAssertLuceneQuery(RangeQueryBuilder queryBuilder, Query query, ((DateFieldMapper.DateFieldType) mappedFieldType).parseToLong(queryBuilder.from(), queryBuilder.includeLower(), queryBuilder.getDateTimeZone(), - queryBuilder.getForceDateParser(), context); + queryBuilder.getForceDateParser(), context::nowInMillis); toInMillis = queryBuilder.to() == null ? null : ((DateFieldMapper.DateFieldType) mappedFieldType).parseToLong(queryBuilder.to(), queryBuilder.includeUpper(), queryBuilder.getDateTimeZone(), - queryBuilder.getForceDateParser(), context); + queryBuilder.getForceDateParser(), context::nowInMillis); } else { fromInMillis = toInMillis = null; fail("unexpected mapped field type: [" + mappedFieldType.getClass() + "] " + mappedFieldType.toString()); From 11f23e73bd9186be44b4f4a20ea4a84defd5cb90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Fri, 31 Jan 2020 11:27:14 +0100 Subject: [PATCH 09/11] Removing note to put it back when backporting to 7.x --- .../migration/migrate_8_0/search.asciidoc | 61 ------------------- 1 file changed, 61 deletions(-) delete mode 100644 docs/reference/migration/migrate_8_0/search.asciidoc diff --git a/docs/reference/migration/migrate_8_0/search.asciidoc b/docs/reference/migration/migrate_8_0/search.asciidoc deleted file mode 100644 index aee6e4bbb78c6..0000000000000 --- a/docs/reference/migration/migrate_8_0/search.asciidoc +++ /dev/null @@ -1,61 +0,0 @@ -[float] -[[breaking_80_search_changes]] -=== Search Changes - -[float] -==== Removal of types - -The `/{index}/{type}/_search`, `/{index}/{type}/_msearch`, `/{index}/{type}/_search/template` and `/{index}/{type}/_msearch/template` REST endpoints have been removed in favour of `/{index}/_search`, `/{index}/_msearch`, `/{index}/_search/template` and `/{index}/_msearch/template`; since indexes no longer contain types, these typed endpoints are obsolete.. - -The `/{index}/{type}/_termvectors`, `/{index}/{type}/{id}/_termvectors` and `/{index}/{type}/_mtermvectors` REST endpoints have been removed in favour of `/{index}/_termvectors`, `/{index}/{id}/_termvectors` and `/{index}/_mtermvectors`; since indexes no longer contain types, these typed endpoints are obsolete.. - -The `/{index}/{type}/{doc}` and `/{index}/{type}/_mget` REST endpoints have been removed in favour of `/{index}/_doc/{doc}` and `/{index}/_mget`; since indexes no longer contain types, these typed endpoints are obsolete. - -[float] -==== Removal of queries - -The `common` query, deprecated in 7.x, has been removed in 8.0. -The same functionality can be achieved by the `match` query if the total number of hits is not tracked. - -[float] -===== Removal of query parameters - -The `cutoff_frequency` parameter, deprecated in 7.x, has been removed in 8.0 from `match` and `multi_match` queries. -The same functionality can be achieved without any configuration provided that the total number of hits is not tracked. - -[float] -===== Removal of sort parameters - -The `nested_filter` and `nested_path` options, deprecated in 6.x, have been removed in favor of the `nested` context. - - -[float] -===== Shard allocation awareness in Search and Get requests - -{es} will no longer prefer using shards in the same location (with the same awareness attribute values) to process -`_search` and `_get` requests. Adaptive replica selection (activated by default in this version) will route requests -more efficiently using the service time of prior inter-node communications. - -[float] -==== Removal of sparse vector fields -The `sparse_vector` field type was deprecated in 7.6 and is now removed in -8.0. We have not seen much interest in this experimental field type, and don't -see a clear use case as it's currently designed. If you have feedback or -suggestions around sparse vector functionality, please let us know through -GitHub or the 'discuss' forums. - -[float] -==== Update to vector function signatures -The vector functions of the form `function(query, doc['field'])` were -deprecated in 7.6, and are now removed in 8.x. The form -`function(query, 'field')` should be used instead. For example, -`cosineSimilarity(query, doc['field'])` is replaced by -`cosineSimilarity(query, 'field')`. - -[float] -==== Consistent rounding of range queries on `date_range` fields -`range` queries on `date_range` field currently can have slightly differently boundaries than their equivalent -query on a pure `date` field. This can e.g. happen when using date math or dates that don't specify up to the -last millisecond. While queries on `date` field round up to the latest millisecond for `gt` and `lte` boundaries, -the same queries on `date_range` fields didn't do this. The behavior is now the same for both field types like -documented in <>. From afaeb1aa786d2c456bbd7cb5c5487548b8f0cd76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Fri, 31 Jan 2020 12:15:15 +0100 Subject: [PATCH 10/11] Revert "Removing note to put it back when backporting to 7.x" This reverts commit 11f23e73bd9186be44b4f4a20ea4a84defd5cb90. --- .../migration/migrate_8_0/search.asciidoc | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 docs/reference/migration/migrate_8_0/search.asciidoc diff --git a/docs/reference/migration/migrate_8_0/search.asciidoc b/docs/reference/migration/migrate_8_0/search.asciidoc new file mode 100644 index 0000000000000..aee6e4bbb78c6 --- /dev/null +++ b/docs/reference/migration/migrate_8_0/search.asciidoc @@ -0,0 +1,61 @@ +[float] +[[breaking_80_search_changes]] +=== Search Changes + +[float] +==== Removal of types + +The `/{index}/{type}/_search`, `/{index}/{type}/_msearch`, `/{index}/{type}/_search/template` and `/{index}/{type}/_msearch/template` REST endpoints have been removed in favour of `/{index}/_search`, `/{index}/_msearch`, `/{index}/_search/template` and `/{index}/_msearch/template`; since indexes no longer contain types, these typed endpoints are obsolete.. + +The `/{index}/{type}/_termvectors`, `/{index}/{type}/{id}/_termvectors` and `/{index}/{type}/_mtermvectors` REST endpoints have been removed in favour of `/{index}/_termvectors`, `/{index}/{id}/_termvectors` and `/{index}/_mtermvectors`; since indexes no longer contain types, these typed endpoints are obsolete.. + +The `/{index}/{type}/{doc}` and `/{index}/{type}/_mget` REST endpoints have been removed in favour of `/{index}/_doc/{doc}` and `/{index}/_mget`; since indexes no longer contain types, these typed endpoints are obsolete. + +[float] +==== Removal of queries + +The `common` query, deprecated in 7.x, has been removed in 8.0. +The same functionality can be achieved by the `match` query if the total number of hits is not tracked. + +[float] +===== Removal of query parameters + +The `cutoff_frequency` parameter, deprecated in 7.x, has been removed in 8.0 from `match` and `multi_match` queries. +The same functionality can be achieved without any configuration provided that the total number of hits is not tracked. + +[float] +===== Removal of sort parameters + +The `nested_filter` and `nested_path` options, deprecated in 6.x, have been removed in favor of the `nested` context. + + +[float] +===== Shard allocation awareness in Search and Get requests + +{es} will no longer prefer using shards in the same location (with the same awareness attribute values) to process +`_search` and `_get` requests. Adaptive replica selection (activated by default in this version) will route requests +more efficiently using the service time of prior inter-node communications. + +[float] +==== Removal of sparse vector fields +The `sparse_vector` field type was deprecated in 7.6 and is now removed in +8.0. We have not seen much interest in this experimental field type, and don't +see a clear use case as it's currently designed. If you have feedback or +suggestions around sparse vector functionality, please let us know through +GitHub or the 'discuss' forums. + +[float] +==== Update to vector function signatures +The vector functions of the form `function(query, doc['field'])` were +deprecated in 7.6, and are now removed in 8.x. The form +`function(query, 'field')` should be used instead. For example, +`cosineSimilarity(query, doc['field'])` is replaced by +`cosineSimilarity(query, 'field')`. + +[float] +==== Consistent rounding of range queries on `date_range` fields +`range` queries on `date_range` field currently can have slightly differently boundaries than their equivalent +query on a pure `date` field. This can e.g. happen when using date math or dates that don't specify up to the +last millisecond. While queries on `date` field round up to the latest millisecond for `gt` and `lte` boundaries, +the same queries on `date_range` fields didn't do this. The behavior is now the same for both field types like +documented in <>. From 89a9b38ee10fbb28b1b06a6a8eb1ac1796171bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Fri, 31 Jan 2020 12:15:36 +0100 Subject: [PATCH 11/11] Removing note to put it back when backporting to 7.x --- docs/reference/migration/migrate_8_0/search.asciidoc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/reference/migration/migrate_8_0/search.asciidoc b/docs/reference/migration/migrate_8_0/search.asciidoc index aee6e4bbb78c6..eb97f0ec7144a 100644 --- a/docs/reference/migration/migrate_8_0/search.asciidoc +++ b/docs/reference/migration/migrate_8_0/search.asciidoc @@ -52,10 +52,3 @@ deprecated in 7.6, and are now removed in 8.x. The form `cosineSimilarity(query, doc['field'])` is replaced by `cosineSimilarity(query, 'field')`. -[float] -==== Consistent rounding of range queries on `date_range` fields -`range` queries on `date_range` field currently can have slightly differently boundaries than their equivalent -query on a pure `date` field. This can e.g. happen when using date math or dates that don't specify up to the -last millisecond. While queries on `date` field round up to the latest millisecond for `gt` and `lte` boundaries, -the same queries on `date_range` fields didn't do this. The behavior is now the same for both field types like -documented in <>.