Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ private void registerAggregations(List<SearchPlugin> plugins) {
registerAggregation(new AggregationSpec(PercentileRanksAggregationBuilder.NAME, PercentileRanksAggregationBuilder::new,
PercentileRanksAggregationBuilder::parse)
.addResultReader(InternalTDigestPercentileRanks.NAME, InternalTDigestPercentileRanks::new)
.addResultReader(InternalHDRPercentileRanks.NAME, InternalHDRPercentileRanks::new));
.addResultReader(InternalHDRPercentileRanks.NAME, InternalHDRPercentileRanks::new)
.setAggregatorRegistrar(PercentileRanksAggregationBuilder::registerAggregators));
registerAggregation(new AggregationSpec(MedianAbsoluteDeviationAggregationBuilder.NAME,
MedianAbsoluteDeviationAggregationBuilder::new, MedianAbsoluteDeviationAggregationBuilder::parse)
.addResultReader(InternalMedianAbsoluteDeviation::new));
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,22 @@
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregatorFactories.Builder;
import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.metrics.PercentilesAggregationBuilder.PercentilesConfig;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuilder.LeafOnly;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.ValuesSourceParserHelper;
import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry;
import org.elasticsearch.search.aggregations.support.ValuesSourceType;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;

Expand Down Expand Up @@ -98,6 +101,13 @@ private static class HDROptions {
}, HDR_OPTIONS_PARSER::parse, PercentilesMethod.HDR.getParseField(), ObjectParser.ValueType.OBJECT);
}

private static AtomicBoolean wasRegistered = new AtomicBoolean(false);
public static void registerAggregators(ValuesSourceRegistry valuesSourceRegistry) {
if (wasRegistered.compareAndSet(false, true) == true) {
PercentileRanksAggregatorFactory.registerAggregators(valuesSourceRegistry);
}
}

