Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions docs/changelog/139247.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 139247
summary: Add TDigest histogram as metric to time series data streams
area: "TSDB"
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.SourceLoader;
import org.elasticsearch.index.mapper.SourceValueFetcher;
import org.elasticsearch.index.mapper.TimeSeriesParams;
import org.elasticsearch.index.mapper.ValueFetcher;
import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.script.field.DocValuesScriptFieldFactory;
Expand Down Expand Up @@ -78,6 +79,11 @@ public static class Builder extends FieldMapper.Builder {
private final Parameter<Map<String, String>> meta = Parameter.metaParam();
private final Parameter<Explicit<Boolean>> ignoreMalformed;
private final Parameter<Explicit<Boolean>> coerce;
/**
* Parameter that marks this field as a time series metric defining its time series metric type.
* Only the metric type histogram is supported.
*/
private final Parameter<TimeSeriesParams.MetricType> metric;

public Builder(String name, boolean ignoreMalformedByDefault, boolean coerceByDefault) {
super(name);
Expand All @@ -88,18 +94,24 @@ public Builder(String name, boolean ignoreMalformedByDefault, boolean coerceByDe
ignoreMalformedByDefault
);
this.coerce = Parameter.explicitBoolParam("coerce", true, m -> toType(m).coerce, coerceByDefault);
this.metric = TimeSeriesParams.metricParam(m -> toType(m).metricType, TimeSeriesParams.MetricType.HISTOGRAM);
}

public Builder metric(TimeSeriesParams.MetricType metric) {
this.metric.setValue(metric);
return this;
}

@Override
protected Parameter<?>[] getParameters() {
return new Parameter<?>[] { ignoreMalformed, coerce, meta };
return new Parameter<?>[] { ignoreMalformed, coerce, meta, metric };
}

@Override
public HistogramFieldMapper build(MapperBuilderContext context) {
return new HistogramFieldMapper(
leafName(),
new HistogramFieldType(context.buildFullName(leafName()), meta.getValue()),
new HistogramFieldType(context.buildFullName(leafName()), meta.getValue(), this.metric.getValue()),
builderParams(this, context),
this
);
Expand All @@ -116,13 +128,15 @@ public HistogramFieldMapper build(MapperBuilderContext context) {

private final Explicit<Boolean> coerce;
private final boolean coerceByDefault;
private final TimeSeriesParams.MetricType metricType;

public HistogramFieldMapper(String simpleName, MappedFieldType mappedFieldType, BuilderParams builderParams, Builder builder) {
super(simpleName, mappedFieldType, builderParams);
this.ignoreMalformed = builder.ignoreMalformed.getValue();
this.ignoreMalformedByDefault = builder.ignoreMalformed.getDefaultValue().value();
this.coerce = builder.coerce.getValue();
this.coerceByDefault = builder.coerce.getDefaultValue().value();
this.metricType = builder.metric.get();
}

@Override
Expand All @@ -141,7 +155,7 @@ protected String contentType() {

@Override
public FieldMapper.Builder getMergeBuilder() {
return new Builder(leafName(), ignoreMalformedByDefault, coerceByDefault).init(this);
return new Builder(leafName(), ignoreMalformedByDefault, coerceByDefault).metric(metricType).init(this);
}

@Override
Expand All @@ -150,9 +164,11 @@ protected void parseCreateField(DocumentParserContext context) {
}

public static class HistogramFieldType extends MappedFieldType {
private final TimeSeriesParams.MetricType metricType;

public HistogramFieldType(String name, Map<String, String> meta) {
public HistogramFieldType(String name, Map<String, String> meta, TimeSeriesParams.MetricType metricType) {
super(name, IndexType.docValuesOnly(), false, meta);
this.metricType = metricType;
}

@Override
Expand All @@ -170,6 +186,11 @@ public boolean isSearchable() {
return false;
}

@Override
public TimeSeriesParams.MetricType getMetricType() {
return metricType;
}

@Override
public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) {
failIfNoDocValues();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ protected AggregationBuilder createAggBuilderForTypeTest(MappedFieldType fieldTy
}

private MappedFieldType defaultFieldType(String fieldName) {
return new HistogramFieldMapper.HistogramFieldType(fieldName, Collections.emptyMap());
return new HistogramFieldMapper.HistogramFieldType(fieldName, Collections.emptyMap(), null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ protected AggregationBuilder createAggBuilderForTypeTest(MappedFieldType fieldTy

private MappedFieldType defaultFieldType(String fieldName) {
if (fieldName.equals(HISTO_FIELD_NAME)) {
return new HistogramFieldMapper.HistogramFieldType(fieldName, Collections.emptyMap());
return new HistogramFieldMapper.HistogramFieldType(fieldName, Collections.emptyMap(), null);
} else {
return new NumberFieldMapper.NumberFieldType(fieldName, NumberFieldMapper.NumberType.DOUBLE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public void testSimple() throws IOException {
PercentileRanksAggregationBuilder aggBuilder = new PercentileRanksAggregationBuilder("my_agg", new double[] { 0.1, 0.5, 12 })
.field("field")
.method(PercentilesMethod.HDR);
MappedFieldType fieldType = new HistogramFieldMapper.HistogramFieldType("field", Collections.emptyMap());
MappedFieldType fieldType = new HistogramFieldMapper.HistogramFieldType("field", Collections.emptyMap(), null);
try (IndexReader reader = w.getReader()) {
PercentileRanks ranks = searchAndReduce(reader, new AggTestConfig(aggBuilder, fieldType));
Iterator<Percentile> rankIterator = ranks.iterator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ private void testCase(Query query, CheckedConsumer<RandomIndexWriter, IOExceptio
throws IOException {
PercentilesAggregationBuilder builder = new PercentilesAggregationBuilder("test").field("number").method(PercentilesMethod.HDR);

MappedFieldType fieldType = new HistogramFieldMapper.HistogramFieldType("number", Collections.emptyMap());
MappedFieldType fieldType = new HistogramFieldMapper.HistogramFieldType("number", Collections.emptyMap(), null);
testCase(buildIndex, verify, new AggTestConfig(builder, fieldType).withQuery(query));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,6 @@ protected AggregationBuilder createAggBuilderForTypeTest(MappedFieldType fieldTy
}

private MappedFieldType defaultFieldType() {
return new HistogramFieldMapper.HistogramFieldType(HistoBackedAvgAggregatorTests.FIELD_NAME, Collections.emptyMap());
return new HistogramFieldMapper.HistogramFieldType(HistoBackedAvgAggregatorTests.FIELD_NAME, Collections.emptyMap(), null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,6 @@ protected AggregationBuilder createAggBuilderForTypeTest(MappedFieldType fieldTy
}

private MappedFieldType defaultFieldType() {
return new HistogramFieldMapper.HistogramFieldType(HistoBackedMaxAggregatorTests.FIELD_NAME, Collections.emptyMap());
return new HistogramFieldMapper.HistogramFieldType(HistoBackedMaxAggregatorTests.FIELD_NAME, Collections.emptyMap(), null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,6 @@ protected AggregationBuilder createAggBuilderForTypeTest(MappedFieldType fieldTy
}

private MappedFieldType defaultFieldType() {
return new HistogramFieldMapper.HistogramFieldType(HistoBackedMinAggregatorTests.FIELD_NAME, Collections.emptyMap());
return new HistogramFieldMapper.HistogramFieldType(HistoBackedMinAggregatorTests.FIELD_NAME, Collections.emptyMap(), null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,6 @@ protected AggregationBuilder createAggBuilderForTypeTest(MappedFieldType fieldTy
}

private MappedFieldType defaultFieldType() {
return new HistogramFieldMapper.HistogramFieldType(HistoBackedSumAggregatorTests.FIELD_NAME, Collections.emptyMap());
return new HistogramFieldMapper.HistogramFieldType(HistoBackedSumAggregatorTests.FIELD_NAME, Collections.emptyMap(), null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,6 @@ protected AggregationBuilder createAggBuilderForTypeTest(MappedFieldType fieldTy
}

private MappedFieldType defaultFieldType() {
return new HistogramFieldMapper.HistogramFieldType("field", Collections.emptyMap());
return new HistogramFieldMapper.HistogramFieldType("field", Collections.emptyMap(), null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public void testSimple() throws IOException {
PercentileRanksAggregationBuilder aggBuilder = new PercentileRanksAggregationBuilder("my_agg", new double[] { 0.1, 0.5, 12 })
.field("field")
.method(PercentilesMethod.TDIGEST);
MappedFieldType fieldType = new HistogramFieldMapper.HistogramFieldType("field", Collections.emptyMap());
MappedFieldType fieldType = new HistogramFieldMapper.HistogramFieldType("field", Collections.emptyMap(), null);
try (IndexReader reader = w.getReader()) {
PercentileRanks ranks = searchAndReduce(reader, new AggTestConfig(aggBuilder, fieldType));
Iterator<Percentile> rankIterator = ranks.iterator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private void testCase(
) throws IOException {
PercentilesAggregationBuilder builder = new PercentilesAggregationBuilder("test").field("number").method(PercentilesMethod.TDIGEST);

MappedFieldType fieldType = new HistogramFieldMapper.HistogramFieldType("number", Collections.emptyMap());
MappedFieldType fieldType = new HistogramFieldMapper.HistogramFieldType("number", Collections.emptyMap(), null);
testCase(buildIndex, verify, new AggTestConfig(builder, fieldType).withQuery(query));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.elasticsearch.index.mapper.DocumentParsingException;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.MapperTestCase;
import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.SourceToParse;
Expand Down Expand Up @@ -463,6 +464,41 @@ public void testArrayValueSyntheticSource() throws Exception {
assertEquals(Strings.toString(expected), syntheticSource);
}

public void testMetricType() throws IOException {
// Test default setting
MapperService mapperService = createMapperService(fieldMapping(this::minimalMapping));
HistogramFieldMapper.HistogramFieldType ft = (HistogramFieldMapper.HistogramFieldType) mapperService.fieldType("field");
assertNull(ft.getMetricType());

assertMetricType("histogram", HistogramFieldMapper.HistogramFieldType::getMetricType);

{
String unsupportedMetricTypes = randomFrom("counter", "gauge", "position");
// Test invalid metric type for this field type
Exception e = expectThrows(MapperParsingException.class, () -> createMapperService(fieldMapping(b -> {
minimalMapping(b);
b.field("time_series_metric", unsupportedMetricTypes);
})));
assertThat(
e.getCause().getMessage(),
containsString(
"Unknown value [" + unsupportedMetricTypes + "] for field [time_series_metric] - accepted values are [histogram]"
)
);
}
{
// Test invalid metric type
Exception e = expectThrows(MapperParsingException.class, () -> createMapperService(fieldMapping(b -> {
minimalMapping(b);
b.field("time_series_metric", "unknown");
})));
assertThat(
e.getCause().getMessage(),
containsString("Unknown value [unknown] for field [time_series_metric] - accepted values are [histogram]")
);
}
}

@Override
protected SyntheticSourceSupport syntheticSourceSupport(boolean ignoreMalformed) {
return new HistogramFieldSyntheticSourceSupport(ignoreMalformed);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ public void testFormatter() throws IOException {
}

public void testHistogramFieldMonthToMonth() throws IOException {
MappedFieldType histType = new HistogramFieldMapper.HistogramFieldType("val", Collections.emptyMap());
MappedFieldType histType = new HistogramFieldMapper.HistogramFieldType("val", Collections.emptyMap(), null);
MappedFieldType dateType = dateFieldType(DATE_FIELD);
RateAggregationBuilder rateAggregationBuilder = new RateAggregationBuilder("my_rate").rateUnit("month").field("val");
if (randomBoolean()) {
Expand All @@ -750,7 +750,7 @@ public void testHistogramFieldMonthToMonth() throws IOException {
}

public void testHistogramFieldMonthToYear() throws IOException {
MappedFieldType histType = new HistogramFieldMapper.HistogramFieldType("val", Collections.emptyMap());
MappedFieldType histType = new HistogramFieldMapper.HistogramFieldType("val", Collections.emptyMap(), null);
MappedFieldType dateType = dateFieldType(DATE_FIELD);
RateAggregationBuilder rateAggregationBuilder = new RateAggregationBuilder("my_rate").rateUnit("month").field("val");
if (randomBoolean()) {
Expand All @@ -770,7 +770,7 @@ public void testHistogramFieldMonthToYear() throws IOException {
}

public void testHistogramFieldMonthToMonthValueCount() throws IOException {
MappedFieldType histType = new HistogramFieldMapper.HistogramFieldType("val", Collections.emptyMap());
MappedFieldType histType = new HistogramFieldMapper.HistogramFieldType("val", Collections.emptyMap(), null);
MappedFieldType dateType = dateFieldType(DATE_FIELD);
RateAggregationBuilder rateAggregationBuilder = new RateAggregationBuilder("my_rate").rateUnit("month")
.rateMode("value_count")
Expand All @@ -792,7 +792,7 @@ public void testHistogramFieldMonthToMonthValueCount() throws IOException {
}

public void testHistogramFieldMonthToYearValueCount() throws IOException {
MappedFieldType histType = new HistogramFieldMapper.HistogramFieldType("val", Collections.emptyMap());
MappedFieldType histType = new HistogramFieldMapper.HistogramFieldType("val", Collections.emptyMap(), null);
MappedFieldType dateType = dateFieldType(DATE_FIELD);
RateAggregationBuilder rateAggregationBuilder = new RateAggregationBuilder("my_rate").rateUnit("month")
.rateMode("value_count")
Expand All @@ -813,7 +813,7 @@ public void testHistogramFieldMonthToYearValueCount() throws IOException {
}

public void testFilterWithHistogramField() throws IOException {
MappedFieldType histType = new HistogramFieldMapper.HistogramFieldType("val", Collections.emptyMap());
MappedFieldType histType = new HistogramFieldMapper.HistogramFieldType("val", Collections.emptyMap(), null);
MappedFieldType dateType = dateFieldType(DATE_FIELD);
MappedFieldType keywordType = new KeywordFieldMapper.KeywordFieldType("term");
RateAggregationBuilder rateAggregationBuilder = new RateAggregationBuilder("my_rate").rateUnit("month").field("val");
Expand Down
Loading