|
@@ -38,6 +38,7 @@ import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry;
|
|
|
import org.elasticsearch.search.aggregations.support.ValuesSourceType;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
+import java.util.Locale;
|
|
|
import java.util.Map;
|
|
|
import java.util.Objects;
|
|
|
|
|
@@ -48,7 +49,7 @@ public class VariableWidthHistogramAggregationBuilder
|
|
|
|
|
|
private static final ParseField NUM_BUCKETS_FIELD = new ParseField("buckets");
|
|
|
|
|
|
- private static ParseField INITIAL_BUFFER_FIELD = new ParseField("initial_buffer");
|
|
|
+ private static final ParseField INITIAL_BUFFER_FIELD = new ParseField("initial_buffer");
|
|
|
|
|
|
private static final ParseField SHARD_SIZE_FIELD = new ParseField("shard_size");
|
|
|
|
|
@@ -62,12 +63,13 @@ public class VariableWidthHistogramAggregationBuilder
|
|
|
}
|
|
|
|
|
|
private int numBuckets = 10;
|
|
|
- private int shardSize = numBuckets * 50;
|
|
|
- private int initialBuffer = Math.min(10 * this.shardSize, 50000);
|
|
|
+ private int shardSize = -1;
|
|
|
+ private int initialBuffer = -1;
|
|
|
|
|
|
public static void registerAggregators(ValuesSourceRegistry.Builder builder) {
|
|
|
VariableWidthHistogramAggregatorFactory.registerAggregators(builder);
|
|
|
}
|
|
|
+
|
|
|
/** Create a new builder with the given name. */
|
|
|
public VariableWidthHistogramAggregationBuilder(String name) {
|
|
|
super(name);
|
|
@@ -93,41 +95,48 @@ public class VariableWidthHistogramAggregationBuilder
|
|
|
|
|
|
public VariableWidthHistogramAggregationBuilder setNumBuckets(int numBuckets){
|
|
|
if (numBuckets <= 0) {
|
|
|
- throw new IllegalArgumentException(NUM_BUCKETS_FIELD.getPreferredName() + " must be greater than 0 for ["
|
|
|
- + name + "]");
|
|
|
- } else if (numBuckets > 50000){
|
|
|
- throw new IllegalArgumentException(NUM_BUCKETS_FIELD.getPreferredName() + " must not be greater than 50,000 for ["
|
|
|
+ throw new IllegalArgumentException(NUM_BUCKETS_FIELD.getPreferredName() + " must be greater than [0] for ["
|
|
|
+ name + "]");
|
|
|
}
|
|
|
this.numBuckets = numBuckets;
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
- public VariableWidthHistogramAggregationBuilder setShardSize(int shardSize){
|
|
|
- if (shardSize < numBuckets) {
|
|
|
- throw new IllegalArgumentException(SHARD_SIZE_FIELD.getPreferredName() + " must not be less than "
|
|
|
- + NUM_BUCKETS_FIELD.getPreferredName() + " for [" + name + "]");
|
|
|
+ public VariableWidthHistogramAggregationBuilder setShardSize(int shardSize) {
|
|
|
+ if (shardSize <= 1) {
|
|
|
+ // A shard size of 1 will cause divide by 0s and, even if it worked, would produce garbage results.
|
|
|
+ throw new IllegalArgumentException(SHARD_SIZE_FIELD.getPreferredName() + " must be greater than [1] for [" + name + "]");
|
|
|
}
|
|
|
this.shardSize = shardSize;
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
- public VariableWidthHistogramAggregationBuilder setInitialBuffer(int initialBuffer){
|
|
|
- if (initialBuffer < numBuckets) {
|
|
|
- // If numBuckets buckets are being returned, then at least that many must be stored in memory
|
|
|
- throw new IllegalArgumentException(INITIAL_BUFFER_FIELD.getPreferredName() + " must be greater than numBuckets "
|
|
|
- + NUM_BUCKETS_FIELD.getPreferredName() + " for [" + name + "]");
|
|
|
-
|
|
|
+ public VariableWidthHistogramAggregationBuilder setInitialBuffer(int initialBuffer) {
|
|
|
+ if (initialBuffer <= 0) {
|
|
|
+ throw new IllegalArgumentException(INITIAL_BUFFER_FIELD.getPreferredName() + " must be greater than [0] for ["
|
|
|
+ + name + "]");
|
|
|
}
|
|
|
this.initialBuffer = initialBuffer;
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
- public int getNumBuckets(){ return numBuckets; }
|
|
|
+ public int getNumBuckets() {
|
|
|
+ return numBuckets;
|
|
|
+ }
|
|
|
|
|
|
- public int getShardSize(){ return shardSize; }
|
|
|
+ public int getShardSize() {
|
|
|
+ if (shardSize == -1) {
|
|
|
+ return numBuckets * 50;
|
|
|
+ }
|
|
|
+ return shardSize;
|
|
|
+ }
|
|
|
|
|
|
- public int getInitialBuffer(){ return initialBuffer; }
|
|
|
+ public int getInitialBuffer() {
|
|
|
+ if (initialBuffer == -1) {
|
|
|
+ return Math.min(10 * getShardSize(), 50000);
|
|
|
+ }
|
|
|
+ return initialBuffer;
|
|
|
+ }
|
|
|
|
|
|
@Override
|
|
|
public BucketCardinality bucketCardinality() {
|
|
@@ -149,12 +158,32 @@ public class VariableWidthHistogramAggregationBuilder
|
|
|
ValuesSourceConfig config,
|
|
|
AggregatorFactory parent,
|
|
|
AggregatorFactories.Builder subFactoriesBuilder) throws IOException {
|
|
|
-
|
|
|
Settings settings = queryShardContext.getIndexSettings().getNodeSettings();
|
|
|
int maxBuckets = MultiBucketConsumerService.MAX_BUCKET_SETTING.get(settings);
|
|
|
if (numBuckets > maxBuckets) {
|
|
|
- throw new IllegalArgumentException(NUM_BUCKETS_FIELD.getPreferredName()+
|
|
|
- " must be less than " + maxBuckets);
|
|
|
+ throw new IllegalArgumentException(NUM_BUCKETS_FIELD.getPreferredName() + " must be less than " + maxBuckets);
|
|
|
+ }
|
|
|
+ int initialBuffer = getInitialBuffer();
|
|
|
+ int shardSize = getShardSize();
|
|
|
+ if (initialBuffer < numBuckets) {
|
|
|
+ // If numBuckets buckets are being returned, then at least that many must be stored in memory
|
|
|
+ throw new IllegalArgumentException(
|
|
|
+ String.format(
|
|
|
+ Locale.ROOT,
|
|
|
+ "%s must be at least %s but was [%s<%s] for [%s]",
|
|
|
+ INITIAL_BUFFER_FIELD.getPreferredName(),
|
|
|
+ NUM_BUCKETS_FIELD.getPreferredName(),
|
|
|
+ initialBuffer,
|
|
|
+ numBuckets,
|
|
|
+ name
|
|
|
+ )
|
|
|
+ );
|
|
|
+ }
|
|
|
+ int mergePhaseInit = VariableWidthHistogramAggregator.mergePhaseInitialBucketCount(shardSize);
|
|
|
+ if (mergePhaseInit < numBuckets) {
|
|
|
+ // If the initial buckets from the merge phase is super low we will consistently return too few buckets
|
|
|
+ throw new IllegalArgumentException("3/4 of " + SHARD_SIZE_FIELD.getPreferredName() + " must be at least "
|
|
|
+ + NUM_BUCKETS_FIELD.getPreferredName() + " but was [" + mergePhaseInit + "<" + numBuckets + "] for [" + name + "]");
|
|
|
}
|
|
|
return new VariableWidthHistogramAggregatorFactory(name, config, numBuckets, shardSize, initialBuffer,
|
|
|
queryShardContext, parent, subFactoriesBuilder, metadata);
|