/*
* 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.pipeline;
import org.elasticsearch.search.aggregations.metrics.avg.AvgAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.max.MaxAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.min.MinAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.sum.SumAggregationBuilder;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuilder;
import org.elasticsearch.test.ESTestCase;
import java.util.ArrayList;
/**
* Provides helper methods and classes for use in PipelineAggregation tests,
* such as creating mock histograms or computing simple metrics
*/
public class PipelineAggregationHelperTests extends ESTestCase {
/**
* Generates a mock histogram to use for testing. Each MockBucket holds a doc count, key and document values
* which can later be used to compute metrics and compare against the real aggregation results. Gappiness can be
* controlled via parameters
*
* @param interval Interval between bucket keys
* @param size Size of mock histogram to generate (in buckets)
* @param gapProbability Probability of generating an empty bucket. 0.0-1.0 inclusive
* @param runProbability Probability of extending a gap once one has been created. 0.0-1.0 inclusive
*/
public static ArrayList<MockBucket> generateHistogram(int interval, int size, double gapProbability, double runProbability) {
ArrayList<MockBucket> values = new ArrayList<>(size);
boolean lastWasGap = false;
boolean emptyHisto = true;
for (int i = 0; i < size; i++) {
MockBucket bucket = new MockBucket();
if (randomDouble() < gapProbability) {
// start a gap
bucket.count = 0;
bucket.docValues = new double[0];
lastWasGap = true;
} else if (lastWasGap && randomDouble() < runProbability) {
// add to the existing gap
bucket.count = 0;
bucket.docValues = new double[0];
lastWasGap = true;
} else {
bucket.count = randomIntBetween(1, 50);
bucket.docValues = new double[bucket.count];
for (int j = 0; j < bucket.count; j++) {
bucket.docValues[j] = randomDouble() * randomIntBetween(-20, 20);
}
lastWasGap = false;
emptyHisto = false;
}
bucket.key = i * interval;
values.add(bucket);
}
if (emptyHisto) {
int idx = randomIntBetween(0, values.size()-1);
MockBucket bucket = values.get(idx);
bucket.count = randomIntBetween(1, 50);
bucket.docValues = new double[bucket.count];
for (int j = 0; j < bucket.count; j++) {
bucket.docValues[j] = randomDouble() * randomIntBetween(-20, 20);
}
values.set(idx, bucket);
}
return values;
}
/**
* Simple mock bucket container
*/
public static class MockBucket {
public int count;
public double[] docValues;
public long key;
}
/**
* Computes a simple agg metric (min, sum, etc) from the provided values
*
* @param values Array of values to compute metric for
* @param metric A metric builder which defines what kind of metric should be returned for the values
*/
public static double calculateMetric(double[] values, ValuesSourceAggregationBuilder<?, ?> metric) {
if (metric instanceof MinAggregationBuilder) {
double accumulator = Double.POSITIVE_INFINITY;
for (double value : values) {
accumulator = Math.min(accumulator, value);
}
return accumulator;
} else if (metric instanceof MaxAggregationBuilder) {
double accumulator = Double.NEGATIVE_INFINITY;
for (double value : values) {
accumulator = Math.max(accumulator, value);
}
return accumulator;
} else if (metric instanceof SumAggregationBuilder) {
double accumulator = 0;
for (double value : values) {
accumulator += value;
}
return accumulator;
} else if (metric instanceof AvgAggregationBuilder) {
double accumulator = 0;
for (double value : values) {
accumulator += value;
}
return accumulator / values.length;
}
return 0.0;
}
}