// This file is part of OpenTSDB.
// Copyright (C) 2010-2012 The OpenTSDB Authors.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 2.1 of the License, or (at your
// option) any later version. This program is distributed in the hope that it
// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details. You should have received a copy
// of the GNU Lesser General Public License along with this program. If not,
// see <http://www.gnu.org/licenses/>.
package net.opentsdb.core;
import java.util.HashMap;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Utility class that provides common, generally useful aggregators.
*/
public final class Aggregators {
/** Aggregator that sums up all the data points. */
public static final Aggregator SUM = new Sum();
/** Aggregator that returns the minimum data point. */
public static final Aggregator MIN = new Min();
/** Aggregator that returns the maximum data point. */
public static final Aggregator MAX = new Max();
/** Aggregator that returns the average value of the data point. */
public static final Aggregator AVG = new Avg();
/** Aggregator that returns the Standard Deviation of the data points. */
public static final Aggregator DEV = new StdDev();
/** Maps an aggregator name to its instance. */
private static final HashMap<String, Aggregator> aggregators;
static {
aggregators = new HashMap<String, Aggregator>(5);
aggregators.put("sum", SUM);
aggregators.put("min", MIN);
aggregators.put("max", MAX);
aggregators.put("avg", AVG);
aggregators.put("dev", DEV);
}
private Aggregators() {
// Can't create instances of this utility class.
}
/**
* Returns the set of the names that can be used with {@link #get get}.
*/
public static Set<String> set() {
return aggregators.keySet();
}
/**
* Returns the aggregator corresponding to the given name.
* @param name The name of the aggregator to get.
* @throws NoSuchElementException if the given name doesn't exist.
* @see #set
*/
public static Aggregator get(final String name) {
final Aggregator agg = aggregators.get(name);
if (agg != null) {
return agg;
}
throw new NoSuchElementException("No such aggregator: " + name);
}
private static final class Sum implements Aggregator {
public long runLong(final Longs values) {
long result = values.nextLongValue();
while (values.hasNextValue()) {
result += values.nextLongValue();
}
return result;
}
public double runDouble(final Doubles values) {
double result = values.nextDoubleValue();
while (values.hasNextValue()) {
result += values.nextDoubleValue();
}
return result;
}
public String toString() {
return "sum";
}
}
private static final class Min implements Aggregator {
public long runLong(final Longs values) {
long min = values.nextLongValue();
while (values.hasNextValue()) {
final long val = values.nextLongValue();
if (val < min) {
min = val;
}
}
return min;
}
public double runDouble(final Doubles values) {
double min = values.nextDoubleValue();
while (values.hasNextValue()) {
final double val = values.nextDoubleValue();
if (val < min) {
min = val;
}
}
return min;
}
public String toString() {
return "min";
}
}
private static final class Max implements Aggregator {
public long runLong(final Longs values) {
long max = values.nextLongValue();
while (values.hasNextValue()) {
final long val = values.nextLongValue();
if (val > max) {
max = val;
}
}
return max;
}
public double runDouble(final Doubles values) {
double max = values.nextDoubleValue();
while (values.hasNextValue()) {
final double val = values.nextDoubleValue();
if (val > max) {
max = val;
}
}
return max;
}
public String toString() {
return "max";
}
}
private static final class Avg implements Aggregator {
public long runLong(final Longs values) {
long result = values.nextLongValue();
int n = 1;
while (values.hasNextValue()) {
result += values.nextLongValue();
n++;
}
return result / n;
}
public double runDouble(final Doubles values) {
double result = values.nextDoubleValue();
int n = 1;
while (values.hasNextValue()) {
result += values.nextDoubleValue();
n++;
}
return result / n;
}
public String toString() {
return "avg";
}
}
/**
* Standard Deviation aggregator.
* Can compute without storing all of the data points in memory at the same
* time. This implementation is based upon a
* <a href="http://www.johndcook.com/standard_deviation.html">paper by John
* D. Cook</a>, which itself is based upon a method that goes back to a 1962
* paper by B. P. Welford and is presented in Donald Knuth's Art of
* Computer Programming, Vol 2, page 232, 3rd edition
*/
private static final class StdDev implements Aggregator {
public long runLong(final Longs values) {
double old_mean = values.nextLongValue();
if (!values.hasNextValue()) {
return 0;
}
long n = 2;
double new_mean = 0;
double variance = 0;
do {
final double x = values.nextLongValue();
new_mean = old_mean + (x - old_mean) / n;
variance += (x - old_mean) * (x - new_mean);
old_mean = new_mean;
n++;
} while (values.hasNextValue());
return (long) Math.sqrt(variance / (n - 1));
}
public double runDouble(final Doubles values) {
double old_mean = values.nextDoubleValue();
if (!values.hasNextValue()) {
return 0;
}
long n = 2;
double new_mean = 0;
double variance = 0;
do {
final double x = values.nextDoubleValue();
new_mean = old_mean + (x - old_mean) / n;
variance += (x - old_mean) * (x - new_mean);
old_mean = new_mean;
n++;
} while (values.hasNextValue());
return Math.sqrt(variance / (n - 1));
}
public String toString() {
return "dev";
}
}
}