|
19 | 19 |
|
20 | 20 | package org.elasticsearch.search.aggregations.bucket.histogram; |
21 | 21 |
|
22 | | -import org.apache.lucene.index.IndexReader; |
23 | | -import org.apache.lucene.index.LeafReaderContext; |
24 | | -import org.apache.lucene.index.SortedNumericDocValues; |
25 | | -import org.apache.lucene.search.DocIdSetIterator; |
26 | 22 | import org.elasticsearch.common.Rounding; |
27 | 23 | import org.elasticsearch.common.io.stream.StreamInput; |
28 | 24 | import org.elasticsearch.common.io.stream.StreamOutput; |
29 | 25 | import org.elasticsearch.common.unit.TimeValue; |
30 | 26 | import org.elasticsearch.common.xcontent.ObjectParser; |
31 | 27 | import org.elasticsearch.common.xcontent.XContentBuilder; |
32 | 28 | import org.elasticsearch.common.xcontent.XContentParser; |
33 | | -import org.elasticsearch.index.fielddata.IndexNumericFieldData; |
34 | | -import org.elasticsearch.index.fielddata.LeafNumericFieldData; |
35 | | -import org.elasticsearch.index.mapper.DateFieldMapper; |
36 | | -import org.elasticsearch.index.mapper.MappedFieldType; |
37 | | -import org.elasticsearch.index.mapper.MappedFieldType.Relation; |
38 | 29 | import org.elasticsearch.index.query.QueryShardContext; |
39 | 30 | import org.elasticsearch.search.aggregations.AggregationBuilder; |
40 | 31 | import org.elasticsearch.search.aggregations.AggregatorFactories; |
|
50 | 41 | import org.elasticsearch.search.aggregations.support.ValuesSourceType; |
51 | 42 |
|
52 | 43 | import java.io.IOException; |
53 | | -import java.time.Instant; |
54 | 44 | import java.time.ZoneId; |
55 | | -import java.time.ZoneOffset; |
56 | | -import java.time.zone.ZoneOffsetTransition; |
57 | 45 | import java.util.HashMap; |
58 | 46 | import java.util.List; |
59 | 47 | import java.util.Map; |
@@ -407,144 +395,32 @@ public String getType() { |
407 | 395 | return NAME; |
408 | 396 | } |
409 | 397 |
|
410 | | - /** |
411 | | - * Returns a {@linkplain ZoneId} that functions the same as |
412 | | - * {@link #timeZone()} on the data in the shard referred to by |
413 | | - * {@code context}. It <strong>attempts</strong> to convert zones that |
414 | | - * have non-fixed offsets into fixed offset zones that produce the |
415 | | - * same results on all data in the shard. |
416 | | - * <p> |
417 | | - * We go about this in three phases: |
418 | | - * <ol> |
419 | | - * <li>A bunch of preflight checks to see if we *can* optimize it |
420 | | - * <li>Find the any Instant in shard |
421 | | - * <li>Find the DST transition before and after that Instant |
422 | | - * <li>Round those into the interval |
423 | | - * <li>Check if the rounded value include all values within shard |
424 | | - * <li>If they do then return a fixed offset time zone because it |
425 | | - * will return the same values for all time in the shard as the |
426 | | - * original time zone, but faster |
427 | | - * <li>Otherwise return the original time zone. It'll be slower, but |
428 | | - * correct. |
429 | | - * </ol> |
430 | | - * <p> |
431 | | - * NOTE: this can't be done in rewrite() because the timezone is then also used on the |
432 | | - * coordinating node in order to generate missing buckets, which may cross a transition |
433 | | - * even though data on the shards doesn't. |
434 | | - */ |
435 | | - ZoneId rewriteTimeZone(QueryShardContext context) throws IOException { |
436 | | - final ZoneId tz = timeZone(); |
437 | | - if (tz == null || tz.getRules().isFixedOffset()) { |
438 | | - // This time zone is already as fast as it is going to get. |
439 | | - return tz; |
440 | | - } |
441 | | - if (script() != null) { |
442 | | - // We can't be sure what dates the script will return so we don't attempt to optimize anything |
443 | | - return tz; |
444 | | - } |
445 | | - if (field() == null) { |
446 | | - // Without a field we're not going to be able to look anything up. |
447 | | - return tz; |
448 | | - } |
449 | | - MappedFieldType ft = context.fieldMapper(field()); |
450 | | - if (ft == null || false == ft instanceof DateFieldMapper.DateFieldType) { |
451 | | - // If the field is unmapped or not a date then we can't get its range. |
452 | | - return tz; |
453 | | - } |
454 | | - DateFieldMapper.DateFieldType dft = (DateFieldMapper.DateFieldType) ft; |
455 | | - final IndexReader reader = context.getIndexReader(); |
456 | | - if (reader == null) { |
457 | | - return tz; |
458 | | - } |
459 | | - |
460 | | - Instant instant = null; |
461 | | - final IndexNumericFieldData fieldData = context.getForField(ft); |
462 | | - for (LeafReaderContext ctx : reader.leaves()) { |
463 | | - LeafNumericFieldData leafFD = fieldData.load(ctx); |
464 | | - SortedNumericDocValues values = leafFD.getLongValues(); |
465 | | - if (values.nextDoc() != DocIdSetIterator.NO_MORE_DOCS) { |
466 | | - instant = Instant.ofEpochMilli(values.nextValue()); |
467 | | - break; |
468 | | - } |
469 | | - } |
470 | | - if (instant == null) { |
471 | | - return tz; |
472 | | - } |
473 | | - |
474 | | - ZoneOffsetTransition prevOffsetTransition = tz.getRules().previousTransition(instant); |
475 | | - final long prevTransition; |
476 | | - if (prevOffsetTransition != null) { |
477 | | - prevTransition = prevOffsetTransition.getInstant().toEpochMilli(); |
478 | | - } else { |
479 | | - prevTransition = instant.toEpochMilli(); |
480 | | - } |
481 | | - ZoneOffsetTransition nextOffsetTransition = tz.getRules().nextTransition(instant); |
482 | | - final long nextTransition; |
483 | | - if (nextOffsetTransition != null) { |
484 | | - nextTransition = nextOffsetTransition.getInstant().toEpochMilli(); |
485 | | - } else { |
486 | | - nextTransition = Long.MAX_VALUE; // fixed time-zone after prevTransition |
487 | | - } |
488 | | - |
489 | | - // We need all not only values but also rounded values to be within |
490 | | - // [prevTransition, nextTransition]. |
491 | | - final long low; |
492 | | - |
493 | | - DateIntervalWrapper.IntervalTypeEnum intervalType = dateHistogramInterval.getIntervalType(); |
494 | | - if (intervalType.equals(DateIntervalWrapper.IntervalTypeEnum.FIXED)) { |
495 | | - low = Math.addExact(prevTransition, dateHistogramInterval.tryIntervalAsFixedUnit().millis()); |
496 | | - } else if (intervalType.equals(DateIntervalWrapper.IntervalTypeEnum.CALENDAR)) { |
497 | | - final Rounding.DateTimeUnit intervalAsUnit = dateHistogramInterval.tryIntervalAsCalendarUnit(); |
498 | | - final Rounding rounding = Rounding.builder(intervalAsUnit).timeZone(timeZone()).build(); |
499 | | - low = rounding.nextRoundingValue(prevTransition); |
500 | | - } else { |
501 | | - // We're not sure what the interval was originally (legacy) so use old behavior of assuming |
502 | | - // calendar first, then fixed. Required because fixed/cal overlap in places ("1h") |
503 | | - Rounding.DateTimeUnit intervalAsUnit = dateHistogramInterval.tryIntervalAsCalendarUnit(); |
504 | | - if (intervalAsUnit != null) { |
505 | | - final Rounding rounding = Rounding.builder(intervalAsUnit).timeZone(timeZone()).build(); |
506 | | - low = rounding.nextRoundingValue(prevTransition); |
507 | | - } else { |
508 | | - final TimeValue intervalAsMillis = dateHistogramInterval.tryIntervalAsFixedUnit(); |
509 | | - low = Math.addExact(prevTransition, intervalAsMillis.millis()); |
510 | | - } |
511 | | - } |
512 | | - // rounding rounds down, so 'nextTransition' is a good upper bound |
513 | | - final long high = nextTransition; |
514 | | - |
515 | | - if (dft.isFieldWithinRange( |
516 | | - reader, Instant.ofEpochMilli(low), Instant.ofEpochMilli(high - 1)) == Relation.WITHIN) { |
517 | | - // All values in this reader have the same offset despite daylight saving times. |
518 | | - // This is very common for location-based timezones such as Europe/Paris in |
519 | | - // combination with time-based indices. |
520 | | - return ZoneOffset.ofTotalSeconds(tz.getRules().getOffset(instant).getTotalSeconds()); |
521 | | - } |
522 | | - return tz; |
523 | | - } |
524 | | - |
525 | 398 | @Override |
526 | 399 | protected ValuesSourceAggregatorFactory innerBuild(QueryShardContext queryShardContext, |
527 | 400 | ValuesSourceConfig config, |
528 | 401 | AggregatorFactory parent, |
529 | 402 | AggregatorFactories.Builder subFactoriesBuilder) throws IOException { |
530 | 403 | final ZoneId tz = timeZone(); |
531 | 404 | final Rounding rounding = dateHistogramInterval.createRounding(tz, offset); |
532 | | - // TODO once we optimize TimeIntervalRounding we won't need to rewrite the time zone |
533 | | - final ZoneId rewrittenTimeZone = rewriteTimeZone(queryShardContext); |
534 | | - final Rounding shardRounding; |
535 | | - if (tz == rewrittenTimeZone) { |
536 | | - shardRounding = rounding; |
537 | | - } else { |
538 | | - shardRounding = dateHistogramInterval.createRounding(rewrittenTimeZone, offset); |
539 | | - } |
540 | 405 |
|
541 | 406 | ExtendedBounds roundedBounds = null; |
542 | 407 | if (this.extendedBounds != null) { |
543 | 408 | // parse any string bounds to longs and round |
544 | 409 | roundedBounds = this.extendedBounds.parseAndValidate(name, queryShardContext, config.format()).round(rounding); |
545 | 410 | } |
546 | | - return new DateHistogramAggregatorFactory(name, config, order, keyed, minDocCount, |
547 | | - rounding, shardRounding, roundedBounds, queryShardContext, parent, subFactoriesBuilder, metadata); |
| 411 | + return new DateHistogramAggregatorFactory( |
| 412 | + name, |
| 413 | + config, |
| 414 | + order, |
| 415 | + keyed, |
| 416 | + minDocCount, |
| 417 | + rounding, |
| 418 | + roundedBounds, |
| 419 | + queryShardContext, |
| 420 | + parent, |
| 421 | + subFactoriesBuilder, |
| 422 | + metadata |
| 423 | + ); |
548 | 424 | } |
549 | 425 |
|
550 | 426 | @Override |
|
0 commit comments