From a1c99b90cb32d8550e1f9fe616f1cdc70151949d Mon Sep 17 00:00:00 2001 From: Bryan Burkholder Date: Thu, 21 Mar 2024 15:50:08 -0700 Subject: [PATCH] Improve ES query compatibility for Grafana 10 --- .../opensearch/BulkApiRequestParser.java | 3 - .../ElasticsearchApiService.java | 21 ++++ .../elasticsearchApi/OpenSearchRequest.java | 106 +++++++++++++++--- .../opensearch/OpenSearchAdapter.java | 39 +++++++ .../OpenSearchInternalAggregation.java | 10 ++ .../SchemaAwareLogDocumentBuilderImpl.java | 5 +- .../logstore/search/SearchResultUtils.java | 58 ++++++++++ .../AutoDateHistogramAggBuilder.java | 82 ++++++++++++++ .../aggregations/DateHistogramAggBuilder.java | 22 +++- kaldb/src/main/proto/kaldb_search.proto | 11 ++ .../opensearch/OpenSearchAdapterTest.java | 31 +++++ .../OpenSearchInternalAggregationTest.java | 29 ++++- .../search/LogIndexSearcherImplTest.java | 1 + .../SearchResultAggregatorImplTest.java | 1 + .../search/SearchResultUtilsTest.java | 29 +++++ .../AutoDateHistogramAggBuilderTest.java | 68 +++++++++++ .../DateHistogramAggBuilderTest.java | 39 ++++++- 17 files changed, 530 insertions(+), 25 deletions(-) create mode 100644 kaldb/src/main/java/com/slack/kaldb/logstore/search/aggregations/AutoDateHistogramAggBuilder.java create mode 100644 kaldb/src/test/java/com/slack/kaldb/logstore/search/aggregations/AutoDateHistogramAggBuilderTest.java diff --git a/kaldb/src/main/java/com/slack/kaldb/bulkIngestApi/opensearch/BulkApiRequestParser.java b/kaldb/src/main/java/com/slack/kaldb/bulkIngestApi/opensearch/BulkApiRequestParser.java index 8826c9650e..62763d9bb9 100644 --- a/kaldb/src/main/java/com/slack/kaldb/bulkIngestApi/opensearch/BulkApiRequestParser.java +++ b/kaldb/src/main/java/com/slack/kaldb/bulkIngestApi/opensearch/BulkApiRequestParser.java @@ -111,9 +111,6 @@ public static Trace.Span fromIngestDocument( // these fields don't need to be tags as they have been explicitly set already sourceAndMetadata.remove(IngestDocument.Metadata.ID.getFieldName()); sourceAndMetadata.remove(IngestDocument.Metadata.INDEX.getFieldName()); - sourceAndMetadata.remove("timestamp"); - sourceAndMetadata.remove("_timestamp"); - sourceAndMetadata.remove("@timestamp"); sourceAndMetadata.forEach( (key, value) -> spanBuilder.addTags(SpanFormatter.convertKVtoProto(key, value, schema))); diff --git a/kaldb/src/main/java/com/slack/kaldb/elasticsearchApi/ElasticsearchApiService.java b/kaldb/src/main/java/com/slack/kaldb/elasticsearchApi/ElasticsearchApiService.java index e2c279fd03..75e51bd388 100644 --- a/kaldb/src/main/java/com/slack/kaldb/elasticsearchApi/ElasticsearchApiService.java +++ b/kaldb/src/main/java/com/slack/kaldb/elasticsearchApi/ElasticsearchApiService.java @@ -61,6 +61,27 @@ public ElasticsearchApiService(KaldbQueryServiceBase searcher) { this.searcher = searcher; } + /** Returns metadata about the cluster */ + @Get + @Path("/") + public HttpResponse clusterMetadata() { + // todo - expand this to automatically pull in build info + // example - https://opensearch.org/docs/2.3/quickstart/ + // number must validate with npm semver validate for grafana compatibility due to + // https://github.com/grafana/grafana/blob/f74d5ff93ebe61e090994162be9b08bafcd5b7f0/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.tsx#L54 + return HttpResponse.of( + """ + { + "version": + { + "distribution": "astra", + "number": "0.0.1", + "lucene_version": "9.7.0" + } + } + """); + } + /** * Multisearch API * diff --git a/kaldb/src/main/java/com/slack/kaldb/elasticsearchApi/OpenSearchRequest.java b/kaldb/src/main/java/com/slack/kaldb/elasticsearchApi/OpenSearchRequest.java index fa2de9f7f4..28d87cbcc5 100644 --- a/kaldb/src/main/java/com/slack/kaldb/elasticsearchApi/OpenSearchRequest.java +++ b/kaldb/src/main/java/com/slack/kaldb/elasticsearchApi/OpenSearchRequest.java @@ -7,6 +7,7 @@ import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.slack.kaldb.logstore.search.SearchResultUtils; +import com.slack.kaldb.logstore.search.aggregations.AutoDateHistogramAggBuilder; import com.slack.kaldb.logstore.search.aggregations.AvgAggBuilder; import com.slack.kaldb.logstore.search.aggregations.CumulativeSumAggBuilder; import com.slack.kaldb.logstore.search.aggregations.DateHistogramAggBuilder; @@ -120,28 +121,74 @@ private static List getRecursive(Js .fieldNames() .forEachRemaining( aggregationObject -> { - if (aggregationObject.equals(DateHistogramAggBuilder.TYPE)) { - JsonNode dateHistogram = aggs.get(aggregationName).get(aggregationObject); + if (aggregationObject.equals(AutoDateHistogramAggBuilder.TYPE)) { + JsonNode autoDateHistogram = + aggs.get(aggregationName).get(aggregationObject); aggBuilder - .setType(DateHistogramAggBuilder.TYPE) + .setType(AutoDateHistogramAggBuilder.TYPE) .setName(aggregationName) .setValueSource( KaldbSearch.SearchRequest.SearchAggregation.ValueSourceAggregation .newBuilder() - .setField(getFieldName(dateHistogram)) - .setDateHistogram( + .setField(getFieldName(autoDateHistogram)) + .setAutoDateHistogram( KaldbSearch.SearchRequest.SearchAggregation - .ValueSourceAggregation.DateHistogramAggregation + .ValueSourceAggregation.AutoDateHistogramAggregation .newBuilder() - .setMinDocCount( - getDateHistogramMinDocCount(dateHistogram)) - .setInterval(getDateHistogramInterval(dateHistogram)) - .putAllExtendedBounds( - getDateHistogramExtendedBounds(dateHistogram)) - .setFormat(getDateHistogramFormat(dateHistogram)) - .setOffset(getDateHistogramOffset(dateHistogram)) + .setMinInterval( + SearchResultUtils.toValueProto( + getAutoDateHistogramMinInterval( + autoDateHistogram))) + .setNumBuckets( + SearchResultUtils.toValueProto( + getAutoDateHistogramNumBuckets( + autoDateHistogram))) .build()) .build()); + } else if (aggregationObject.equals(DateHistogramAggBuilder.TYPE)) { + JsonNode dateHistogram = aggs.get(aggregationName).get(aggregationObject); + if (getDateHistogramInterval(dateHistogram).equals("auto")) { + // if using "auto" type, default to using AutoDateHistogram as "auto" is + // not a valid interval for DateHistogramAggBuilder + aggBuilder + .setType(AutoDateHistogramAggBuilder.TYPE) + .setName(aggregationName) + .setValueSource( + KaldbSearch.SearchRequest.SearchAggregation + .ValueSourceAggregation.newBuilder() + .setField(getFieldName(dateHistogram)) + .build()); + } else { + + KaldbSearch.SearchRequest.SearchAggregation.ValueSourceAggregation + .DateHistogramAggregation.Builder + dateHistogramBuilder = + KaldbSearch.SearchRequest.SearchAggregation + .ValueSourceAggregation.DateHistogramAggregation + .newBuilder() + .setMinDocCount(getDateHistogramMinDocCount(dateHistogram)) + .setInterval(getDateHistogramInterval(dateHistogram)) + .putAllExtendedBounds( + getDateHistogramExtendedBounds(dateHistogram)) + .setFormat(getDateHistogramFormat(dateHistogram)) + .setOffset(getDateHistogramOffset(dateHistogram)); + + String zoneId = getDateHistogramZoneId(dateHistogram); + if (zoneId != null) { + dateHistogramBuilder.setZoneId( + SearchResultUtils.toValueProto(zoneId)); + } + + aggBuilder + .setType(DateHistogramAggBuilder.TYPE) + .setName(aggregationName) + .setValueSource( + KaldbSearch.SearchRequest.SearchAggregation + .ValueSourceAggregation.newBuilder() + .setField(getFieldName(dateHistogram)) + .setDateHistogram(dateHistogramBuilder.build()) + .build()); + } } else if (aggregationObject.equals(FiltersAggBuilder.TYPE)) { JsonNode filters = aggs.get(aggregationName).get(aggregationObject); @@ -440,11 +487,26 @@ private static List getRecursive(Js } private static String getDateHistogramInterval(JsonNode dateHistogram) { - return dateHistogram.get("interval").asText(); + if (dateHistogram.has("fixed_interval")) { + return dateHistogram.get("fixed_interval").asText(); + } else if (dateHistogram.has("interval")) { + return dateHistogram.get("interval").asText(); + } + return "auto"; + } + + private static String getDateHistogramZoneId(JsonNode dateHistogram) { + if (dateHistogram.has("time_zone")) { + return dateHistogram.get("time_zone").asText(); + } + return null; } private static String getHistogramInterval(JsonNode dateHistogram) { - return dateHistogram.get("interval").asText(); + if (dateHistogram.has("interval")) { + return dateHistogram.get("interval").asText(); + } + return "auto"; } private static String getFieldName(JsonNode agg) { @@ -539,6 +601,20 @@ private static String getDateHistogramOffset(JsonNode dateHistogram) { return ""; } + private static Integer getAutoDateHistogramNumBuckets(JsonNode autoDateHistogram) { + if (autoDateHistogram.has("buckets")) { + return autoDateHistogram.get("buckets").asInt(); + } + return null; + } + + private static String getAutoDateHistogramMinInterval(JsonNode autoDateHistogram) { + if (autoDateHistogram.has("minimum_interval")) { + return autoDateHistogram.get("minimum_interval").asText(); + } + return null; + } + private static String getFormat(JsonNode cumulateSum) { if (cumulateSum.has("format")) { return cumulateSum.get("format").asText(); diff --git a/kaldb/src/main/java/com/slack/kaldb/logstore/opensearch/OpenSearchAdapter.java b/kaldb/src/main/java/com/slack/kaldb/logstore/opensearch/OpenSearchAdapter.java index 07d684a6d1..02f7b429a6 100644 --- a/kaldb/src/main/java/com/slack/kaldb/logstore/opensearch/OpenSearchAdapter.java +++ b/kaldb/src/main/java/com/slack/kaldb/logstore/opensearch/OpenSearchAdapter.java @@ -7,6 +7,7 @@ import com.slack.kaldb.logstore.LogMessage; import com.slack.kaldb.logstore.search.aggregations.AggBuilder; import com.slack.kaldb.logstore.search.aggregations.AggBuilderBase; +import com.slack.kaldb.logstore.search.aggregations.AutoDateHistogramAggBuilder; import com.slack.kaldb.logstore.search.aggregations.AvgAggBuilder; import com.slack.kaldb.logstore.search.aggregations.CumulativeSumAggBuilder; import com.slack.kaldb.logstore.search.aggregations.DateHistogramAggBuilder; @@ -26,6 +27,7 @@ import com.slack.kaldb.metadata.schema.LuceneFieldDef; import java.io.IOException; import java.time.Instant; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -71,6 +73,7 @@ import org.opensearch.search.aggregations.InternalAggregation; import org.opensearch.search.aggregations.bucket.filter.FiltersAggregationBuilder; import org.opensearch.search.aggregations.bucket.filter.FiltersAggregator; +import org.opensearch.search.aggregations.bucket.histogram.AutoDateHistogramAggregationBuilder; import org.opensearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder; import org.opensearch.search.aggregations.bucket.histogram.DateHistogramInterval; import org.opensearch.search.aggregations.bucket.histogram.HistogramAggregationBuilder; @@ -316,6 +319,7 @@ public InternalAggregation reduce(Collection collectors) throws IOEx private static ValuesSourceRegistry buildValueSourceRegistry() { ValuesSourceRegistry.Builder valuesSourceRegistryBuilder = new ValuesSourceRegistry.Builder(); + AutoDateHistogramAggregationBuilder.registerAggregators(valuesSourceRegistryBuilder); DateHistogramAggregationBuilder.registerAggregators(valuesSourceRegistryBuilder); HistogramAggregationBuilder.registerAggregators(valuesSourceRegistryBuilder); TermsAggregationBuilder.registerAggregators(valuesSourceRegistryBuilder); @@ -484,6 +488,8 @@ public Aggregator buildAggregatorUsingContext( public static AbstractAggregationBuilder getAggregationBuilder(AggBuilder aggBuilder) { if (aggBuilder.getType().equals(DateHistogramAggBuilder.TYPE)) { return getDateHistogramAggregationBuilder((DateHistogramAggBuilder) aggBuilder); + } else if (aggBuilder.getType().equals(AutoDateHistogramAggBuilder.TYPE)) { + return getAutoDateHistogramAggregationBuilder((AutoDateHistogramAggBuilder) aggBuilder); } else if (aggBuilder.getType().equals(HistogramAggBuilder.TYPE)) { return getHistogramAggregationBuilder((HistogramAggBuilder) aggBuilder); } else if (aggBuilder.getType().equals(FiltersAggBuilder.TYPE)) { @@ -909,6 +915,35 @@ protected static FiltersAggregationBuilder getFiltersAggregationBuilder( return filtersAggregationBuilder; } + /** + * Given an AutoDateHistogramAggBuilder returns a AutoDateHistogramAggBuilder to be used in + * building aggregation tree + */ + protected static AutoDateHistogramAggregationBuilder getAutoDateHistogramAggregationBuilder( + AutoDateHistogramAggBuilder builder) { + AutoDateHistogramAggregationBuilder autoDateHistogramAggregationBuilder = + new AutoDateHistogramAggregationBuilder(builder.getName()).field(builder.getField()); + + if (builder.getMinInterval() != null && !builder.getMinInterval().isEmpty()) { + autoDateHistogramAggregationBuilder.setMinimumIntervalExpression(builder.getMinInterval()); + } + + if (builder.getNumBuckets() != null && builder.getNumBuckets() > 0) { + autoDateHistogramAggregationBuilder.setNumBuckets(builder.getNumBuckets()); + } + + for (AggBuilder subAggregation : builder.getSubAggregations()) { + if (isPipelineAggregation(subAggregation)) { + autoDateHistogramAggregationBuilder.subAggregation( + getPipelineAggregationBuilder(subAggregation)); + } else { + autoDateHistogramAggregationBuilder.subAggregation(getAggregationBuilder(subAggregation)); + } + } + + return autoDateHistogramAggregationBuilder; + } + /** * Given an DateHistogramAggBuilder returns a DateHistogramAggregationBuilder to be used in * building aggregation tree @@ -931,6 +966,10 @@ protected static DateHistogramAggregationBuilder getDateHistogramAggregationBuil // dateHistogramAggregationBuilder.format(builder.getFormat()); } + if (builder.getZoneId() != null && !builder.getZoneId().isEmpty()) { + dateHistogramAggregationBuilder.timeZone(ZoneId.of(builder.getZoneId())); + } + if (builder.getMinDocCount() == 0) { if (builder.getExtendedBounds() != null && builder.getExtendedBounds().containsKey("min") diff --git a/kaldb/src/main/java/com/slack/kaldb/logstore/opensearch/OpenSearchInternalAggregation.java b/kaldb/src/main/java/com/slack/kaldb/logstore/opensearch/OpenSearchInternalAggregation.java index 2f21923a60..ac8f15ca69 100644 --- a/kaldb/src/main/java/com/slack/kaldb/logstore/opensearch/OpenSearchInternalAggregation.java +++ b/kaldb/src/main/java/com/slack/kaldb/logstore/opensearch/OpenSearchInternalAggregation.java @@ -18,8 +18,10 @@ import org.opensearch.search.aggregations.InternalAggregations; import org.opensearch.search.aggregations.bucket.filter.FiltersAggregationBuilder; import org.opensearch.search.aggregations.bucket.filter.InternalFilters; +import org.opensearch.search.aggregations.bucket.histogram.AutoDateHistogramAggregationBuilder; import org.opensearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder; import org.opensearch.search.aggregations.bucket.histogram.HistogramAggregationBuilder; +import org.opensearch.search.aggregations.bucket.histogram.InternalAutoDateHistogram; import org.opensearch.search.aggregations.bucket.histogram.InternalDateHistogram; import org.opensearch.search.aggregations.bucket.histogram.InternalHistogram; import org.opensearch.search.aggregations.bucket.terms.DoubleTerms; @@ -78,6 +80,14 @@ public class OpenSearchInternalAggregation { InternalAggregation.class, DateHistogramAggregationBuilder.NAME, InternalDateHistogram::new), + new NamedWriteableRegistry.Entry( + AggregationBuilder.class, + AutoDateHistogramAggregationBuilder.NAME, + AutoDateHistogramAggregationBuilder::new), + new NamedWriteableRegistry.Entry( + InternalAggregation.class, + AutoDateHistogramAggregationBuilder.NAME, + InternalAutoDateHistogram::new), new NamedWriteableRegistry.Entry( AggregationBuilder.class, FiltersAggregationBuilder.NAME, diff --git a/kaldb/src/main/java/com/slack/kaldb/logstore/schema/SchemaAwareLogDocumentBuilderImpl.java b/kaldb/src/main/java/com/slack/kaldb/logstore/schema/SchemaAwareLogDocumentBuilderImpl.java index 03b51f1691..93b8371f98 100644 --- a/kaldb/src/main/java/com/slack/kaldb/logstore/schema/SchemaAwareLogDocumentBuilderImpl.java +++ b/kaldb/src/main/java/com/slack/kaldb/logstore/schema/SchemaAwareLogDocumentBuilderImpl.java @@ -420,8 +420,12 @@ public Document fromMessage(Trace.Span message) throws JsonProcessingException { jsonMap.put( LogMessage.ReservedField.KALDB_INVALID_TIMESTAMP.fieldName, message.getTimestamp()); } + addField( doc, LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, timestamp.toEpochMilli(), "", 0); + // todo - this should be removed once we simplify the time handling + // this will be overridden below if a user provided value exists + jsonMap.put(LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, timestamp.toString()); Map tags = message.getTagsList().stream() @@ -459,7 +463,6 @@ public Document fromMessage(Trace.Span message) throws JsonProcessingException { tags.remove(LogMessage.ReservedField.NAME.fieldName); tags.remove(LogMessage.ReservedField.DURATION_MS.fieldName); tags.remove(LogMessage.SystemField.ID.fieldName); - tags.remove(LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName); for (Trace.KeyValue keyValue : tags.values()) { if (keyValue.getVType() == Trace.ValueType.STRING) { diff --git a/kaldb/src/main/java/com/slack/kaldb/logstore/search/SearchResultUtils.java b/kaldb/src/main/java/com/slack/kaldb/logstore/search/SearchResultUtils.java index 8af8b3a92c..200f27ef7c 100644 --- a/kaldb/src/main/java/com/slack/kaldb/logstore/search/SearchResultUtils.java +++ b/kaldb/src/main/java/com/slack/kaldb/logstore/search/SearchResultUtils.java @@ -8,6 +8,7 @@ import com.slack.kaldb.logstore.LogWireMessage; import com.slack.kaldb.logstore.opensearch.OpenSearchInternalAggregation; import com.slack.kaldb.logstore.search.aggregations.AggBuilder; +import com.slack.kaldb.logstore.search.aggregations.AutoDateHistogramAggBuilder; import com.slack.kaldb.logstore.search.aggregations.AvgAggBuilder; import com.slack.kaldb.logstore.search.aggregations.CumulativeSumAggBuilder; import com.slack.kaldb.logstore.search.aggregations.DateHistogramAggBuilder; @@ -208,12 +209,27 @@ public static AggBuilder fromSearchAggregations( searchAggregation.getValueSource().getField(), searchAggregation.getValueSource().getDateHistogram().getInterval(), searchAggregation.getValueSource().getDateHistogram().getOffset(), + (String) + fromValueProto(searchAggregation.getValueSource().getDateHistogram().getZoneId()), searchAggregation.getValueSource().getDateHistogram().getMinDocCount(), searchAggregation.getValueSource().getDateHistogram().getFormat(), searchAggregation.getValueSource().getDateHistogram().getExtendedBoundsMap(), searchAggregation.getSubAggregationsList().stream() .map(SearchResultUtils::fromSearchAggregations) .collect(Collectors.toList())); + } else if (searchAggregation.getType().equals(AutoDateHistogramAggBuilder.TYPE)) { + return new AutoDateHistogramAggBuilder( + searchAggregation.getName(), + searchAggregation.getValueSource().getField(), + (String) + fromValueProto( + searchAggregation.getValueSource().getAutoDateHistogram().getMinInterval()), + (Integer) + fromValueProto( + searchAggregation.getValueSource().getAutoDateHistogram().getNumBuckets()), + searchAggregation.getSubAggregationsList().stream() + .map(SearchResultUtils::fromSearchAggregations) + .collect(Collectors.toList())); } else if (searchAggregation.getType().equals(FiltersAggBuilder.TYPE)) { return new FiltersAggBuilder( searchAggregation.getName(), @@ -508,6 +524,12 @@ public static KaldbSearch.SearchRequest.SearchAggregation toSearchAggregationPro dateHistogramAggregationBuilder.setFormat(dateHistogramAggBuilder.getFormat()); } + if (dateHistogramAggBuilder.getZoneId() != null + && !dateHistogramAggBuilder.getZoneId().isEmpty()) { + dateHistogramAggregationBuilder.setZoneId( + toValueProto(dateHistogramAggBuilder.getZoneId())); + } + return KaldbSearch.SearchRequest.SearchAggregation.newBuilder() .setType(DateHistogramAggBuilder.TYPE) .setName(dateHistogramAggBuilder.getName()) @@ -521,6 +543,42 @@ public static KaldbSearch.SearchRequest.SearchAggregation toSearchAggregationPro .setDateHistogram(dateHistogramAggregationBuilder.build()) .build()) .build(); + + } else if (aggBuilder instanceof AutoDateHistogramAggBuilder) { + AutoDateHistogramAggBuilder autoDateHistogramAggBuilder = + (AutoDateHistogramAggBuilder) aggBuilder; + + KaldbSearch.SearchRequest.SearchAggregation.ValueSourceAggregation + .AutoDateHistogramAggregation.Builder + autoDateHistogramAggregationBuilder = + KaldbSearch.SearchRequest.SearchAggregation.ValueSourceAggregation + .AutoDateHistogramAggregation.newBuilder(); + + if (autoDateHistogramAggBuilder.getNumBuckets() != null + && autoDateHistogramAggBuilder.getNumBuckets() > 0) { + autoDateHistogramAggregationBuilder.setNumBuckets( + toValueProto(autoDateHistogramAggBuilder.getNumBuckets())); + } + + if (autoDateHistogramAggBuilder.getMinInterval() != null + && !autoDateHistogramAggBuilder.getMinInterval().isEmpty()) { + autoDateHistogramAggregationBuilder.setMinInterval( + toValueProto(autoDateHistogramAggBuilder.getMinInterval())); + } + + return KaldbSearch.SearchRequest.SearchAggregation.newBuilder() + .setType(AutoDateHistogramAggBuilder.TYPE) + .setName(autoDateHistogramAggBuilder.getName()) + .addAllSubAggregations( + autoDateHistogramAggBuilder.getSubAggregations().stream() + .map(SearchResultUtils::toSearchAggregationProto) + .collect(Collectors.toList())) + .setValueSource( + KaldbSearch.SearchRequest.SearchAggregation.ValueSourceAggregation.newBuilder() + .setField(autoDateHistogramAggBuilder.getField()) + .setAutoDateHistogram(autoDateHistogramAggregationBuilder.build()) + .build()) + .build(); } else if (aggBuilder instanceof FiltersAggBuilder) { FiltersAggBuilder filtersAggBuilder = (FiltersAggBuilder) aggBuilder; diff --git a/kaldb/src/main/java/com/slack/kaldb/logstore/search/aggregations/AutoDateHistogramAggBuilder.java b/kaldb/src/main/java/com/slack/kaldb/logstore/search/aggregations/AutoDateHistogramAggBuilder.java new file mode 100644 index 0000000000..bd29430f29 --- /dev/null +++ b/kaldb/src/main/java/com/slack/kaldb/logstore/search/aggregations/AutoDateHistogramAggBuilder.java @@ -0,0 +1,82 @@ +package com.slack.kaldb.logstore.search.aggregations; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** Aggregation request type to form an automatic histogram bucketed by a timestamp */ +public class AutoDateHistogramAggBuilder extends ValueSourceAggBuilder { + public static final String TYPE = "auto_date_histogram"; + private final String minInterval; + private final Integer numBuckets; + + public AutoDateHistogramAggBuilder( + String name, + String fieldName, + String minInterval, + Integer numBuckets, + List subAggregations) { + // todo - metadata? + super(name, Map.of(), subAggregations, fieldName); + + this.minInterval = minInterval; + this.numBuckets = numBuckets; + } + + public String getMinInterval() { + return minInterval; + } + + public Integer getNumBuckets() { + return numBuckets; + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AutoDateHistogramAggBuilder that)) return false; + if (!super.equals(o)) return false; + + if (!Objects.equals(minInterval, that.minInterval)) return false; + return Objects.equals(numBuckets, that.numBuckets); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (minInterval != null ? minInterval.hashCode() : 0); + result = 31 * result + (numBuckets != null ? numBuckets.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "AutoDateHistogramAggBuilder{" + + "minInterval='" + + minInterval + + '\'' + + ", numBuckets=" + + numBuckets + + ", field='" + + field + + '\'' + + ", missing=" + + missing + + ", script='" + + script + + '\'' + + ", name='" + + name + + '\'' + + ", metadata=" + + metadata + + ", subAggregations=" + + subAggregations + + '}'; + } +} diff --git a/kaldb/src/main/java/com/slack/kaldb/logstore/search/aggregations/DateHistogramAggBuilder.java b/kaldb/src/main/java/com/slack/kaldb/logstore/search/aggregations/DateHistogramAggBuilder.java index 632a20e395..f85044eee2 100644 --- a/kaldb/src/main/java/com/slack/kaldb/logstore/search/aggregations/DateHistogramAggBuilder.java +++ b/kaldb/src/main/java/com/slack/kaldb/logstore/search/aggregations/DateHistogramAggBuilder.java @@ -9,6 +9,7 @@ public class DateHistogramAggBuilder extends ValueSourceAggBuilder { public static final String TYPE = "date_histogram"; private final String interval; private final String offset; + private final String zoneId; private final long minDocCount; private final String format; @@ -20,6 +21,7 @@ public DateHistogramAggBuilder(String name, String fieldName, String interval) { this.interval = interval; this.offset = ""; + this.zoneId = null; this.minDocCount = 1; this.format = null; this.extendedBounds = Map.of(); @@ -30,6 +32,7 @@ public DateHistogramAggBuilder( String fieldName, String interval, String offset, + String zoneId, long minDocCount, String format, Map extendedBounds, @@ -39,6 +42,7 @@ public DateHistogramAggBuilder( this.interval = interval; this.offset = offset; + this.zoneId = zoneId; this.minDocCount = minDocCount; this.format = format; this.extendedBounds = extendedBounds; @@ -48,6 +52,10 @@ public String getInterval() { return interval; } + public String getZoneId() { + return zoneId; + } + public String getOffset() { return offset; } @@ -72,14 +80,13 @@ public String getType() { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof DateHistogramAggBuilder)) return false; + if (!(o instanceof DateHistogramAggBuilder that)) return false; if (!super.equals(o)) return false; - DateHistogramAggBuilder that = (DateHistogramAggBuilder) o; - if (minDocCount != that.minDocCount) return false; if (!interval.equals(that.interval)) return false; if (!Objects.equals(offset, that.offset)) return false; + if (!Objects.equals(zoneId, that.zoneId)) return false; if (!Objects.equals(format, that.format)) return false; return Objects.equals(extendedBounds, that.extendedBounds); } @@ -89,6 +96,7 @@ public int hashCode() { int result = super.hashCode(); result = 31 * result + interval.hashCode(); result = 31 * result + (offset != null ? offset.hashCode() : 0); + result = 31 * result + (zoneId != null ? zoneId.hashCode() : 0); result = 31 * result + (int) (minDocCount ^ (minDocCount >>> 32)); result = 31 * result + (format != null ? format.hashCode() : 0); result = 31 * result + (extendedBounds != null ? extendedBounds.hashCode() : 0); @@ -104,6 +112,9 @@ public String toString() { + ", offset='" + offset + '\'' + + ", zoneId='" + + zoneId + + '\'' + ", minDocCount=" + minDocCount + ", format='" @@ -114,6 +125,11 @@ public String toString() { + ", field='" + field + '\'' + + ", missing=" + + missing + + ", script='" + + script + + '\'' + ", name='" + name + '\'' diff --git a/kaldb/src/main/proto/kaldb_search.proto b/kaldb/src/main/proto/kaldb_search.proto index 18e559ac67..59f58bc4a3 100644 --- a/kaldb/src/main/proto/kaldb_search.proto +++ b/kaldb/src/main/proto/kaldb_search.proto @@ -67,6 +67,7 @@ message SearchRequest { DateHistogramAggregation date_histogram = 11; TermsAggregation terms = 12; HistogramAggregation histogram = 13; + AutoDateHistogramAggregation auto_date_histogram = 14; ExtendedStatsAggregation extended_stats = 15; UniqueCountAggregation unique_count = 16; PercentilesAggregation percentiles = 17; @@ -93,6 +94,16 @@ message SearchRequest { map extended_bounds = 4; // Format for the resulting buckets timestamps string format = 5; + // Date zoneId if requesting with timezone option + Value zoneId = 6; + } + + // Unique fields specific to the auto date histogram aggregation request + message AutoDateHistogramAggregation { + // Value representing the minimum interval of the bucket size (ie, day, hour) + Value min_interval = 1; + // Exact number of buckets required + Value num_buckets = 2; } // Unique fields specific to the terms aggregation request diff --git a/kaldb/src/test/java/com/slack/kaldb/logstore/opensearch/OpenSearchAdapterTest.java b/kaldb/src/test/java/com/slack/kaldb/logstore/opensearch/OpenSearchAdapterTest.java index 58e71f83b7..f756fb0666 100644 --- a/kaldb/src/test/java/com/slack/kaldb/logstore/opensearch/OpenSearchAdapterTest.java +++ b/kaldb/src/test/java/com/slack/kaldb/logstore/opensearch/OpenSearchAdapterTest.java @@ -7,6 +7,7 @@ import com.slack.kaldb.logstore.schema.SchemaAwareLogDocumentBuilderImpl; import com.slack.kaldb.logstore.search.aggregations.AggBuilder; import com.slack.kaldb.logstore.search.aggregations.AggBuilderBase; +import com.slack.kaldb.logstore.search.aggregations.AutoDateHistogramAggBuilder; import com.slack.kaldb.logstore.search.aggregations.AvgAggBuilder; import com.slack.kaldb.logstore.search.aggregations.CumulativeSumAggBuilder; import com.slack.kaldb.logstore.search.aggregations.DateHistogramAggBuilder; @@ -37,6 +38,7 @@ import org.opensearch.search.aggregations.AbstractAggregationBuilder; import org.opensearch.search.aggregations.Aggregator; import org.opensearch.search.aggregations.InternalAggregation; +import org.opensearch.search.aggregations.bucket.histogram.InternalAutoDateHistogram; import org.opensearch.search.aggregations.bucket.histogram.InternalDateHistogram; import org.opensearch.search.aggregations.bucket.histogram.InternalHistogram; import org.opensearch.search.aggregations.metrics.InternalAvg; @@ -236,6 +238,7 @@ public void canBuildValidDateHistogram() throws IOException { LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "5s", "2s", + null, 100, "epoch_ms", Map.of(), @@ -257,6 +260,29 @@ public void canBuildValidDateHistogram() throws IOException { } } + @Test + public void canBuildValidAutoDateHistogram() throws IOException { + AutoDateHistogramAggBuilder autoDateHistogramAggBuilder = + new AutoDateHistogramAggBuilder( + "foo", LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, null, null, List.of()); + + CollectorManager collectorManager = + openSearchAdapter.getCollectorManager( + autoDateHistogramAggBuilder, + logStoreAndSearcherRule.logStore.getSearcherManager().acquire(), + null); + + try (Aggregator autoDateHistogramAggregator = collectorManager.newCollector()) { + InternalAutoDateHistogram internalDateHistogram = + (InternalAutoDateHistogram) autoDateHistogramAggregator.buildTopLevel(); + + assertThat(internalDateHistogram.getName()).isEqualTo("foo"); + + // todo - we don't have access to the package local methods for extra asserts - use + // reflection? + } + } + @Test public void canBuildValidCumulativeSumPipelineAggregator() { DateHistogramAggBuilder dateHistogramWithCumulativeSum = @@ -265,6 +291,7 @@ public void canBuildValidCumulativeSumPipelineAggregator() { LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "5s", "2s", + null, 100, "epoch_ms", Map.of(), @@ -292,6 +319,7 @@ public void canBuildValidMovingFunctionPipelineAggregator() { LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "5s", "2s", + null, 100, "epoch_ms", Map.of(), @@ -319,6 +347,7 @@ public void canBuildValidMovingAveragePipelineAggregator() { LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "5s", "2s", + null, 100, "epoch_ms", Map.of(), @@ -346,6 +375,7 @@ public void canBuildValidDerivativePipelineAggregator() { LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "5s", "2s", + null, 100, "epoch_ms", Map.of(), @@ -392,6 +422,7 @@ public void handlesDateHistogramExtendedBoundsMinDocEdgeCases() throws IOExcepti LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "5s", "2s", + null, 0, "epoch_ms", Map.of(), diff --git a/kaldb/src/test/java/com/slack/kaldb/logstore/opensearch/OpenSearchInternalAggregationTest.java b/kaldb/src/test/java/com/slack/kaldb/logstore/opensearch/OpenSearchInternalAggregationTest.java index afa64f764a..9ebdf758d8 100644 --- a/kaldb/src/test/java/com/slack/kaldb/logstore/opensearch/OpenSearchInternalAggregationTest.java +++ b/kaldb/src/test/java/com/slack/kaldb/logstore/opensearch/OpenSearchInternalAggregationTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import com.slack.kaldb.logstore.LogMessage; +import com.slack.kaldb.logstore.search.aggregations.AutoDateHistogramAggBuilder; import com.slack.kaldb.logstore.search.aggregations.AvgAggBuilder; import com.slack.kaldb.logstore.search.aggregations.DateHistogramAggBuilder; import com.slack.kaldb.logstore.search.aggregations.HistogramAggBuilder; @@ -37,7 +38,7 @@ public void canSerializeDeserializeInternalDateHistogramAggregation() throws IOE new AvgAggBuilder("foo", LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "3", null); DateHistogramAggBuilder dateHistogramAggBuilder = new DateHistogramAggBuilder( - "foo", "epoch_ms", "10s", "5s", 10, "epoch_ms", Map.of(), List.of(avgAggBuilder)); + "foo", "epoch_ms", "10s", "5s", null, 10, "epoch_ms", Map.of(), List.of(avgAggBuilder)); CollectorManager collectorManager = openSearchAdapter.getCollectorManager( dateHistogramAggBuilder, @@ -58,6 +59,32 @@ public void canSerializeDeserializeInternalDateHistogramAggregation() throws IOE assertThat(internalAggregation1.toString()).isEqualTo(internalAggregation2.toString()); } + @Test + public void canSerializeDeserializeInternalAutoDateHistogramAggregation() throws IOException { + AvgAggBuilder avgAggBuilder = + new AvgAggBuilder("foo", LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "3", null); + AutoDateHistogramAggBuilder autoDateHistogramAggBuilder = + new AutoDateHistogramAggBuilder("foo", "epoch_ms", "day", 5, List.of(avgAggBuilder)); + CollectorManager collectorManager = + openSearchAdapter.getCollectorManager( + autoDateHistogramAggBuilder, + logStoreAndSearcherRule.logStore.getSearcherManager().acquire(), + null); + InternalAggregation internalAggregation1 = + collectorManager.reduce(Collections.singleton(collectorManager.newCollector())); + + byte[] serialize = OpenSearchInternalAggregation.toByteArray(internalAggregation1); + InternalAggregation internalAggregation2 = + OpenSearchInternalAggregation.fromByteArray(serialize); + + // todo - this is pending a PR to OpenSearch to address specific to histograms + // https://github.com/opensearch-project/OpenSearch/pull/6357 + // this is because DocValueFormat.DateTime in OpenSearch does not implement a proper equals + // method + // As such the DocValueFormat.parser are never equal to each other + assertThat(internalAggregation1.toString()).isEqualTo(internalAggregation2.toString()); + } + @Test public void canSerializeDeserializeInternalHistogramAggregation() throws IOException { AvgAggBuilder avgAggBuilder = diff --git a/kaldb/src/test/java/com/slack/kaldb/logstore/search/LogIndexSearcherImplTest.java b/kaldb/src/test/java/com/slack/kaldb/logstore/search/LogIndexSearcherImplTest.java index f3b182ba11..b33fd62788 100644 --- a/kaldb/src/test/java/com/slack/kaldb/logstore/search/LogIndexSearcherImplTest.java +++ b/kaldb/src/test/java/com/slack/kaldb/logstore/search/LogIndexSearcherImplTest.java @@ -947,6 +947,7 @@ public void testPipelineAggregation() { LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "1s", null, + null, 0, "epoch_ms", Map.of("min", 1593365471000L, "max", 1593365471000L + 5000L), diff --git a/kaldb/src/test/java/com/slack/kaldb/logstore/search/SearchResultAggregatorImplTest.java b/kaldb/src/test/java/com/slack/kaldb/logstore/search/SearchResultAggregatorImplTest.java index 6d178a91d0..7d83ce765a 100644 --- a/kaldb/src/test/java/com/slack/kaldb/logstore/search/SearchResultAggregatorImplTest.java +++ b/kaldb/src/test/java/com/slack/kaldb/logstore/search/SearchResultAggregatorImplTest.java @@ -552,6 +552,7 @@ private InternalAggregation makeHistogram( LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, interval, "0", + null, 0, "", Map.of("min", histogramStartMs, "max", histogramEndMs), diff --git a/kaldb/src/test/java/com/slack/kaldb/logstore/search/SearchResultUtilsTest.java b/kaldb/src/test/java/com/slack/kaldb/logstore/search/SearchResultUtilsTest.java index 066db531be..ae9f10bc16 100644 --- a/kaldb/src/test/java/com/slack/kaldb/logstore/search/SearchResultUtilsTest.java +++ b/kaldb/src/test/java/com/slack/kaldb/logstore/search/SearchResultUtilsTest.java @@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.assertThat; import com.slack.kaldb.logstore.LogMessage; +import com.slack.kaldb.logstore.search.aggregations.AutoDateHistogramAggBuilder; import com.slack.kaldb.logstore.search.aggregations.AvgAggBuilder; import com.slack.kaldb.logstore.search.aggregations.CumulativeSumAggBuilder; import com.slack.kaldb.logstore.search.aggregations.DateHistogramAggBuilder; @@ -122,6 +123,7 @@ public void shouldConvertDateHistogramAggToFromProto() { LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "5s", "2s", + null, 10000, "epoch_ms", Map.of( @@ -137,6 +139,31 @@ public void shouldConvertDateHistogramAggToFromProto() { assertThat(dateHistogramAggBuilder1).isEqualTo(dateHistogramAggBuilder2); } + @Test + public void shouldConvertAutoDateHistogramAggToFromProto() { + AutoDateHistogramAggBuilder autoDateHistogramAggBuilder1 = + new AutoDateHistogramAggBuilder( + "1", LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "day", 10, List.of()); + + KaldbSearch.SearchRequest.SearchAggregation searchAggregation = + SearchResultUtils.toSearchAggregationProto(autoDateHistogramAggBuilder1); + AutoDateHistogramAggBuilder autoDateHistogramAggBuilder2 = + (AutoDateHistogramAggBuilder) SearchResultUtils.fromSearchAggregations(searchAggregation); + + assertThat(autoDateHistogramAggBuilder1).isEqualTo(autoDateHistogramAggBuilder2); + + AutoDateHistogramAggBuilder autoDateHistogramAggBuilder3 = + new AutoDateHistogramAggBuilder( + "1", LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, null, null, List.of()); + + KaldbSearch.SearchRequest.SearchAggregation searchAggregation2 = + SearchResultUtils.toSearchAggregationProto(autoDateHistogramAggBuilder3); + AutoDateHistogramAggBuilder autoDateHistogramAggBuilder4 = + (AutoDateHistogramAggBuilder) SearchResultUtils.fromSearchAggregations(searchAggregation2); + + assertThat(autoDateHistogramAggBuilder3).isEqualTo(autoDateHistogramAggBuilder4); + } + @Test public void shouldConvertHistogramAggToFromProto() { HistogramAggBuilder histogramAggBuilder1 = @@ -282,6 +309,7 @@ public void shouldConvertNestedAggregations() { LogMessage.SystemField.TIME_SINCE_EPOCH.fieldName, "5s", "2s", + null, 10000, "epoch_ms", Map.of( @@ -295,6 +323,7 @@ public void shouldConvertNestedAggregations() { "duration_ms", "10s", "7s", + null, 1000, "epoch_ms", Map.of( diff --git a/kaldb/src/test/java/com/slack/kaldb/logstore/search/aggregations/AutoDateHistogramAggBuilderTest.java b/kaldb/src/test/java/com/slack/kaldb/logstore/search/aggregations/AutoDateHistogramAggBuilderTest.java new file mode 100644 index 0000000000..e564c2c20e --- /dev/null +++ b/kaldb/src/test/java/com/slack/kaldb/logstore/search/aggregations/AutoDateHistogramAggBuilderTest.java @@ -0,0 +1,68 @@ +package com.slack.kaldb.logstore.search.aggregations; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.Test; + +public class AutoDateHistogramAggBuilderTest { + + @Test + public void testEqualsAndHashCode() { + assertThat( + new AutoDateHistogramAggBuilder( + "name", + "field", + "day", + 10, + List.of(new AvgAggBuilder("name", "field", null, null)))) + .isEqualTo( + new AutoDateHistogramAggBuilder( + "name", + "field", + "day", + 10, + List.of(new AvgAggBuilder("name", "field", null, null)))); + + assertThat( + new AutoDateHistogramAggBuilder( + "name", + "field", + null, + null, + List.of(new AvgAggBuilder("name", "field", null, null)))) + .isEqualTo( + new AutoDateHistogramAggBuilder( + "name", + "field", + null, + null, + List.of(new AvgAggBuilder("name", "field", null, null)))); + + assertThat( + new AutoDateHistogramAggBuilder( + "name", + "field", + "day", + null, + List.of(new AvgAggBuilder("name", "field", null, null)))) + .isNotEqualTo( + new AutoDateHistogramAggBuilder( + "name", + "field", + null, + null, + List.of(new AvgAggBuilder("name", "field", null, null)))); + + assertThat( + new AutoDateHistogramAggBuilder( + "name", "field", null, 10, List.of(new AvgAggBuilder("name", "field", null, null)))) + .isNotEqualTo( + new AutoDateHistogramAggBuilder( + "name", + "field", + null, + null, + List.of(new AvgAggBuilder("name", "field", null, null)))); + } +} diff --git a/kaldb/src/test/java/com/slack/kaldb/logstore/search/aggregations/DateHistogramAggBuilderTest.java b/kaldb/src/test/java/com/slack/kaldb/logstore/search/aggregations/DateHistogramAggBuilderTest.java index 6dfe8c7036..85b82641e3 100644 --- a/kaldb/src/test/java/com/slack/kaldb/logstore/search/aggregations/DateHistogramAggBuilderTest.java +++ b/kaldb/src/test/java/com/slack/kaldb/logstore/search/aggregations/DateHistogramAggBuilderTest.java @@ -16,6 +16,7 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 0, "epoch_ms", Map.of("max", 1L, "min", 0L), @@ -26,6 +27,7 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 0, "epoch_ms", Map.of("max", 1L, "min", 0L), @@ -36,6 +38,7 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 0, "epoch_ms", Map.of("max", 1L, "min", 0L), @@ -47,6 +50,7 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 0, "epoch_ms", Map.of("max", 1L, "min", 0L), @@ -59,6 +63,7 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 1, "epoch_ms", Map.of(), @@ -69,6 +74,7 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 1, "epoch_ms", Map.of(), @@ -80,6 +86,7 @@ public void testEqualsAndHashCode() { "field", "1d", "1d", + "-01:00", 1, "epoch_ms", Map.of(), @@ -90,6 +97,7 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 1, "epoch_ms", Map.of(), @@ -97,10 +105,10 @@ public void testEqualsAndHashCode() { assertThat( new DateHistogramAggBuilder( - "name", "field", "12d", "10s", 1, "epoch_ms", Map.of(), List.of())) + "name", "field", "12d", "10s", "-01:00", 1, "epoch_ms", Map.of(), List.of())) .isNotEqualTo( new DateHistogramAggBuilder( - "name", "field", "1d", "10s", 1, "epoch_ms", Map.of(), List.of())); + "name", "field", "1d", "10s", "-01:00", 1, "epoch_ms", Map.of(), List.of())); assertThat( new DateHistogramAggBuilder( @@ -108,6 +116,7 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 0, "epoch_ms", Map.of("max", 1L, "min", 0L), @@ -118,6 +127,7 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 0, "epoch_ms", Map.of("max", 1L, "min", 1L), @@ -129,6 +139,7 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 1, "epoch_ms", Map.of(), @@ -139,9 +150,33 @@ public void testEqualsAndHashCode() { "field", "1d", "10s", + "-01:00", 1, "epoch_ms", Map.of(), List.of(new AvgAggBuilder("name", "field2", null, null)))); + + assertThat( + new DateHistogramAggBuilder( + "name", + "field", + "1d", + "10s", + null, + 1, + "epoch_ms", + Map.of(), + List.of(new AvgAggBuilder("name", "field1", null, null)))) + .isNotEqualTo( + new DateHistogramAggBuilder( + "name", + "field", + "1d", + "10s", + "-01:00", + 1, + "epoch_ms", + Map.of(), + List.of(new AvgAggBuilder("name", "field1", null, null)))); } }