Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public class AutoDateHistogramAggregationBuilder extends ValuesSourceAggregation
entry(Rounding.DateTimeUnit.MONTH_OF_YEAR, "month"),
entry(Rounding.DateTimeUnit.DAY_OF_MONTH, "day"),
entry(Rounding.DateTimeUnit.HOUR_OF_DAY, "hour"),
entry(Rounding.DateTimeUnit.MINUTES_OF_HOUR, "minute"),
entry(Rounding.DateTimeUnit.MINUTE_OF_HOUR, "minute"),
entry(Rounding.DateTimeUnit.SECOND_OF_MINUTE, "second")
);

Expand All @@ -84,7 +84,7 @@ static RoundingInfo[] buildRoundings(ZoneId timeZone, String minimumInterval) {

RoundingInfo[] roundings = new RoundingInfo[6];
roundings[0] = new RoundingInfo(Rounding.DateTimeUnit.SECOND_OF_MINUTE, timeZone, 1000L, "s", 1, 5, 10, 30);
roundings[1] = new RoundingInfo(Rounding.DateTimeUnit.MINUTES_OF_HOUR, timeZone, 60 * 1000L, "m", 1, 5, 10, 30);
roundings[1] = new RoundingInfo(Rounding.DateTimeUnit.MINUTE_OF_HOUR, timeZone, 60 * 1000L, "m", 1, 5, 10, 30);
roundings[2] = new RoundingInfo(Rounding.DateTimeUnit.HOUR_OF_DAY, timeZone, 60 * 60 * 1000L, "h", 1, 3, 12);
roundings[3] = new RoundingInfo(Rounding.DateTimeUnit.DAY_OF_MONTH, timeZone, 24 * 60 * 60 * 1000L, "d", 1, 7);
roundings[4] = new RoundingInfo(Rounding.DateTimeUnit.MONTH_OF_YEAR, timeZone, 30 * 24 * 60 * 60 * 1000L, "M", 1, 3);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public void testGetAppropriateRoundingUsesCorrectIntervals() {
// an innerInterval that is quite large, such that targetBuckets * roundings[i].getMaximumInnerInterval()
// will be larger than the estimate.
roundings[0] = new RoundingInfo(Rounding.DateTimeUnit.SECOND_OF_MINUTE, timeZone, 1000L, "s", 1000);
roundings[1] = new RoundingInfo(Rounding.DateTimeUnit.MINUTES_OF_HOUR, timeZone, 60 * 1000L, "m", 1, 5, 10, 30);
roundings[1] = new RoundingInfo(Rounding.DateTimeUnit.MINUTE_OF_HOUR, timeZone, 60 * 1000L, "m", 1, 5, 10, 30);
roundings[2] = new RoundingInfo(Rounding.DateTimeUnit.HOUR_OF_DAY, timeZone, 60 * 60 * 1000L, "h", 1, 3, 12);

OffsetDateTime timestamp = Instant.parse("2018-01-01T00:00:01.000Z").atOffset(ZoneOffset.UTC);
Expand Down
68 changes: 55 additions & 13 deletions server/src/main/java/org/elasticsearch/common/Rounding.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public enum DateTimeUnit {

@Override
long roundFloor(long utcMillis, int multiplier) {
return DateUtils.roundWeekIntervalOfWeekYear(utcMillis, multiplier);
assert multiplier == 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this change. If we want the change as a short term one, to profile the outcome in an integrated system, it's OK, but otherwise we would better change the API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure either.
Yeah, that's the intention

return DateUtils.roundWeekOfWeekYear(utcMillis);
}

@Override
Expand All @@ -74,7 +75,8 @@ long extraLocalOffsetLookup() {

@Override
long roundFloor(long utcMillis, int multiplier) {
return multiplier == 1 ? DateUtils.roundYear(utcMillis) : DateUtils.roundYearInterval(utcMillis, multiplier);
assert multiplier == 1;
return DateUtils.roundYear(utcMillis);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please confirm my understanding that this check was showing in profile?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that one specifically, but the equivalent for WEEK_OF_YEAR, in particular I see the cost of roundWeekIntervalOfWeekYear(). It's smaller than the slowdown we are seeing in the nightlies though.
My doubt is that these methods are really small, so they are probably hard to sample and catch in flamegraphs.
On the other hand, in the commit diff there is really nothing apart from this change (all the rest is tests), so this is my only candidate...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My doubt is that these methods are really small, so they are probably hard to sample and catch in flamegraphs.

If they're small but called a lot, I would statistically expect them to still show up.

}

@Override
Expand All @@ -87,9 +89,8 @@ long extraLocalOffsetLookup() {

@Override
long roundFloor(long utcMillis, int multiplier) {
return multiplier == 1
? DateUtils.roundQuarterOfYear(utcMillis)
: DateUtils.roundIntervalMonthOfYear(utcMillis, multiplier * 3);
assert multiplier == 1;
return DateUtils.roundQuarterOfYear(utcMillis);
}

@Override
Expand All @@ -102,7 +103,8 @@ long extraLocalOffsetLookup() {

@Override
long roundFloor(long utcMillis, int multiplier) {
return multiplier == 1 ? DateUtils.roundMonthOfYear(utcMillis) : DateUtils.roundIntervalMonthOfYear(utcMillis, multiplier);
assert multiplier == 1;
return DateUtils.roundMonthOfYear(utcMillis);
}

@Override
Expand All @@ -113,7 +115,8 @@ long extraLocalOffsetLookup() {
DAY_OF_MONTH((byte) 5, "day", ChronoField.DAY_OF_MONTH, true, ChronoField.DAY_OF_MONTH.getBaseUnit().getDuration().toMillis()) {
@Override
long roundFloor(long utcMillis, int multiplier) {
return DateUtils.roundFloor(utcMillis, this.ratio * multiplier);
assert multiplier == 1;
return DateUtils.roundFloor(utcMillis, this.ratio);
}

@Override
Expand All @@ -124,15 +127,16 @@ long extraLocalOffsetLookup() {
HOUR_OF_DAY((byte) 6, "hour", ChronoField.HOUR_OF_DAY, true, ChronoField.HOUR_OF_DAY.getBaseUnit().getDuration().toMillis()) {
@Override
long roundFloor(long utcMillis, int multiplier) {
return DateUtils.roundFloor(utcMillis, ratio * multiplier);
assert multiplier == 1;
return DateUtils.roundFloor(utcMillis, ratio);
}

@Override
long extraLocalOffsetLookup() {
return ratio;
}
},
MINUTES_OF_HOUR(
MINUTE_OF_HOUR(
(byte) 7,
"minute",
ChronoField.MINUTE_OF_HOUR,
Expand All @@ -141,7 +145,8 @@ long extraLocalOffsetLookup() {
) {
@Override
long roundFloor(long utcMillis, int multiplier) {
return DateUtils.roundFloor(utcMillis, ratio * multiplier);
assert multiplier == 1;
return DateUtils.roundFloor(utcMillis, ratio);
}

@Override
Expand All @@ -158,13 +163,40 @@ long extraLocalOffsetLookup() {
) {
@Override
long roundFloor(long utcMillis, int multiplier) {
return DateUtils.roundFloor(utcMillis, ratio * multiplier);
assert multiplier == 1;
return DateUtils.roundFloor(utcMillis, ratio);
}

@Override
long extraLocalOffsetLookup() {
return ratio;
}
},
YEARS_OF_CENTURY((byte) 9, "years", ChronoField.YEAR_OF_ERA, false, 12) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to add these two new enums to the tests?

private final long extraLocalOffsetLookup = TimeUnit.DAYS.toMillis(366);

@Override
long roundFloor(long utcMillis, int multiplier) {
return multiplier == 1 ? DateUtils.roundYear(utcMillis) : DateUtils.roundYearInterval(utcMillis, multiplier);
}

@Override
long extraLocalOffsetLookup() {
return extraLocalOffsetLookup;
}
},
MONTHS_OF_YEAR((byte) 10, "months", ChronoField.MONTH_OF_YEAR, false, 1) {
private final long extraLocalOffsetLookup = TimeUnit.DAYS.toMillis(31);

@Override
long roundFloor(long utcMillis, int multiplier) {
return multiplier == 1 ? DateUtils.roundMonthOfYear(utcMillis) : DateUtils.roundIntervalMonthOfYear(utcMillis, multiplier);
}

@Override
long extraLocalOffsetLookup() {
return extraLocalOffsetLookup;
}
};

private final byte id;
Expand Down Expand Up @@ -222,8 +254,10 @@ public static DateTimeUnit resolve(byte id) {
case 4 -> MONTH_OF_YEAR;
case 5 -> DAY_OF_MONTH;
case 6 -> HOUR_OF_DAY;
case 7 -> MINUTES_OF_HOUR;
case 7 -> MINUTE_OF_HOUR;
case 8 -> SECOND_OF_MINUTE;
case 9 -> YEARS_OF_CENTURY;
case 10 -> MONTHS_OF_YEAR;
default -> throw new ElasticsearchException("Unknown date time unit id [" + id + "]");
};
}
Expand Down Expand Up @@ -480,7 +514,7 @@ private LocalDateTime truncateLocalDateTime(LocalDateTime localDateTime) {
case SECOND_OF_MINUTE:
return localDateTime.withNano(0);

case MINUTES_OF_HOUR:
case MINUTE_OF_HOUR:
return LocalDateTime.of(
localDateTime.getYear(),
localDateTime.getMonthValue(),
Expand Down Expand Up @@ -517,6 +551,12 @@ private LocalDateTime truncateLocalDateTime(LocalDateTime localDateTime) {
case YEAR_OF_CENTURY:
return LocalDateTime.of(LocalDate.of(localDateTime.getYear(), 1, 1), LocalTime.MIDNIGHT);

case YEARS_OF_CENTURY:
return LocalDateTime.of(LocalDate.of(localDateTime.getYear(), 1, 1), LocalTime.MIDNIGHT);

case MONTHS_OF_YEAR:
return LocalDateTime.of(localDateTime.getYear(), localDateTime.getMonthValue(), 1, 0, 0);

default:
throw new IllegalArgumentException("NOT YET IMPLEMENTED for unit " + unit);
}
Expand Down Expand Up @@ -879,6 +919,8 @@ private LocalDateTime nextRelevantMidnight(LocalDateTime localMidnight) {
case MONTH_OF_YEAR -> localMidnight.plus(1, ChronoUnit.MONTHS);
case QUARTER_OF_YEAR -> localMidnight.plus(3, ChronoUnit.MONTHS);
case YEAR_OF_CENTURY -> localMidnight.plus(1, ChronoUnit.YEARS);
case YEARS_OF_CENTURY -> localMidnight.plus(1, ChronoUnit.YEARS);
case MONTHS_OF_YEAR -> localMidnight.plus(1, ChronoUnit.MONTHS);
default -> throw new IllegalArgumentException("Unknown round-to-midnight unit: " + unit);
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,24 +479,7 @@ public static long roundYearInterval(final long utcMillis, final int yearInterva
* @return The milliseconds since the epoch rounded down to the beginning of the week based on week year
*/
public static long roundWeekOfWeekYear(final long utcMillis) {
return roundWeekIntervalOfWeekYear(utcMillis, 1);
}

/**
* Round down to the beginning of the nearest multiple of the specified week interval based on week year
* <p>
* Consider Sun Dec 29 1969 00:00:00.000 as the start of the first week.
* @param utcMillis the milliseconds since the epoch
* @param weekInterval the interval in weeks to round down to
*
* @return The milliseconds since the epoch rounded down to the beginning of the nearest multiple of the
* specified week interval based on week year
*/
public static long roundWeekIntervalOfWeekYear(final long utcMillis, final int weekInterval) {
if (weekInterval <= 0) {
throw new IllegalArgumentException("week interval must be strictly positive, got [" + weekInterval + "]");
}
return roundFloor(utcMillis + 3 * 86400 * 1000L, 604800000L * weekInterval) - 3 * 86400 * 1000L;
return roundFloor(utcMillis + 3 * 86400 * 1000L, 604800000L) - 3 * 86400 * 1000L;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@ public class DateHistogramAggregationBuilder extends ValuesSourceAggregationBuil
entry("1d", Rounding.DateTimeUnit.DAY_OF_MONTH),
entry("hour", Rounding.DateTimeUnit.HOUR_OF_DAY),
entry("1h", Rounding.DateTimeUnit.HOUR_OF_DAY),
entry("minute", Rounding.DateTimeUnit.MINUTES_OF_HOUR),
entry("1m", Rounding.DateTimeUnit.MINUTES_OF_HOUR),
entry("minute", Rounding.DateTimeUnit.MINUTE_OF_HOUR),
entry("1m", Rounding.DateTimeUnit.MINUTE_OF_HOUR),
entry("second", Rounding.DateTimeUnit.SECOND_OF_MINUTE),
entry("1s", Rounding.DateTimeUnit.SECOND_OF_MINUTE)
entry("1s", Rounding.DateTimeUnit.SECOND_OF_MINUTE),
entry("years", Rounding.DateTimeUnit.YEARS_OF_CENTURY),
entry("months", Rounding.DateTimeUnit.MONTHS_OF_YEAR)
);

public static final ObjectParser<DateHistogramAggregationBuilder, String> PARSER = ObjectParser.fromBuilder(
Expand Down
15 changes: 6 additions & 9 deletions server/src/test/java/org/elasticsearch/common/RoundingTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void testUTCTimeUnitRounding() {
assertThat(tzRounding.round(time("2012-01-10T01:01:01")), isDate(time("2012-01-01T00:00:00.000Z"), tz));
assertThat(tzRounding.nextRoundingValue(time("2012-01-09T00:00:00.000Z")), isDate(time("2013-01-01T00:00:00.000Z"), tz));

tzRounding = Rounding.builder(Rounding.DateTimeUnit.MINUTES_OF_HOUR).build();
tzRounding = Rounding.builder(Rounding.DateTimeUnit.MINUTE_OF_HOUR).build();
assertThat(tzRounding.round(time("2012-01-10T01:01:01")), isDate(time("2012-01-10T01:01:00.000Z"), tz));
assertThat(tzRounding.nextRoundingValue(time("2012-01-09T00:00:00.000Z")), isDate(time("2012-01-09T00:01:00.000Z"), tz));

Expand Down Expand Up @@ -656,7 +656,7 @@ public void testLenientConversionDST() {

long start = time("2014-10-18T20:50:00.000", tz);
long end = time("2014-10-19T01:00:00.000", tz);
Rounding tzRounding = new Rounding.TimeUnitRounding(Rounding.DateTimeUnit.MINUTES_OF_HOUR, tz);
Rounding tzRounding = new Rounding.TimeUnitRounding(Rounding.DateTimeUnit.MINUTE_OF_HOUR, tz);
Rounding dayTzRounding = new Rounding.TimeIntervalRounding(60000, tz);
for (long time = start; time < end; time = time + 60000) {
assertThat(tzRounding.nextRoundingValue(time), greaterThan(time));
Expand Down Expand Up @@ -1045,10 +1045,7 @@ public void testFixedIntervalRoundingSize() {
prepared.roundingSize(time("2015-01-01T00:00:00.000Z"), Rounding.DateTimeUnit.SECOND_OF_MINUTE),
closeTo(36000.0, 0.000001)
);
assertThat(
prepared.roundingSize(time("2015-01-01T00:00:00.000Z"), Rounding.DateTimeUnit.MINUTES_OF_HOUR),
closeTo(600.0, 0.000001)
);
assertThat(prepared.roundingSize(time("2015-01-01T00:00:00.000Z"), Rounding.DateTimeUnit.MINUTE_OF_HOUR), closeTo(600.0, 0.000001));
assertThat(prepared.roundingSize(time("2015-01-01T00:00:00.000Z"), Rounding.DateTimeUnit.HOUR_OF_DAY), closeTo(10.0, 0.000001));
assertThat(
prepared.roundingSize(time("2015-01-01T00:00:00.000Z"), Rounding.DateTimeUnit.DAY_OF_MONTH),
Expand Down Expand Up @@ -1101,8 +1098,8 @@ public void testMillisecondsBasedUnitCalendarRoundingSize() {
closeTo(3600.0, 0.000001)
);
assertThat(prepared.roundingSize(Rounding.DateTimeUnit.SECOND_OF_MINUTE), closeTo(3600.0, 0.000001));
assertThat(prepared.roundingSize(time("2015-01-01T00:00:00.000Z"), Rounding.DateTimeUnit.MINUTES_OF_HOUR), closeTo(60.0, 0.000001));
assertThat(prepared.roundingSize(Rounding.DateTimeUnit.MINUTES_OF_HOUR), closeTo(60.0, 0.000001));
assertThat(prepared.roundingSize(time("2015-01-01T00:00:00.000Z"), Rounding.DateTimeUnit.MINUTE_OF_HOUR), closeTo(60.0, 0.000001));
assertThat(prepared.roundingSize(Rounding.DateTimeUnit.MINUTE_OF_HOUR), closeTo(60.0, 0.000001));
assertThat(prepared.roundingSize(time("2015-01-01T00:00:00.000Z"), Rounding.DateTimeUnit.HOUR_OF_DAY), closeTo(1.0, 0.000001));
assertThat(prepared.roundingSize(Rounding.DateTimeUnit.HOUR_OF_DAY), closeTo(1.0, 0.000001));
assertThat(
Expand Down Expand Up @@ -1187,7 +1184,7 @@ public void testNonMillisecondsBasedUnitCalendarRoundingSize() {
assertThat(prepared.roundingSize(Rounding.DateTimeUnit.YEAR_OF_CENTURY), closeTo(0.25, 0.000001));
// Real interval based
assertThat(prepared.roundingSize(firstQuarter, Rounding.DateTimeUnit.SECOND_OF_MINUTE), closeTo(7776000.0, 0.000001));
assertThat(prepared.roundingSize(firstQuarter, Rounding.DateTimeUnit.MINUTES_OF_HOUR), closeTo(129600.0, 0.000001));
assertThat(prepared.roundingSize(firstQuarter, Rounding.DateTimeUnit.MINUTE_OF_HOUR), closeTo(129600.0, 0.000001));
assertThat(prepared.roundingSize(firstQuarter, Rounding.DateTimeUnit.HOUR_OF_DAY), closeTo(2160.0, 0.000001));
assertThat(prepared.roundingSize(firstQuarter, Rounding.DateTimeUnit.DAY_OF_MONTH), closeTo(90.0, 0.000001));
long thirdQuarter = prepared.round(time("2015-07-01T00:00:00.000Z"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,15 +313,7 @@ public void testRoundWeek() {
assertThat(DateUtils.roundWeekOfWeekYear(1), is(epochMilli));
assertThat(DateUtils.roundWeekOfWeekYear(-1), is(epochMilli));

IllegalArgumentException exc = expectThrows(IllegalArgumentException.class, () -> DateUtils.roundWeekIntervalOfWeekYear(0, -1));
assertThat(exc.getMessage(), is("week interval must be strictly positive, got [-1]"));
assertThat(DateUtils.roundWeekIntervalOfWeekYear(0, 3), is(epochMilli));
assertThat(DateUtils.roundWeekIntervalOfWeekYear(1, 3), is(epochMilli));
assertThat(DateUtils.roundWeekIntervalOfWeekYear(-1, 2), is(epochMilli));

epochMilli = Year.of(2025).atMonth(1).atDay(20).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli();
assertThat(DateUtils.roundWeekOfWeekYear(1737378896000L), is(epochMilli));
epochMilli = Year.of(2025).atMonth(1).atDay(13).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli();
assertThat(DateUtils.roundWeekIntervalOfWeekYear(1737378896000L, 4), is(epochMilli));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void testReductionSecond() {
}

public void testReductionMinute() {
testReduction(Rounding.DateTimeUnit.MINUTES_OF_HOUR, 0.01 * MILLIS_IN_MINUTE);
testReduction(Rounding.DateTimeUnit.MINUTE_OF_HOUR, 0.01 * MILLIS_IN_MINUTE);
}

public void testReductionHour() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,10 @@ public static long validateAndGetCalendarInterval(String calendarInterval) {
case WEEK_OF_WEEKYEAR -> new TimeValue(7, TimeUnit.DAYS);
case DAY_OF_MONTH -> new TimeValue(1, TimeUnit.DAYS);
case HOUR_OF_DAY -> new TimeValue(1, TimeUnit.HOURS);
case MINUTES_OF_HOUR -> new TimeValue(1, TimeUnit.MINUTES);
case MINUTE_OF_HOUR -> new TimeValue(1, TimeUnit.MINUTES);
case SECOND_OF_MINUTE -> new TimeValue(1, TimeUnit.SECONDS);
case MONTH_OF_YEAR, YEAR_OF_CENTURY, QUARTER_OF_YEAR -> throw ExceptionsHelper.badRequestException(
invalidDateHistogramCalendarIntervalMessage(calendarInterval)
);
case MONTH_OF_YEAR, YEAR_OF_CENTURY, QUARTER_OF_YEAR, YEARS_OF_CENTURY, MONTHS_OF_YEAR -> throw ExceptionsHelper
.badRequestException(invalidDateHistogramCalendarIntervalMessage(calendarInterval));
};
} else {
interval = TimeValue.parseTimeValue(calendarInterval, "date_histogram.calendar_interval");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,14 @@ private static Rounding.Prepared createRounding(final Period period, final ZoneI
// java.time.Period does not have a QUARTERLY period, so a period of 3 months
// returns a quarterly rounding
rounding = new Rounding.Builder(Rounding.DateTimeUnit.QUARTER_OF_YEAR);
} else if (period.getMonths() == 1) {
rounding = new Rounding.Builder(Rounding.DateTimeUnit.MONTH_OF_YEAR);
} else if (period.getMonths() > 0) {
rounding = new Rounding.Builder(Rounding.DateTimeUnit.MONTH_OF_YEAR, period.getMonths());
rounding = new Rounding.Builder(Rounding.DateTimeUnit.MONTHS_OF_YEAR, period.getMonths());
} else if (period.getYears() == 1) {
rounding = new Rounding.Builder(Rounding.DateTimeUnit.YEAR_OF_CENTURY);
} else if (period.getYears() > 0) {
rounding = new Rounding.Builder(Rounding.DateTimeUnit.YEAR_OF_CENTURY, period.getYears());
rounding = new Rounding.Builder(Rounding.DateTimeUnit.YEARS_OF_CENTURY, period.getYears());
} else {
throw new IllegalArgumentException("Time interval is not supported");
}
Expand Down
Loading