public static AggregationBuilder parse(String aggregationName, XContentParser parser) throws IOException {
// the aggregation name is supplied to the parser as a Context. See note at top of Parser for more details
return PARSER.parse(parser, aggregationName);
Expand Down Expand Up @@ -246,16 +256,17 @@ public PercentilesMethod method() {
@Override
protected ValuesSourceAggregatorFactory innerBuild(QueryShardContext queryShardContext, ValuesSourceConfig config,
AggregatorFactory parent, Builder subFactoriesBuilder) throws IOException {
switch (method) {
case TDIGEST:
return new TDigestPercentileRanksAggregatorFactory(name, config, values, compression, keyed, queryShardContext, parent,
subFactoriesBuilder, metaData);
case HDR:
return new HDRPercentileRanksAggregatorFactory(name, config, values, numberOfSignificantValueDigits, keyed, queryShardContext,
parent, subFactoriesBuilder, metaData);
default:
PercentilesConfig percentilesConfig;
if (method.equals(PercentilesMethod.TDIGEST)) {
percentilesConfig = new PercentilesConfig.TDigestConfig(compression);
} else if (method.equals(PercentilesMethod.HDR)) {
percentilesConfig = new PercentilesConfig.HdrHistoConfig(numberOfSignificantValueDigits);
} else {
throw new IllegalStateException("Illegal method [" + method + "]");
}

return new PercentileRanksAggregatorFactory(name, config, values, percentilesConfig, keyed, queryShardContext, parent,
subFactoriesBuilder, metaData);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.search.aggregations.metrics;

import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.AggregationExecutionException;
import org.elasticsearch.search.aggregations.Aggregator;
import org.elasticsearch.search.aggregations.AggregatorFactories;
import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.metrics.PercentilesAggregationBuilder.PercentilesConfig;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import org.elasticsearch.search.aggregations.support.AggregatorSupplier;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry;
import org.elasticsearch.search.internal.SearchContext;

import java.io.IOException;
import java.util.List;
import java.util.Map;

class PercentileRanksAggregatorFactory extends ValuesSourceAggregatorFactory {
private final double[] values;
private final PercentilesConfig percentilesConfig;
private final boolean keyed;

static void registerAggregators(ValuesSourceRegistry valuesSourceRegistry) {
valuesSourceRegistry.register(PercentileRanksAggregationBuilder.NAME,
List.of(CoreValuesSourceType.NUMERIC, CoreValuesSourceType.HISTOGRAM),
new PercentilesAggregatorSupplier() {
@Override
public Aggregator build(String name, ValuesSource valuesSource, SearchContext context, Aggregator parent,
double[] percents, PercentilesConfig percentilesConfig, boolean keyed, DocValueFormat formatter,
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) throws IOException {

if (percentilesConfig.getMethod().equals(PercentilesMethod.TDIGEST)) {
double compression = ((PercentilesConfig.TDigestConfig)percentilesConfig).getCompression();
return new TDigestPercentileRanksAggregator(name, valuesSource, context, parent, percents, compression, keyed,
formatter, pipelineAggregators, metaData);
} else if (percentilesConfig.getMethod().equals(PercentilesMethod.HDR)) {
int numSigFig = ((PercentilesConfig.HdrHistoConfig)percentilesConfig).getNumberOfSignificantValueDigits();
return new HDRPercentileRanksAggregator(name, valuesSource, context, parent, percents, numSigFig, keyed,
formatter, pipelineAggregators, metaData);
}

// This should already have thrown but just in case
throw new IllegalStateException("Unknown percentiles method: [" + percentilesConfig.getMethod().toString() + "]");
}
}
);
}

PercentileRanksAggregatorFactory(String name, ValuesSourceConfig config, double[] values,
PercentilesConfig percentilesConfig, boolean keyed,
QueryShardContext queryShardContext, AggregatorFactory parent,
AggregatorFactories.Builder subFactoriesBuilder,
Map<String, Object> metaData) throws IOException {
super(name, config, queryShardContext, parent, subFactoriesBuilder, metaData);
this.values = values;
this.percentilesConfig = percentilesConfig;
this.keyed = keyed;
}

@Override
protected Aggregator createUnmapped(SearchContext searchContext,
Aggregator parent,
List<PipelineAggregator> pipelineAggregators,
Map<String, Object> metaData) throws IOException {
if (percentilesConfig.getMethod().equals(PercentilesMethod.TDIGEST)) {
double compression = ((PercentilesConfig.TDigestConfig)percentilesConfig).getCompression();
return new TDigestPercentileRanksAggregator(name, null, searchContext, parent, values, compression, keyed, config.format(),
pipelineAggregators, metaData);
} else if (percentilesConfig.getMethod().equals(PercentilesMethod.HDR)) {
int numSigFig = ((PercentilesConfig.HdrHistoConfig)percentilesConfig).getNumberOfSignificantValueDigits();
return new HDRPercentileRanksAggregator(name, null, searchContext, parent, values, numSigFig, keyed,
config.format(), pipelineAggregators, metaData);
}

// This should already have thrown but just in case
throw new IllegalStateException("Unknown percentiles method: [" + percentilesConfig.getMethod().toString() + "]");
}

@Override
protected Aggregator doCreateInternal(ValuesSource valuesSource,
SearchContext searchContext,
Aggregator parent,
boolean collectsFromSingleBucket,
List<PipelineAggregator> pipelineAggregators,
Map<String, Object> metaData) throws IOException {

AggregatorSupplier aggregatorSupplier = ValuesSourceRegistry.getInstance().getAggregator(config.valueSourceType(),
PercentileRanksAggregationBuilder.NAME);

if (aggregatorSupplier instanceof PercentilesAggregatorSupplier == false) {
throw new AggregationExecutionException("Registry miss-match - expected PercentilesAggregatorSupplier, found [" +
aggregatorSupplier.getClass().toString() + "]");
}
PercentilesAggregatorSupplier percentilesAggregatorSupplier = (PercentilesAggregatorSupplier) aggregatorSupplier;
return percentilesAggregatorSupplier.build(name, valuesSource, searchContext, parent, values, percentilesConfig, keyed,
config.format(), pipelineAggregators, metaData);
}

}