rename and document "index.mapping.date.parse_upper_inclusive" setting for date fields
The setting causes the upper bound for a range query/filter to be rounded up, therefore the name `round_ceil` seems to make more sense. Also this commit removes the redundant fourth parameter to DateMathParser.parse(..) which was never used. was: parse(String text, long now, boolean roundUp, boolean upperInclusive) is now: parse(String text, long now, boolean roundCeil) closes #3914
This commit is contained in:
parent
2e8bbe9e30
commit
c9dab6991e
|
@ -39,6 +39,10 @@ Note, when doing `range` type searches, and the upper value is
|
||||||
inclusive, the rounding will properly be rounded to the ceiling instead
|
inclusive, the rounding will properly be rounded to the ceiling instead
|
||||||
of flooring it.
|
of flooring it.
|
||||||
|
|
||||||
|
To change this behavior, set
|
||||||
|
`"mapping.date.round_ceil": false`.
|
||||||
|
|
||||||
|
|
||||||
[float]
|
[float]
|
||||||
[[built-in]]
|
[[built-in]]
|
||||||
=== Built In Formats
|
=== Built In Formats
|
||||||
|
|
|
@ -20,14 +20,14 @@ public class DateMathParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
public long parse(String text, long now) {
|
public long parse(String text, long now) {
|
||||||
return parse(text, now, false, false);
|
return parse(text, now, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long parseUpperInclusive(String text, long now) {
|
public long parseRoundCeil(String text, long now) {
|
||||||
return parse(text, now, true, true);
|
return parse(text, now, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long parse(String text, long now, boolean roundUp, boolean upperInclusive) {
|
public long parse(String text, long now, boolean roundCeil) {
|
||||||
long time;
|
long time;
|
||||||
String mathString;
|
String mathString;
|
||||||
if (text.startsWith("now")) {
|
if (text.startsWith("now")) {
|
||||||
|
@ -43,8 +43,8 @@ public class DateMathParser {
|
||||||
parseString = text.substring(0, index);
|
parseString = text.substring(0, index);
|
||||||
mathString = text.substring(index + 2);
|
mathString = text.substring(index + 2);
|
||||||
}
|
}
|
||||||
if (upperInclusive) {
|
if (roundCeil) {
|
||||||
time = parseUpperInclusiveStringValue(parseString);
|
time = parseRoundCeilStringValue(parseString);
|
||||||
} else {
|
} else {
|
||||||
time = parseStringValue(parseString);
|
time = parseStringValue(parseString);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ public class DateMathParser {
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseMath(mathString, time, roundUp);
|
return parseMath(mathString, time, roundCeil);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long parseMath(String mathString, long time, boolean roundUp) throws ElasticSearchParseException {
|
private long parseMath(String mathString, long time, boolean roundUp) throws ElasticSearchParseException {
|
||||||
|
@ -209,7 +209,7 @@ public class DateMathParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long parseUpperInclusiveStringValue(String value) {
|
private long parseRoundCeilStringValue(String value) {
|
||||||
try {
|
try {
|
||||||
// we create a date time for inclusive upper range, we "include" by default the day level data
|
// 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.
|
// so something like 2011-01-01 will include the full first day of 2011.
|
||||||
|
|
|
@ -81,7 +81,7 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
|
||||||
public static final String NULL_VALUE = null;
|
public static final String NULL_VALUE = null;
|
||||||
|
|
||||||
public static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS;
|
public static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS;
|
||||||
public static final boolean PARSE_UPPER_INCLUSIVE = true;
|
public static final boolean ROUND_CEIL = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder extends NumberFieldMapper.Builder<Builder, DateFieldMapper> {
|
public static class Builder extends NumberFieldMapper.Builder<Builder, DateFieldMapper> {
|
||||||
|
@ -118,16 +118,17 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DateFieldMapper build(BuilderContext context) {
|
public DateFieldMapper build(BuilderContext context) {
|
||||||
boolean parseUpperInclusive = Defaults.PARSE_UPPER_INCLUSIVE;
|
boolean roundCeil = Defaults.ROUND_CEIL;
|
||||||
if (context.indexSettings() != null) {
|
if (context.indexSettings() != null) {
|
||||||
parseUpperInclusive = context.indexSettings().getAsBoolean("index.mapping.date.parse_upper_inclusive", Defaults.PARSE_UPPER_INCLUSIVE);
|
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);
|
fieldType.setOmitNorms(fieldType.omitNorms() && boost == 1.0f);
|
||||||
if (!locale.equals(dateTimeFormatter.locale())) {
|
if (!locale.equals(dateTimeFormatter.locale())) {
|
||||||
dateTimeFormatter = new FormatDateTimeFormatter(dateTimeFormatter.format(), dateTimeFormatter.parser(), dateTimeFormatter.printer(), locale);
|
dateTimeFormatter = new FormatDateTimeFormatter(dateTimeFormatter.format(), dateTimeFormatter.parser(), dateTimeFormatter.printer(), locale);
|
||||||
}
|
}
|
||||||
DateFieldMapper fieldMapper = new DateFieldMapper(buildNames(context), dateTimeFormatter,
|
DateFieldMapper fieldMapper = new DateFieldMapper(buildNames(context), dateTimeFormatter,
|
||||||
precisionStep, boost, fieldType, nullValue, timeUnit, parseUpperInclusive, ignoreMalformed(context),
|
precisionStep, boost, fieldType, nullValue, timeUnit, roundCeil, ignoreMalformed(context),
|
||||||
postingsProvider, docValuesProvider, similarity, fieldDataSettings, context.indexSettings());
|
postingsProvider, docValuesProvider, similarity, fieldDataSettings, context.indexSettings());
|
||||||
fieldMapper.includeInAll(includeInAll);
|
fieldMapper.includeInAll(includeInAll);
|
||||||
return fieldMapper;
|
return fieldMapper;
|
||||||
|
@ -184,7 +185,14 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
|
||||||
|
|
||||||
protected final FormatDateTimeFormatter dateTimeFormatter;
|
protected final FormatDateTimeFormatter dateTimeFormatter;
|
||||||
|
|
||||||
private final boolean parseUpperInclusive;
|
// 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 final DateMathParser dateMathParser;
|
||||||
|
|
||||||
|
@ -193,7 +201,7 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
|
||||||
protected final TimeUnit timeUnit;
|
protected final TimeUnit timeUnit;
|
||||||
|
|
||||||
protected DateFieldMapper(Names names, FormatDateTimeFormatter dateTimeFormatter, int precisionStep, float boost, FieldType fieldType,
|
protected DateFieldMapper(Names names, FormatDateTimeFormatter dateTimeFormatter, int precisionStep, float boost, FieldType fieldType,
|
||||||
String nullValue, TimeUnit timeUnit, boolean parseUpperInclusive, Explicit<Boolean> ignoreMalformed,
|
String nullValue, TimeUnit timeUnit, boolean roundCeil, Explicit<Boolean> ignoreMalformed,
|
||||||
PostingsFormatProvider postingsProvider, DocValuesFormatProvider docValuesProvider, SimilarityProvider similarity,
|
PostingsFormatProvider postingsProvider, DocValuesFormatProvider docValuesProvider, SimilarityProvider similarity,
|
||||||
@Nullable Settings fieldDataSettings, Settings indexSettings) {
|
@Nullable Settings fieldDataSettings, Settings indexSettings) {
|
||||||
super(names, precisionStep, boost, fieldType, ignoreMalformed, new NamedAnalyzer("_date/" + precisionStep,
|
super(names, precisionStep, boost, fieldType, ignoreMalformed, new NamedAnalyzer("_date/" + precisionStep,
|
||||||
|
@ -203,7 +211,7 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
|
||||||
this.dateTimeFormatter = dateTimeFormatter;
|
this.dateTimeFormatter = dateTimeFormatter;
|
||||||
this.nullValue = nullValue;
|
this.nullValue = nullValue;
|
||||||
this.timeUnit = timeUnit;
|
this.timeUnit = timeUnit;
|
||||||
this.parseUpperInclusive = parseUpperInclusive;
|
this.roundCeil = roundCeil;
|
||||||
this.dateMathParser = new DateMathParser(dateTimeFormatter, timeUnit);
|
this.dateMathParser = new DateMathParser(dateTimeFormatter, timeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +313,7 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
|
||||||
|
|
||||||
public long parseToMilliseconds(Object value, @Nullable QueryParseContext context, boolean includeUpper) {
|
public long parseToMilliseconds(Object value, @Nullable QueryParseContext context, boolean includeUpper) {
|
||||||
long now = context == null ? System.currentTimeMillis() : context.nowInMillis();
|
long now = context == null ? System.currentTimeMillis() : context.nowInMillis();
|
||||||
return includeUpper ? dateMathParser.parseUpperInclusive(convertToString(value), now) : dateMathParser.parse(convertToString(value), now);
|
return includeUpper && roundCeil ? dateMathParser.parseRoundCeil(convertToString(value), now) : dateMathParser.parse(convertToString(value), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -319,7 +327,7 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
|
||||||
public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, @Nullable QueryParseContext context) {
|
public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, @Nullable QueryParseContext context) {
|
||||||
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
|
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
|
||||||
lowerTerm == null ? null : parseToMilliseconds(lowerTerm, context),
|
lowerTerm == null ? null : parseToMilliseconds(lowerTerm, context),
|
||||||
upperTerm == null ? null : parseToMilliseconds(upperTerm, context, includeUpper && parseUpperInclusive),
|
upperTerm == null ? null : parseToMilliseconds(upperTerm, context, includeUpper),
|
||||||
includeLower, includeUpper);
|
includeLower, includeUpper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,7 +335,7 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
|
||||||
public Filter rangeFilter(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, @Nullable QueryParseContext context) {
|
public Filter rangeFilter(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, @Nullable QueryParseContext context) {
|
||||||
return NumericRangeFilter.newLongRange(names.indexName(), precisionStep,
|
return NumericRangeFilter.newLongRange(names.indexName(), precisionStep,
|
||||||
lowerTerm == null ? null : parseToMilliseconds(lowerTerm, context),
|
lowerTerm == null ? null : parseToMilliseconds(lowerTerm, context),
|
||||||
upperTerm == null ? null : parseToMilliseconds(upperTerm, context, includeUpper && parseUpperInclusive),
|
upperTerm == null ? null : parseToMilliseconds(upperTerm, context, includeUpper),
|
||||||
includeLower, includeUpper);
|
includeLower, includeUpper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,7 +343,7 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
|
||||||
public Filter rangeFilter(IndexFieldDataService fieldData, Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, @Nullable QueryParseContext context) {
|
public Filter rangeFilter(IndexFieldDataService fieldData, Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, @Nullable QueryParseContext context) {
|
||||||
return NumericRangeFieldDataFilter.newLongRange((IndexNumericFieldData<?>) fieldData.getForField(this),
|
return NumericRangeFieldDataFilter.newLongRange((IndexNumericFieldData<?>) fieldData.getForField(this),
|
||||||
lowerTerm == null ? null : parseToMilliseconds(lowerTerm, context),
|
lowerTerm == null ? null : parseToMilliseconds(lowerTerm, context),
|
||||||
upperTerm == null ? null : parseToMilliseconds(upperTerm, context, includeUpper && parseUpperInclusive),
|
upperTerm == null ? null : parseToMilliseconds(upperTerm, context, includeUpper),
|
||||||
includeLower, includeUpper);
|
includeLower, includeUpper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,11 +99,12 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TimestampFieldMapper build(BuilderContext context) {
|
public TimestampFieldMapper build(BuilderContext context) {
|
||||||
boolean parseUpperInclusive = Defaults.PARSE_UPPER_INCLUSIVE;
|
boolean roundCeil = Defaults.ROUND_CEIL;
|
||||||
if (context.indexSettings() != null) {
|
if (context.indexSettings() != null) {
|
||||||
parseUpperInclusive = context.indexSettings().getAsBoolean("index.mapping.date.parse_upper_inclusive", Defaults.PARSE_UPPER_INCLUSIVE);
|
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, enabledState, path, dateTimeFormatter, parseUpperInclusive,
|
return new TimestampFieldMapper(fieldType, enabledState, path, dateTimeFormatter, roundCeil,
|
||||||
ignoreMalformed(context), postingsProvider, docValuesProvider, fieldDataSettings, context.indexSettings());
|
ignoreMalformed(context), postingsProvider, docValuesProvider, fieldDataSettings, context.indexSettings());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,18 +137,18 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap
|
||||||
|
|
||||||
public TimestampFieldMapper() {
|
public TimestampFieldMapper() {
|
||||||
this(new FieldType(Defaults.FIELD_TYPE), Defaults.ENABLED, Defaults.PATH, Defaults.DATE_TIME_FORMATTER,
|
this(new FieldType(Defaults.FIELD_TYPE), Defaults.ENABLED, Defaults.PATH, Defaults.DATE_TIME_FORMATTER,
|
||||||
Defaults.PARSE_UPPER_INCLUSIVE, Defaults.IGNORE_MALFORMED, null, null, null, ImmutableSettings.EMPTY);
|
Defaults.ROUND_CEIL, Defaults.IGNORE_MALFORMED, null, null, null, ImmutableSettings.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TimestampFieldMapper(FieldType fieldType, EnabledAttributeMapper enabledState, String path,
|
protected TimestampFieldMapper(FieldType fieldType, EnabledAttributeMapper enabledState, String path,
|
||||||
FormatDateTimeFormatter dateTimeFormatter, boolean parseUpperInclusive,
|
FormatDateTimeFormatter dateTimeFormatter, boolean roundCeil,
|
||||||
Explicit<Boolean> ignoreMalformed, PostingsFormatProvider postingsProvider,
|
Explicit<Boolean> ignoreMalformed, PostingsFormatProvider postingsProvider,
|
||||||
DocValuesFormatProvider docValuesProvider, @Nullable Settings fieldDataSettings,
|
DocValuesFormatProvider docValuesProvider, @Nullable Settings fieldDataSettings,
|
||||||
Settings indexSettings) {
|
Settings indexSettings) {
|
||||||
super(new Names(Defaults.NAME, Defaults.NAME, Defaults.NAME, Defaults.NAME), dateTimeFormatter,
|
super(new Names(Defaults.NAME, Defaults.NAME, Defaults.NAME, Defaults.NAME), dateTimeFormatter,
|
||||||
Defaults.PRECISION_STEP, Defaults.BOOST, fieldType,
|
Defaults.PRECISION_STEP, Defaults.BOOST, fieldType,
|
||||||
Defaults.NULL_VALUE, TimeUnit.MILLISECONDS /*always milliseconds*/,
|
Defaults.NULL_VALUE, TimeUnit.MILLISECONDS /*always milliseconds*/,
|
||||||
parseUpperInclusive, ignoreMalformed, postingsProvider, docValuesProvider, null, fieldDataSettings, indexSettings);
|
roundCeil, ignoreMalformed, postingsProvider, docValuesProvider, null, fieldDataSettings, indexSettings);
|
||||||
this.enabledState = enabledState;
|
this.enabledState = enabledState;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class DateMathParserTests extends ElasticsearchTestCase {
|
||||||
assertThat(parser.parse("now+1m-1s", 0), equalTo(TimeUnit.MINUTES.toMillis(1) - TimeUnit.SECONDS.toMillis(1)));
|
assertThat(parser.parse("now+1m-1s", 0), equalTo(TimeUnit.MINUTES.toMillis(1) - TimeUnit.SECONDS.toMillis(1)));
|
||||||
|
|
||||||
assertThat(parser.parse("now+1m+1s/m", 0), equalTo(TimeUnit.MINUTES.toMillis(1)));
|
assertThat(parser.parse("now+1m+1s/m", 0), equalTo(TimeUnit.MINUTES.toMillis(1)));
|
||||||
assertThat(parser.parseUpperInclusive("now+1m+1s/m", 0), equalTo(TimeUnit.MINUTES.toMillis(2)));
|
assertThat(parser.parseRoundCeil("now+1m+1s/m", 0), equalTo(TimeUnit.MINUTES.toMillis(2)));
|
||||||
|
|
||||||
assertThat(parser.parse("now+4y", 0), equalTo(TimeUnit.DAYS.toMillis(4*365 + 1)));
|
assertThat(parser.parse("now+4y", 0), equalTo(TimeUnit.DAYS.toMillis(4*365 + 1)));
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,6 @@ public class DateMathParserTests extends ElasticsearchTestCase {
|
||||||
|
|
||||||
assertThat(parser.parse("2013-01-01||+1y", 0), equalTo(parser.parse("2013-01-01", 0) + TimeUnit.DAYS.toMillis(365)));
|
assertThat(parser.parse("2013-01-01||+1y", 0), equalTo(parser.parse("2013-01-01", 0) + TimeUnit.DAYS.toMillis(365)));
|
||||||
assertThat(parser.parse("2013-03-03||/y", 0), equalTo(parser.parse("2013-01-01", 0)));
|
assertThat(parser.parse("2013-03-03||/y", 0), equalTo(parser.parse("2013-01-01", 0)));
|
||||||
assertThat(parser.parseUpperInclusive("2013-03-03||/y", 0), equalTo(parser.parse("2014-01-01", 0)));
|
assertThat(parser.parseRoundCeil("2013-03-03||/y", 0), equalTo(parser.parse("2014-01-01", 0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,7 @@ public class SimpleSearchTests extends AbstractIntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleDateRangeWithUpperInclusiveDisabledTests() throws Exception {
|
public void simpleDateRangeWithUpperInclusiveDisabledTests() throws Exception {
|
||||||
prepareCreate("test").setSettings(ImmutableSettings.settingsBuilder().put("index.mapping.date.parse_upper_inclusive", false)).execute().actionGet();
|
prepareCreate("test").setSettings(ImmutableSettings.settingsBuilder().put("index.mapping.date.round_ceil", false)).execute().actionGet();
|
||||||
client().prepareIndex("test", "type1", "1").setSource("field", "2010-01-05T02:00").execute().actionGet();
|
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", "2").setSource("field", "2010-01-06T02:00").execute().actionGet();
|
||||||
ensureGreen();
|
ensureGreen();
|
||||||
|
|
Loading…
Reference in New Issue