From 37287284e64a0e91ab400a16b187e719b55c8929 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Wed, 10 Dec 2014 16:28:19 -0800 Subject: [PATCH] Settings: Remove `mapping.date.round_ceil` setting for date math parsing The setting `mapping.date.round_ceil` (and the undocumented setting `index.mapping.date.parse_upper_inclusive`) affect how date ranges using `lte` are parsed. In #8556 the semantics of date rounding were solidified, eliminating the need to have different parsing functions whether the date is inclusive or exclusive. This change removes these legacy settings and improves the tests for the date math parser (now at 100% coverage!). It also removes the unnecessary function `DateMathParser.parseTimeZone` for which the existing `DateTimeZone.forID` handles all use cases. Any user previously using these settings can refer to the changed semantics and change their query accordingly. This is a breaking change because even dates without datemath previously used the different parsing functions depending on context. closes #8598 closes #8889 --- docs/reference/mapping/date-format.asciidoc | 16 ++- .../common/joda/DateMathParser.java | 121 +++++------------- .../index/mapper/core/DateFieldMapper.java | 26 +--- .../mapper/internal/TimestampFieldMapper.java | 15 +-- .../index/query/QueryStringQueryParser.java | 4 +- .../index/query/RangeFilterParser.java | 2 +- .../index/query/RangeQueryParser.java | 2 +- .../bucket/histogram/DateHistogramParser.java | 6 +- .../common/joda/DateMathParserTests.java | 87 ++++++++++--- .../count/simple/SimpleCountTests.java | 25 +--- .../exists/SimpleExistsTests.java | 20 +-- .../mapper/date/SimpleDateMappingTests.java | 4 +- .../query/date_range_filter_timezone.json | 2 +- ...e_range_filter_timezone_numeric_field.json | 2 +- .../query/date_range_query_timezone.json | 2 +- ...te_range_query_timezone_numeric_field.json | 2 +- .../bucket/DateHistogramTests.java | 4 +- .../search/query/SimpleQueryTests.java | 28 ++-- .../search/simple/SimpleSearchTests.java | 52 +++----- 19 files changed, 171 insertions(+), 249 deletions(-) diff --git a/docs/reference/mapping/date-format.asciidoc b/docs/reference/mapping/date-format.asciidoc index 77df3d429dda2..a548d282ee9c6 100644 --- a/docs/reference/mapping/date-format.asciidoc +++ b/docs/reference/mapping/date-format.asciidoc @@ -35,13 +35,15 @@ then follow by a math expression, supporting `+`, `-` and `/` Here are some samples: `now+1h`, `now+1h+1m`, `now+1h/d`, `2012-01-01||+1M/d`. -Note, when doing `range` type searches, and the upper value is -inclusive, the rounding will properly be rounded to the ceiling instead -of flooring it. - -To change this behavior, set -`"mapping.date.round_ceil": false`. - +When doing `range` type searches with rounding, the value parsed +depends on whether the end of the range is inclusive or exclusive, and +whether the beginning or end of the range. Rounding up moves to the +last millisecond of the rounding scope, and rounding down to the +first millisecond of the rounding scope. The semantics work as follows: +* `gt` - round up, and use > that value (`2014-11-18||/M` becomes `2014-11-30T23:59:59.999`, ie excluding the entire month) +* `gte` - round D down, and use >= that value (`2014-11-18||/M` becomes `2014-11-01`, ie including the entire month) +* `lt` - round D down, and use < that value (`2014-11-18||/M` becomes `2014-11-01`, ie excluding the entire month) +* `lte` - round D up, and use <= that value(`2014-11-18||/M` becomes `2014-11-30T23:59:59.999`, ie including the entire month) [float] [[built-in]] diff --git a/src/main/java/org/elasticsearch/common/joda/DateMathParser.java b/src/main/java/org/elasticsearch/common/joda/DateMathParser.java index a0ec73ce0c35b..06aedf58c05cf 100644 --- a/src/main/java/org/elasticsearch/common/joda/DateMathParser.java +++ b/src/main/java/org/elasticsearch/common/joda/DateMathParser.java @@ -19,23 +19,29 @@ package org.elasticsearch.common.joda; +import org.apache.commons.lang3.StringUtils; import org.elasticsearch.ElasticsearchParseException; import org.joda.time.DateTimeZone; import org.joda.time.MutableDateTime; import org.joda.time.format.DateTimeFormatter; -import java.io.IOException; import java.util.concurrent.TimeUnit; /** + * A parser for date/time formatted text with optional date math. + * + * The format of the datetime is configurable, and unix timestamps can also be used. Datemath + * is appended to a datetime with the following syntax: + * ||[+-/](\d+)?[yMwdhHms]. */ public class DateMathParser { private final FormatDateTimeFormatter dateTimeFormatter; - private final TimeUnit timeUnit; public DateMathParser(FormatDateTimeFormatter dateTimeFormatter, TimeUnit timeUnit) { + if (dateTimeFormatter == null) throw new NullPointerException(); + if (timeUnit == null) throw new NullPointerException(); this.dateTimeFormatter = dateTimeFormatter; this.timeUnit = timeUnit; } @@ -44,7 +50,7 @@ public long parse(String text, long now) { return parse(text, now, false, null); } - public long parse(String text, long now, boolean roundCeil, DateTimeZone timeZone) { + public long parse(String text, long now, boolean roundUp, DateTimeZone timeZone) { long time; String mathString; if (text.startsWith("now")) { @@ -52,26 +58,17 @@ public long parse(String text, long now, boolean roundCeil, DateTimeZone timeZon mathString = text.substring("now".length()); } else { int index = text.indexOf("||"); - String parseString; if (index == -1) { - parseString = text; - mathString = ""; // nothing else - } else { - parseString = text.substring(0, index); - mathString = text.substring(index + 2); + return parseDateTime(text, timeZone); } - if (roundCeil) { - time = parseRoundCeilStringValue(parseString, timeZone); - } else { - time = parseStringValue(parseString, timeZone); + time = parseDateTime(text.substring(0, index), timeZone); + mathString = text.substring(index + 2); + if (mathString.isEmpty()) { + return time; } } - if (mathString.isEmpty()) { - return time; - } - - return parseMath(mathString, time, roundCeil); + return parseMath(mathString, time, roundUp); } private long parseMath(String mathString, long time, boolean roundUp) throws ElasticsearchParseException { @@ -174,7 +171,9 @@ private long parseMath(String mathString, long time, boolean roundUp) throws Ela } if (propertyToRound != null) { if (roundUp) { - propertyToRound.roundCeiling(); + // we want to go up to the next whole value, even if we are already on a rounded value + propertyToRound.add(1); + propertyToRound.roundFloor(); dateTime.addMillis(-1); // subtract 1 millisecond to get the largest inclusive value } else { propertyToRound.roundFloor(); @@ -184,83 +183,27 @@ private long parseMath(String mathString, long time, boolean roundUp) throws Ela return dateTime.getMillis(); } - /** - * Get a DateTimeFormatter parser applying timezone if any. - */ - public static DateTimeFormatter getDateTimeFormatterParser(FormatDateTimeFormatter dateTimeFormatter, DateTimeZone timeZone) { - if (dateTimeFormatter == null) { - return null; + private long parseDateTime(String value, DateTimeZone timeZone) { + + // first check for timestamp + if (value.length() > 4 && StringUtils.isNumeric(value)) { + try { + long time = Long.parseLong(value); + return timeUnit.toMillis(time); + } catch (NumberFormatException e) { + throw new ElasticsearchParseException("failed to parse date field [" + value + "] as timestamp", e); + } } - + DateTimeFormatter parser = dateTimeFormatter.parser(); if (timeZone != null) { parser = parser.withZone(timeZone); } - return parser; - } - - private long parseStringValue(String value, DateTimeZone timeZone) { try { - DateTimeFormatter parser = getDateTimeFormatterParser(dateTimeFormatter, timeZone); return parser.parseMillis(value); - } catch (RuntimeException e) { - try { - // When date is given as a numeric value, it's a date in ms since epoch - // By definition, it's a UTC date. - long time = Long.parseLong(value); - return timeUnit.toMillis(time); - } catch (NumberFormatException e1) { - throw new ElasticsearchParseException("failed to parse date field [" + value + "], tried both date format [" + dateTimeFormatter.format() + "], and timestamp number", e); - } - } - } - - private long parseRoundCeilStringValue(String value, DateTimeZone timeZone) { - try { - // we create a date time for inclusive upper range, we "include" by default the day level data - // so something like 2011-01-01 will include the full first day of 2011. - // we also use 1970-01-01 as the base for it so we can handle searches like 10:12:55 (just time) - // since when we index those, the base is 1970-01-01 - MutableDateTime dateTime = new MutableDateTime(1970, 1, 1, 23, 59, 59, 999, DateTimeZone.UTC); - DateTimeFormatter parser = getDateTimeFormatterParser(dateTimeFormatter, timeZone); - int location = parser.parseInto(dateTime, value, 0); - // if we parsed all the string value, we are good - if (location == value.length()) { - return dateTime.getMillis(); - } - // if we did not manage to parse, or the year is really high year which is unreasonable - // see if its a number - if (location <= 0 || dateTime.getYear() > 5000) { - try { - long time = Long.parseLong(value); - return timeUnit.toMillis(time); - } catch (NumberFormatException e1) { - throw new ElasticsearchParseException("failed to parse date field [" + value + "], tried both date format [" + dateTimeFormatter.format() + "], and timestamp number"); - } - } - return dateTime.getMillis(); - } catch (RuntimeException e) { - try { - long time = Long.parseLong(value); - return timeUnit.toMillis(time); - } catch (NumberFormatException e1) { - throw new ElasticsearchParseException("failed to parse date field [" + value + "], tried both date format [" + dateTimeFormatter.format() + "], and timestamp number", e); - } - } - } - - public static DateTimeZone parseZone(String text) throws IOException { - int index = text.indexOf(':'); - if (index != -1) { - int beginIndex = text.charAt(0) == '+' ? 1 : 0; - // format like -02:30 - return DateTimeZone.forOffsetHoursMinutes( - Integer.parseInt(text.substring(beginIndex, index)), - Integer.parseInt(text.substring(index + 1)) - ); - } else { - // id, listed here: http://joda-time.sourceforge.net/timezones.html - return DateTimeZone.forID(text); + } catch (IllegalArgumentException e) { + + throw new ElasticsearchParseException("failed to parse date field [" + value + "] with format [" + dateTimeFormatter.format() + "]", e); } } diff --git a/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java b/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java index 335b6aa67f4e6..8f32d6b164a52 100644 --- a/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java @@ -71,9 +71,6 @@ import static org.elasticsearch.index.mapper.core.TypeParsers.parseDateTimeFormatter; import static org.elasticsearch.index.mapper.core.TypeParsers.parseNumberField; -/** - * - */ public class DateFieldMapper extends NumberFieldMapper { public static final String CONTENT_TYPE = "date"; @@ -90,7 +87,6 @@ public static class Defaults extends NumberFieldMapper.Defaults { public static final String NULL_VALUE = null; public static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS; - public static final boolean ROUND_CEIL = true; } public static class Builder extends NumberFieldMapper.Builder { @@ -127,17 +123,12 @@ public Builder dateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) { @Override public DateFieldMapper build(BuilderContext context) { - boolean roundCeil = Defaults.ROUND_CEIL; - if (context.indexSettings() != null) { - Settings settings = context.indexSettings(); - roundCeil = settings.getAsBoolean("index.mapping.date.round_ceil", settings.getAsBoolean("index.mapping.date.parse_upper_inclusive", Defaults.ROUND_CEIL)); - } fieldType.setOmitNorms(fieldType.omitNorms() && boost == 1.0f); if (!locale.equals(dateTimeFormatter.locale())) { dateTimeFormatter = new FormatDateTimeFormatter(dateTimeFormatter.format(), dateTimeFormatter.parser(), dateTimeFormatter.printer(), locale); } DateFieldMapper fieldMapper = new DateFieldMapper(buildNames(context), dateTimeFormatter, - fieldType.numericPrecisionStep(), boost, fieldType, docValues, nullValue, timeUnit, roundCeil, ignoreMalformed(context), coerce(context), + fieldType.numericPrecisionStep(), boost, fieldType, docValues, nullValue, timeUnit, ignoreMalformed(context), coerce(context), postingsProvider, docValuesProvider, similarity, normsLoading, fieldDataSettings, context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo); fieldMapper.includeInAll(includeInAll); @@ -182,15 +173,6 @@ public static class TypeParser implements Mapper.TypeParser { protected FormatDateTimeFormatter dateTimeFormatter; - // Triggers rounding up of the upper bound for range queries and filters if - // set to true. - // Rounding up a date here has the following meaning: If a date is not - // defined with full precision, for example, no milliseconds given, the date - // will be filled up to the next larger date with that precision. - // Example: An upper bound given as "2000-01-01", will be converted to - // "2000-01-01T23.59.59.999" - private final boolean roundCeil; - private final DateMathParser dateMathParser; private String nullValue; @@ -198,7 +180,7 @@ public static class TypeParser implements Mapper.TypeParser { protected final TimeUnit timeUnit; protected DateFieldMapper(Names names, FormatDateTimeFormatter dateTimeFormatter, int precisionStep, float boost, FieldType fieldType, Boolean docValues, - String nullValue, TimeUnit timeUnit, boolean roundCeil, Explicit ignoreMalformed,Explicit coerce, + String nullValue, TimeUnit timeUnit, Explicit ignoreMalformed,Explicit coerce, PostingsFormatProvider postingsProvider, DocValuesFormatProvider docValuesProvider, SimilarityProvider similarity, Loading normsLoading, @Nullable Settings fieldDataSettings, Settings indexSettings, MultiFields multiFields, CopyTo copyTo) { @@ -208,7 +190,6 @@ protected DateFieldMapper(Names names, FormatDateTimeFormatter dateTimeFormatter this.dateTimeFormatter = dateTimeFormatter; this.nullValue = nullValue; this.timeUnit = timeUnit; - this.roundCeil = roundCeil; this.dateMathParser = new DateMathParser(dateTimeFormatter, timeUnit); } @@ -328,8 +309,7 @@ public long parseToMilliseconds(String value, boolean inclusive, @Nullable DateT if (forcedDateParser != null) { dateParser = forcedDateParser; } - boolean roundUp = inclusive && roundCeil; - return dateParser.parse(value, now, roundUp, zone); + return dateParser.parse(value, now, inclusive, zone); } @Override diff --git a/src/main/java/org/elasticsearch/index/mapper/internal/TimestampFieldMapper.java b/src/main/java/org/elasticsearch/index/mapper/internal/TimestampFieldMapper.java index 95242524fe9b1..aae2104287820 100644 --- a/src/main/java/org/elasticsearch/index/mapper/internal/TimestampFieldMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/internal/TimestampFieldMapper.java @@ -49,8 +49,6 @@ import static org.elasticsearch.index.mapper.core.TypeParsers.parseDateTimeFormatter; import static org.elasticsearch.index.mapper.core.TypeParsers.parseField; -/** - */ public class TimestampFieldMapper extends DateFieldMapper implements InternalMapper, RootMapper { public static final String NAME = "_timestamp"; @@ -123,12 +121,7 @@ public TimestampFieldMapper build(BuilderContext context) { assert fieldType.stored(); fieldType.setStored(false); } - boolean roundCeil = Defaults.ROUND_CEIL; - if (context.indexSettings() != null) { - Settings settings = context.indexSettings(); - roundCeil = settings.getAsBoolean("index.mapping.date.round_ceil", settings.getAsBoolean("index.mapping.date.parse_upper_inclusive", Defaults.ROUND_CEIL)); - } - return new TimestampFieldMapper(fieldType, docValues, enabledState, path, dateTimeFormatter, defaultTimestamp, roundCeil, + return new TimestampFieldMapper(fieldType, docValues, enabledState, path, dateTimeFormatter, defaultTimestamp, ignoreMalformed(context), coerce(context), postingsProvider, docValuesProvider, normsLoading, fieldDataSettings, context.indexSettings()); } } @@ -173,18 +166,18 @@ private static FieldType defaultFieldType(Settings settings) { public TimestampFieldMapper(Settings indexSettings) { this(new FieldType(defaultFieldType(indexSettings)), null, Defaults.ENABLED, Defaults.PATH, Defaults.DATE_TIME_FORMATTER, Defaults.DEFAULT_TIMESTAMP, - Defaults.ROUND_CEIL, Defaults.IGNORE_MALFORMED, Defaults.COERCE, null, null, null, null, indexSettings); + Defaults.IGNORE_MALFORMED, Defaults.COERCE, null, null, null, null, indexSettings); } protected TimestampFieldMapper(FieldType fieldType, Boolean docValues, EnabledAttributeMapper enabledState, String path, - FormatDateTimeFormatter dateTimeFormatter, String defaultTimestamp, boolean roundCeil, + FormatDateTimeFormatter dateTimeFormatter, String defaultTimestamp, Explicit ignoreMalformed, Explicit coerce, PostingsFormatProvider postingsProvider, DocValuesFormatProvider docValuesProvider, Loading normsLoading, @Nullable Settings fieldDataSettings, Settings indexSettings) { super(new Names(Defaults.NAME, Defaults.NAME, Defaults.NAME, Defaults.NAME), dateTimeFormatter, Defaults.PRECISION_STEP_64_BIT, Defaults.BOOST, fieldType, docValues, Defaults.NULL_VALUE, TimeUnit.MILLISECONDS /*always milliseconds*/, - roundCeil, ignoreMalformed, coerce, postingsProvider, docValuesProvider, null, normsLoading, fieldDataSettings, + ignoreMalformed, coerce, postingsProvider, docValuesProvider, null, normsLoading, fieldDataSettings, indexSettings, MultiFields.empty(), null); this.enabledState = enabledState; this.path = path; diff --git a/src/main/java/org/elasticsearch/index/query/QueryStringQueryParser.java b/src/main/java/org/elasticsearch/index/query/QueryStringQueryParser.java index cd7520663fecb..ded43bc50e89b 100644 --- a/src/main/java/org/elasticsearch/index/query/QueryStringQueryParser.java +++ b/src/main/java/org/elasticsearch/index/query/QueryStringQueryParser.java @@ -29,7 +29,6 @@ import org.elasticsearch.common.ParseField; import org.elasticsearch.common.Strings; import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.joda.DateMathParser; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.settings.Settings; @@ -38,6 +37,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.analysis.NamedAnalyzer; import org.elasticsearch.index.query.support.QueryParsers; +import org.joda.time.DateTimeZone; import java.io.IOException; import java.util.Locale; @@ -197,7 +197,7 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars qpSettings.locale(LocaleUtils.parse(localeStr)); } else if ("time_zone".equals(currentFieldName)) { try { - qpSettings.timeZone(DateMathParser.parseZone(parser.text())); + qpSettings.timeZone(DateTimeZone.forID(parser.text())); } catch (IllegalArgumentException e) { throw new QueryParsingException(parseContext.index(), "[query_string] time_zone [" + parser.text() + "] is unknown"); } diff --git a/src/main/java/org/elasticsearch/index/query/RangeFilterParser.java b/src/main/java/org/elasticsearch/index/query/RangeFilterParser.java index a07859d12a789..b90f237b439ba 100644 --- a/src/main/java/org/elasticsearch/index/query/RangeFilterParser.java +++ b/src/main/java/org/elasticsearch/index/query/RangeFilterParser.java @@ -101,7 +101,7 @@ public Filter parse(QueryParseContext parseContext) throws IOException, QueryPar to = parser.objectBytes(); includeUpper = true; } else if ("time_zone".equals(currentFieldName) || "timeZone".equals(currentFieldName)) { - timeZone = DateMathParser.parseZone(parser.text()); + timeZone = DateTimeZone.forID(parser.text()); } else if ("format".equals(currentFieldName)) { forcedDateParser = new DateMathParser(Joda.forPattern(parser.text()), DateFieldMapper.Defaults.TIME_UNIT); } else { diff --git a/src/main/java/org/elasticsearch/index/query/RangeQueryParser.java b/src/main/java/org/elasticsearch/index/query/RangeQueryParser.java index 83b8e93ffea24..c274eaf49442e 100644 --- a/src/main/java/org/elasticsearch/index/query/RangeQueryParser.java +++ b/src/main/java/org/elasticsearch/index/query/RangeQueryParser.java @@ -102,7 +102,7 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars to = parser.objectBytes(); includeUpper = true; } else if ("time_zone".equals(currentFieldName) || "timeZone".equals(currentFieldName)) { - timeZone = DateMathParser.parseZone(parser.text()); + timeZone = DateTimeZone.forID(parser.text()); } else if ("_name".equals(currentFieldName)) { queryName = parser.text(); } else if ("format".equals(currentFieldName)) { diff --git a/src/main/java/org/elasticsearch/search/aggregations/bucket/histogram/DateHistogramParser.java b/src/main/java/org/elasticsearch/search/aggregations/bucket/histogram/DateHistogramParser.java index 7cdc5f78cdc2c..5335f997a7ded 100644 --- a/src/main/java/org/elasticsearch/search/aggregations/bucket/histogram/DateHistogramParser.java +++ b/src/main/java/org/elasticsearch/search/aggregations/bucket/histogram/DateHistogramParser.java @@ -100,11 +100,11 @@ public AggregatorFactory parse(String aggregationName, XContentParser parser, Se continue; } else if (token == XContentParser.Token.VALUE_STRING) { if ("time_zone".equals(currentFieldName) || "timeZone".equals(currentFieldName)) { - preZone = DateMathParser.parseZone(parser.text()); + preZone = DateTimeZone.forID(parser.text()); } else if ("pre_zone".equals(currentFieldName) || "preZone".equals(currentFieldName)) { - preZone = DateMathParser.parseZone(parser.text()); + preZone = DateTimeZone.forID(parser.text()); } else if ("post_zone".equals(currentFieldName) || "postZone".equals(currentFieldName)) { - postZone = DateMathParser.parseZone(parser.text()); + postZone = DateTimeZone.forID(parser.text()); } else if ("pre_offset".equals(currentFieldName) || "preOffset".equals(currentFieldName)) { preOffset = parseOffset(parser.text()); } else if ("post_offset".equals(currentFieldName) || "postOffset".equals(currentFieldName)) { diff --git a/src/test/java/org/elasticsearch/common/joda/DateMathParserTests.java b/src/test/java/org/elasticsearch/common/joda/DateMathParserTests.java index 013e3eed71d4f..3304699dcbddc 100644 --- a/src/test/java/org/elasticsearch/common/joda/DateMathParserTests.java +++ b/src/test/java/org/elasticsearch/common/joda/DateMathParserTests.java @@ -20,11 +20,14 @@ package org.elasticsearch.common.joda; import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.test.ElasticsearchTestCase; import org.joda.time.DateTimeZone; import java.util.concurrent.TimeUnit; +import static org.hamcrest.Matchers.equalTo; + public class DateMathParserTests extends ElasticsearchTestCase { FormatDateTimeFormatter formatter = Joda.forPattern("dateOptionalTime"); DateMathParser parser = new DateMathParser(formatter, TimeUnit.MILLISECONDS); @@ -34,16 +37,19 @@ void assertDateMathEquals(String toTest, String expected) { } void assertDateMathEquals(String toTest, String expected, long now, boolean roundUp, DateTimeZone timeZone) { - DateMathParser parser = new DateMathParser(Joda.forPattern("dateOptionalTime"), TimeUnit.MILLISECONDS); - long gotMillis = parser.parse(toTest, now, roundUp, null); + long gotMillis = parser.parse(toTest, now, roundUp, timeZone); + assertDateEquals(gotMillis, toTest, expected); + } + + void assertDateEquals(long gotMillis, String original, String expected) { long expectedMillis = parser.parse(expected, 0); if (gotMillis != expectedMillis) { fail("Date math not equal\n" + - "Original : " + toTest + "\n" + - "Parsed : " + formatter.printer().print(gotMillis) + "\n" + - "Expected : " + expected + "\n" + - "Expected milliseconds : " + expectedMillis + "\n" + - "Actual milliseconds : " + gotMillis + "\n"); + "Original : " + original + "\n" + + "Parsed : " + formatter.printer().print(gotMillis) + "\n" + + "Expected : " + expected + "\n" + + "Expected milliseconds : " + expectedMillis + "\n" + + "Actual milliseconds : " + gotMillis + "\n"); } } @@ -56,6 +62,23 @@ public void testBasicDates() { assertDateMathEquals("2014-05-30T20:21:35", "2014-05-30T20:21:35.000"); assertDateMathEquals("2014-05-30T20:21:35.123", "2014-05-30T20:21:35.123"); } + + public void testRoundingDoesNotAffectExactDate() { + assertDateMathEquals("2014-11-12T22:55:00Z", "2014-11-12T22:55:00Z", 0, true, null); + assertDateMathEquals("2014-11-12T22:55:00Z", "2014-11-12T22:55:00Z", 0, false, null); + } + + public void testTimezone() { + // timezone works within date format + assertDateMathEquals("2014-05-30T20:21+02:00", "2014-05-30T18:21:00.000"); + + // but also externally + assertDateMathEquals("2014-05-30T20:21", "2014-05-30T18:21:00.000", 0, false, DateTimeZone.forID("+02:00")); + + // and timezone in the date has priority + assertDateMathEquals("2014-05-30T20:21+03:00", "2014-05-30T17:21:00.000", 0, false, DateTimeZone.forID("-08:00")); + assertDateMathEquals("2014-05-30T20:21Z", "2014-05-30T20:21:00.000", 0, false, DateTimeZone.forID("-08:00")); + } public void testBasicMath() { assertDateMathEquals("2014-11-18||+y", "2015-11-18"); @@ -81,6 +104,10 @@ public void testBasicMath() { assertDateMathEquals("2014-11-18T14:27:32||+60s", "2014-11-18T14:28:32"); assertDateMathEquals("2014-11-18T14:27:32||-3600s", "2014-11-18T13:27:32"); } + + public void testLenientEmptyMath() { + assertDateMathEquals("2014-05-30T20:21||", "2014-05-30T20:21:00.000"); + } public void testMultipleAdjustments() { assertDateMathEquals("2014-11-18||+1M-1M", "2014-11-18"); @@ -97,13 +124,16 @@ public void testNow() { assertDateMathEquals("now+M", "2014-12-18T14:27:32", now, false, null); assertDateMathEquals("now-2d", "2014-11-16T14:27:32", now, false, null); assertDateMathEquals("now/m", "2014-11-18T14:27", now, false, null); + + // timezone does not affect now + assertDateMathEquals("now/m", "2014-11-18T14:27", now, false, DateTimeZone.forID("+02:00")); } public void testRounding() { assertDateMathEquals("2014-11-18||/y", "2014-01-01", 0, false, null); assertDateMathEquals("2014-11-18||/y", "2014-12-31T23:59:59.999", 0, true, null); assertDateMathEquals("2014||/y", "2014-01-01", 0, false, null); - assertDateMathEquals("2014||/y", "2014-12-31T23:59:59.999", 0, true, null); + assertDateMathEquals("2014-01-01T00:00:00.001||/y", "2014-12-31T23:59:59.999", 0, true, null); assertDateMathEquals("2014-11-18||/M", "2014-11-01", 0, false, null); assertDateMathEquals("2014-11-18||/M", "2014-11-30T23:59:59.999", 0, true, null); @@ -140,20 +170,47 @@ public void testRounding() { assertDateMathEquals("2014-11-18T14:27:32||/s", "2014-11-18T14:27:32.999", 0, true, null); } - void assertParseException(String msg, String date) { + public void testTimestamps() { + assertDateMathEquals("1418248078000", "2014-12-10T21:47:58.000"); + + // timezone does not affect timestamps + assertDateMathEquals("1418248078000", "2014-12-10T21:47:58.000", 0, false, DateTimeZone.forID("-08:00")); + + // datemath still works on timestamps + assertDateMathEquals("1418248078000||/m", "2014-12-10T21:47:00.000"); + + // also check other time units + DateMathParser parser = new DateMathParser(Joda.forPattern("dateOptionalTime"), TimeUnit.SECONDS); + long datetime = parser.parse("1418248078", 0); + assertDateEquals(datetime, "1418248078", "2014-12-10T21:47:58.000"); + + // a timestamp before 10000 is a year + assertDateMathEquals("9999", "9999-01-01T00:00:00.000"); + // 10000 is the first timestamp + assertDateMathEquals("10000", "1970-01-01T00:00:10.000"); + // but 10000 with T is still a date format + assertDateMathEquals("10000T", "10000-01-01T00:00:00.000"); + } + + void assertParseException(String msg, String date, String exc) { try { parser.parse(date, 0); fail("Date: " + date + "\n" + msg); } catch (ElasticsearchParseException e) { - // expected + assertThat(ExceptionsHelper.detailedMessage(e).contains(exc), equalTo(true)); } } public void testIllegalMathFormat() { - assertParseException("Expected date math unsupported operator exception", "2014-11-18||*5"); - assertParseException("Expected date math incompatible rounding exception", "2014-11-18||/2m"); - assertParseException("Expected date math illegal unit type exception", "2014-11-18||+2a"); - assertParseException("Expected date math truncation exception", "2014-11-18||+12"); - assertParseException("Expected date math truncation exception", "2014-11-18||-"); + assertParseException("Expected date math unsupported operator exception", "2014-11-18||*5", "operator not supported"); + assertParseException("Expected date math incompatible rounding exception", "2014-11-18||/2m", "rounding"); + assertParseException("Expected date math illegal unit type exception", "2014-11-18||+2a", "unit [a] not supported"); + assertParseException("Expected date math truncation exception", "2014-11-18||+12", "truncated"); + assertParseException("Expected date math truncation exception", "2014-11-18||-", "truncated"); + } + + public void testIllegalDateFormat() { + assertParseException("Expected bad timestamp exception", Long.toString(Long.MAX_VALUE) + "0", "timestamp"); + assertParseException("Expected bad date format exception", "123bogus", "with format"); } } diff --git a/src/test/java/org/elasticsearch/count/simple/SimpleCountTests.java b/src/test/java/org/elasticsearch/count/simple/SimpleCountTests.java index c673f8a6b30a4..dd4ed24af5a51 100644 --- a/src/test/java/org/elasticsearch/count/simple/SimpleCountTests.java +++ b/src/test/java/org/elasticsearch/count/simple/SimpleCountTests.java @@ -104,20 +104,6 @@ public void simpleIdTests() { assertHitCount(countResponse, 1l); } - @Test - public void simpleDateMathTests() throws Exception { - createIndex("test"); - client().prepareIndex("test", "type1", "1").setSource("field", "2010-01-05T02:00").execute().actionGet(); - client().prepareIndex("test", "type1", "2").setSource("field", "2010-01-06T02:00").execute().actionGet(); - ensureGreen(); - refresh(); - CountResponse countResponse = client().prepareCount("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-03||+2d").lte("2010-01-04||+2d")).execute().actionGet(); - assertHitCount(countResponse, 2l); - - countResponse = client().prepareCount("test").setQuery(QueryBuilders.queryStringQuery("field:[2010-01-03||+2d TO 2010-01-04||+2d]")).execute().actionGet(); - assertHitCount(countResponse, 2l); - } - @Test public void simpleCountEarlyTerminationTests() throws Exception { // set up one shard only to test early termination @@ -130,29 +116,26 @@ public void simpleCountEarlyTerminationTests() throws Exception { for (int i = 1; i <= max; i++) { String id = String.valueOf(i); - docbuilders.add(client().prepareIndex("test", "type1", id).setSource("field", "2010-01-"+ id +"T02:00")); + docbuilders.add(client().prepareIndex("test", "type1", id).setSource("field", i)); } indexRandom(true, docbuilders); ensureGreen(); refresh(); - String upperBound = "2010-01-" + String.valueOf(max+1) + "||+2d"; - String lowerBound = "2009-12-01||+2d"; - // sanity check - CountResponse countResponse = client().prepareCount("test").setQuery(QueryBuilders.rangeQuery("field").gte(lowerBound).lte(upperBound)).execute().actionGet(); + CountResponse countResponse = client().prepareCount("test").setQuery(QueryBuilders.rangeQuery("field").gte(1).lte(max)).execute().actionGet(); assertHitCount(countResponse, max); // threshold <= actual count for (int i = 1; i <= max; i++) { - countResponse = client().prepareCount("test").setQuery(QueryBuilders.rangeQuery("field").gte(lowerBound).lte(upperBound)).setTerminateAfter(i).execute().actionGet(); + countResponse = client().prepareCount("test").setQuery(QueryBuilders.rangeQuery("field").gte(1).lte(max)).setTerminateAfter(i).execute().actionGet(); assertHitCount(countResponse, i); assertTrue(countResponse.terminatedEarly()); } // threshold > actual count - countResponse = client().prepareCount("test").setQuery(QueryBuilders.rangeQuery("field").gte(lowerBound).lte(upperBound)).setTerminateAfter(max + randomIntBetween(1, max)).execute().actionGet(); + countResponse = client().prepareCount("test").setQuery(QueryBuilders.rangeQuery("field").gte(1).lte(max)).setTerminateAfter(max + randomIntBetween(1, max)).execute().actionGet(); assertHitCount(countResponse, max); assertFalse(countResponse.terminatedEarly()); } diff --git a/src/test/java/org/elasticsearch/exists/SimpleExistsTests.java b/src/test/java/org/elasticsearch/exists/SimpleExistsTests.java index 657855678de60..78e50de0f5094 100644 --- a/src/test/java/org/elasticsearch/exists/SimpleExistsTests.java +++ b/src/test/java/org/elasticsearch/exists/SimpleExistsTests.java @@ -99,29 +99,15 @@ public void simpleIdTests() { assertExists(existsResponse, true); } - @Test - public void simpleDateMathTests() throws Exception { - createIndex("test"); - client().prepareIndex("test", "type1", "1").setSource("field", "2010-01-05T02:00").execute().actionGet(); - client().prepareIndex("test", "type1", "2").setSource("field", "2010-01-06T02:00").execute().actionGet(); - ensureGreen(); - refresh(); - ExistsResponse existsResponse = client().prepareExists("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-03||+2d").lte("2010-01-04||+2d")).execute().actionGet(); - assertExists(existsResponse, true); - - existsResponse = client().prepareExists("test").setQuery(QueryBuilders.queryStringQuery("field:[2010-01-03||+2d TO 2010-01-04||+2d]")).execute().actionGet(); - assertExists(existsResponse, true); - } - @Test public void simpleNonExistenceTests() throws Exception { createIndex("test"); - client().prepareIndex("test", "type1", "1").setSource("field", "2010-01-05T02:00").execute().actionGet(); - client().prepareIndex("test", "type1", "2").setSource("field", "2010-01-06T02:00").execute().actionGet(); + client().prepareIndex("test", "type1", "1").setSource("field", 2).execute().actionGet(); + client().prepareIndex("test", "type1", "2").setSource("field", 5).execute().actionGet(); client().prepareIndex("test", "type", "XXX1").setSource("field", "value").execute().actionGet(); ensureGreen(); refresh(); - ExistsResponse existsResponse = client().prepareExists("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-07||+2d").lte("2010-01-21||+2d")).execute().actionGet(); + ExistsResponse existsResponse = client().prepareExists("test").setQuery(QueryBuilders.rangeQuery("field").gte(6).lte(8)).execute().actionGet(); assertExists(existsResponse, false); existsResponse = client().prepareExists("test").setQuery(QueryBuilders.queryStringQuery("_id:XXY*").lowercaseExpandedTerms(false)).execute().actionGet(); diff --git a/src/test/java/org/elasticsearch/index/mapper/date/SimpleDateMappingTests.java b/src/test/java/org/elasticsearch/index/mapper/date/SimpleDateMappingTests.java index 31f6e6fa27790..bc6abd8653ffc 100644 --- a/src/test/java/org/elasticsearch/index/mapper/date/SimpleDateMappingTests.java +++ b/src/test/java/org/elasticsearch/index/mapper/date/SimpleDateMappingTests.java @@ -232,7 +232,7 @@ public void testHourFormat() throws Exception { } assertThat(filter, instanceOf(NumericRangeFilter.class)); NumericRangeFilter rangeFilter = (NumericRangeFilter) filter; - assertThat(rangeFilter.getMax(), equalTo(new DateTime(TimeValue.timeValueHours(11).millis() + 999).getMillis())); // +999 to include the 00-01 minute + assertThat(rangeFilter.getMax(), equalTo(new DateTime(TimeValue.timeValueHours(11).millis()).getMillis())); assertThat(rangeFilter.getMin(), equalTo(new DateTime(TimeValue.timeValueHours(10).millis()).getMillis())); } @@ -262,7 +262,7 @@ public void testDayWithoutYearFormat() throws Exception { } assertThat(filter, instanceOf(NumericRangeFilter.class)); NumericRangeFilter rangeFilter = (NumericRangeFilter) filter; - assertThat(rangeFilter.getMax(), equalTo(new DateTime(TimeValue.timeValueHours(35).millis() + 999).getMillis())); // +999 to include the 00-01 minute + assertThat(rangeFilter.getMax(), equalTo(new DateTime(TimeValue.timeValueHours(35).millis()).getMillis())); assertThat(rangeFilter.getMin(), equalTo(new DateTime(TimeValue.timeValueHours(34).millis()).getMillis())); } diff --git a/src/test/java/org/elasticsearch/index/query/date_range_filter_timezone.json b/src/test/java/org/elasticsearch/index/query/date_range_filter_timezone.json index 4253018c121c5..158550afbe261 100644 --- a/src/test/java/org/elasticsearch/index/query/date_range_filter_timezone.json +++ b/src/test/java/org/elasticsearch/index/query/date_range_filter_timezone.json @@ -5,7 +5,7 @@ "born" : { "gte": "2012-01-01", "lte": "now", - "time_zone": "+1:00" + "time_zone": "+01:00" } } } diff --git a/src/test/java/org/elasticsearch/index/query/date_range_filter_timezone_numeric_field.json b/src/test/java/org/elasticsearch/index/query/date_range_filter_timezone_numeric_field.json index 8814a7ea9540d..6e0719475b971 100644 --- a/src/test/java/org/elasticsearch/index/query/date_range_filter_timezone_numeric_field.json +++ b/src/test/java/org/elasticsearch/index/query/date_range_filter_timezone_numeric_field.json @@ -5,7 +5,7 @@ "age" : { "gte": "0", "lte": "100", - "time_zone": "-1:00" + "time_zone": "-01:00" } } } diff --git a/src/test/java/org/elasticsearch/index/query/date_range_query_timezone.json b/src/test/java/org/elasticsearch/index/query/date_range_query_timezone.json index da0b94314ce9f..0cabb1511ac19 100644 --- a/src/test/java/org/elasticsearch/index/query/date_range_query_timezone.json +++ b/src/test/java/org/elasticsearch/index/query/date_range_query_timezone.json @@ -3,7 +3,7 @@ "born" : { "gte": "2012-01-01", "lte": "now", - "time_zone": "+1:00" + "time_zone": "+01:00" } } } diff --git a/src/test/java/org/elasticsearch/index/query/date_range_query_timezone_numeric_field.json b/src/test/java/org/elasticsearch/index/query/date_range_query_timezone_numeric_field.json index 61670bd60d3e6..b7526a2c2948e 100644 --- a/src/test/java/org/elasticsearch/index/query/date_range_query_timezone_numeric_field.json +++ b/src/test/java/org/elasticsearch/index/query/date_range_query_timezone_numeric_field.json @@ -3,7 +3,7 @@ "age" : { "gte": "0", "lte": "100", - "time_zone": "-1:00" + "time_zone": "-01:00" } } } diff --git a/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java b/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java index 63a7ab36a1108..8160a30901f7c 100644 --- a/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java +++ b/src/test/java/org/elasticsearch/search/aggregations/bucket/DateHistogramTests.java @@ -1047,7 +1047,7 @@ public void singleValue_WithPreZone() throws Exception { .setQuery(matchAllQuery()) .addAggregation(dateHistogram("date_histo") .field("date") - .preZone("-2:00") + .preZone("-02:00") .interval(DateHistogram.Interval.DAY) .format("yyyy-MM-dd")) .execute().actionGet(); @@ -1082,7 +1082,7 @@ public void singleValue_WithPreZone_WithAadjustLargeInterval() throws Exception .setQuery(matchAllQuery()) .addAggregation(dateHistogram("date_histo") .field("date") - .preZone("-2:00") + .preZone("-02:00") .interval(DateHistogram.Interval.DAY) .preZoneAdjustLargeInterval(true) .format("yyyy-MM-dd'T'HH:mm:ss")) diff --git a/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java b/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java index d37c3d5792e08..027a75fd2f389 100644 --- a/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java +++ b/src/test/java/org/elasticsearch/search/query/SimpleQueryTests.java @@ -2252,17 +2252,17 @@ public void testRangeFilterWithTimeZone() throws Exception { // We define a time zone to be applied to the filter and from/to have no time zone searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from("2014-01-01T03:00:00").to("2014-01-01T03:59:00").timeZone("+3:00"))) + .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from("2014-01-01T03:00:00").to("2014-01-01T03:59:00").timeZone("+03:00"))) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getId(), is("1")); searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from("2014-01-01T02:00:00").to("2014-01-01T02:59:00").timeZone("+3:00"))) + .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from("2014-01-01T02:00:00").to("2014-01-01T02:59:00").timeZone("+03:00"))) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getId(), is("2")); searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from("2014-01-01T04:00:00").to("2014-01-01T04:59:00").timeZone("+3:00"))) + .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from("2014-01-01T04:00:00").to("2014-01-01T04:59:00").timeZone("+03:00"))) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getId(), is("3")); @@ -2270,7 +2270,7 @@ public void testRangeFilterWithTimeZone() throws Exception { // When we use long values, it means we have ms since epoch UTC based so we don't apply any transformation try { client().prepareSearch("test") - .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from(1388534400000L).to(1388537940999L).timeZone("+1:00"))) + .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from(1388534400000L).to(1388537940999L).timeZone("+01:00"))) .get(); fail("A Range Filter using ms since epoch with a TimeZone should raise a QueryParsingException"); } catch (SearchPhaseExecutionException e) { @@ -2278,13 +2278,13 @@ public void testRangeFilterWithTimeZone() throws Exception { } searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from("2014-01-01").to("2014-01-01T00:59:00").timeZone("-1:00"))) + .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from("2014-01-01").to("2014-01-01T00:59:00").timeZone("-01:00"))) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getId(), is("3")); searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from("now/d-1d").timeZone("+1:00"))) + .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("date").from("now/d-1d").timeZone("+01:00"))) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getId(), is("4")); @@ -2292,7 +2292,7 @@ public void testRangeFilterWithTimeZone() throws Exception { // A Range Filter on a numeric field with a TimeZone should raise an exception try { client().prepareSearch("test") - .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("num").from("0").to("4").timeZone("-1:00"))) + .setQuery(QueryBuilders.filteredQuery(matchAllQuery(), FilterBuilders.rangeFilter("num").from("0").to("4").timeZone("-01:00"))) .get(); fail("A Range Filter on a numeric field with a TimeZone should raise a QueryParsingException"); } catch (SearchPhaseExecutionException e) { @@ -2348,17 +2348,17 @@ public void testRangeQueryWithTimeZone() throws Exception { // We define a time zone to be applied to the filter and from/to have no time zone searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.rangeQuery("date").from("2014-01-01T03:00:00").to("2014-01-01T03:59:00").timeZone("+3:00")) + .setQuery(QueryBuilders.rangeQuery("date").from("2014-01-01T03:00:00").to("2014-01-01T03:59:00").timeZone("+03:00")) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getId(), is("1")); searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.rangeQuery("date").from("2014-01-01T02:00:00").to("2014-01-01T02:59:00").timeZone("+3:00")) + .setQuery(QueryBuilders.rangeQuery("date").from("2014-01-01T02:00:00").to("2014-01-01T02:59:00").timeZone("+03:00")) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getId(), is("2")); searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.rangeQuery("date").from("2014-01-01T04:00:00").to("2014-01-01T04:59:00").timeZone("+3:00")) + .setQuery(QueryBuilders.rangeQuery("date").from("2014-01-01T04:00:00").to("2014-01-01T04:59:00").timeZone("+03:00")) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getId(), is("3")); @@ -2366,7 +2366,7 @@ public void testRangeQueryWithTimeZone() throws Exception { // When we use long values, it means we have ms since epoch UTC based so we don't apply any transformation try { client().prepareSearch("test") - .setQuery(QueryBuilders.rangeQuery("date").from(1388534400000L).to(1388537940999L).timeZone("+1:00")) + .setQuery(QueryBuilders.rangeQuery("date").from(1388534400000L).to(1388537940999L).timeZone("+01:00")) .get(); fail("A Range Filter using ms since epoch with a TimeZone should raise a QueryParsingException"); } catch (SearchPhaseExecutionException e) { @@ -2374,13 +2374,13 @@ public void testRangeQueryWithTimeZone() throws Exception { } searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.rangeQuery("date").from("2014-01-01").to("2014-01-01T00:59:00").timeZone("-1:00")) + .setQuery(QueryBuilders.rangeQuery("date").from("2014-01-01").to("2014-01-01T00:59:00").timeZone("-01:00")) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getId(), is("3")); searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.rangeQuery("date").from("now/d-1d").timeZone("+1:00")) + .setQuery(QueryBuilders.rangeQuery("date").from("now/d-1d").timeZone("+01:00")) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getId(), is("4")); @@ -2388,7 +2388,7 @@ public void testRangeQueryWithTimeZone() throws Exception { // A Range Filter on a numeric field with a TimeZone should raise an exception try { client().prepareSearch("test") - .setQuery(QueryBuilders.rangeQuery("num").from("0").to("4").timeZone("-1:00")) + .setQuery(QueryBuilders.rangeQuery("num").from("0").to("4").timeZone("-01:00")) .get(); fail("A Range Filter on a numeric field with a TimeZone should raise a QueryParsingException"); } catch (SearchPhaseExecutionException e) { diff --git a/src/test/java/org/elasticsearch/search/simple/SimpleSearchTests.java b/src/test/java/org/elasticsearch/search/simple/SimpleSearchTests.java index a59d063de6b3e..2e3276107fa3f 100644 --- a/src/test/java/org/elasticsearch/search/simple/SimpleSearchTests.java +++ b/src/test/java/org/elasticsearch/search/simple/SimpleSearchTests.java @@ -126,53 +126,34 @@ public void simpleIdTests() { } @Test - public void simpleDateRangeWithUpperInclusiveEnabledTests() throws Exception { + public void simpleDateRangeTests() throws Exception { createIndex("test"); client().prepareIndex("test", "type1", "1").setSource("field", "2010-01-05T02:00").execute().actionGet(); client().prepareIndex("test", "type1", "2").setSource("field", "2010-01-06T02:00").execute().actionGet(); + ensureGreen(); refresh(); + SearchResponse searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-03||+2d").lte("2010-01-04||+2d/d")).execute().actionGet(); + assertNoFailures(searchResponse); + assertHitCount(searchResponse, 2l); - // test include upper on ranges to include the full day on the upper bound - SearchResponse searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-05").lte("2010-01-06")).execute().actionGet(); + searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-05T02:00").lte("2010-01-06T02:00")).execute().actionGet(); + assertNoFailures(searchResponse); assertHitCount(searchResponse, 2l); - searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-05").lt("2010-01-06")).execute().actionGet(); - assertHitCount(searchResponse, 1l); - } - @Test - public void simpleDateRangeWithUpperInclusiveDisabledTests() throws Exception { - assertAcked(prepareCreate("test").setSettings(ImmutableSettings.settingsBuilder() - .put(indexSettings()) - .put("index.mapping.date.round_ceil", false))); - client().prepareIndex("test", "type1", "1").setSource("field", "2010-01-05T02:00").execute().actionGet(); - client().prepareIndex("test", "type1", "2").setSource("field", "2010-01-06T02:00").execute().actionGet(); - ensureGreen(); - refresh(); - // test include upper on ranges to include the full day on the upper bound (disabled here though...) - SearchResponse searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-05").lte("2010-01-06")).execute().actionGet(); + searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-05T02:00").lt("2010-01-06T02:00")).execute().actionGet(); assertNoFailures(searchResponse); assertHitCount(searchResponse, 1l); - searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-05").lt("2010-01-06")).execute().actionGet(); - assertHitCount(searchResponse, 1l); - } - @Test @TestLogging("action.search.type:TRACE,action.admin.indices.refresh:TRACE") - public void simpleDateMathTests() throws Exception { - createIndex("test"); - client().prepareIndex("test", "type1", "1").setSource("field", "2010-01-05T02:00").execute().actionGet(); - client().prepareIndex("test", "type1", "2").setSource("field", "2010-01-06T02:00").execute().actionGet(); - ensureGreen(); - refresh(); - SearchResponse searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.rangeQuery("field").gte("2010-01-03||+2d").lte("2010-01-04||+2d")).execute().actionGet(); + searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.rangeQuery("field").gt("2010-01-05T02:00").lt("2010-01-06T02:00")).execute().actionGet(); assertNoFailures(searchResponse); - assertHitCount(searchResponse, 2l); + assertHitCount(searchResponse, 0l); - searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.queryStringQuery("field:[2010-01-03||+2d TO 2010-01-04||+2d]")).execute().actionGet(); + searchResponse = client().prepareSearch("test").setQuery(QueryBuilders.queryStringQuery("field:[2010-01-03||+2d TO 2010-01-04||+2d/d]")).execute().actionGet(); assertHitCount(searchResponse, 2l); } @Test - public void localDependentDateTests() throws Exception { + public void localeDependentDateTests() throws Exception { assertAcked(prepareCreate("test") .addMapping("type1", jsonBuilder().startObject() @@ -219,28 +200,25 @@ public void simpleTerminateAfterCountTests() throws Exception { for (int i = 1; i <= max; i++) { String id = String.valueOf(i); - docbuilders.add(client().prepareIndex("test", "type1", id).setSource("field", "2010-01-"+ id +"T02:00")); + docbuilders.add(client().prepareIndex("test", "type1", id).setSource("field", i)); } indexRandom(true, docbuilders); ensureGreen(); refresh(); - String upperBound = "2010-01-" + String.valueOf(max+1) + "||+2d"; - String lowerBound = "2009-12-01||+2d"; - SearchResponse searchResponse; for (int i = 1; i <= max; i++) { searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.rangeQuery("field").gte(lowerBound).lte(upperBound)) + .setQuery(QueryBuilders.rangeQuery("field").gte(1).lte(max)) .setTerminateAfter(i).execute().actionGet(); assertHitCount(searchResponse, (long)i); assertTrue(searchResponse.isTerminatedEarly()); } searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.rangeQuery("field").gte(lowerBound).lte(upperBound)) + .setQuery(QueryBuilders.rangeQuery("field").gte(1).lte(max)) .setTerminateAfter(2 * max).execute().actionGet(); assertHitCount(searchResponse, max);