summaryrefslogtreecommitdiffstats
path: root/tenant-cd
diff options
context:
space:
mode:
authorJon Marius Venstad <jvenstad@yahoo-inc.com>2019-04-16 10:31:58 +0200
committerJon Marius Venstad <jvenstad@yahoo-inc.com>2019-06-06 13:03:28 +0200
commit0f554ee318980e0a2cb82e1cbd16bfde4e1aa9a0 (patch)
tree96eb5253f5b6d64cf0159d7d3deb61426a3bf4f3 /tenant-cd
parent5e326ad275e3f45ebae1e137271f63cb3bdaabe9 (diff)
Add aggregation to metrics
Diffstat (limited to 'tenant-cd')
-rw-r--r--tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Metric.java31
-rw-r--r--tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Metrics.java7
-rw-r--r--tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Statistic.java30
3 files changed, 49 insertions, 19 deletions
diff --git a/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Metric.java b/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Metric.java
index 5da4c3fb750..b7517668e8f 100644
--- a/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Metric.java
+++ b/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Metric.java
@@ -1,5 +1,6 @@
package com.yahoo.vespa.tenant.cd.metrics;
+import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
@@ -18,7 +19,7 @@ public class Metric {
private final Map<Map<String, ?>, Statistic> statistics;
private Metric(Map<Map<String, ?>, Statistic> statistics) {
- this.statistics = copyOf(statistics);
+ this.statistics = statistics;
}
/** Creates a new Metric with a copy of the given data. */
@@ -26,19 +27,16 @@ public class Metric {
if (data.isEmpty())
throw new IllegalArgumentException("No data given.");
+ Map<Map<String, ?>, Statistic> copies = new HashMap<>();
Set<String> dimensions = data.keySet().iterator().next().keySet();
- for (Map<String, ?> point : data.keySet()) {
- if (point.keySet().contains(null))
- throw new IllegalArgumentException("Dimensions may not be null: '" + point.keySet() + "'.");
-
+ data.forEach((point, statistic) -> {
if ( ! point.keySet().equals(dimensions))
throw new IllegalArgumentException("Given data has inconsistent dimensions: '" + dimensions + "' vs '" + point.keySet() + "'.");
- if (point.values().contains(null))
- throw new IllegalArgumentException("Position along a dimension may not be null: '" + point + "'.");
- }
+ copies.put(copyOf(point), statistic);
+ });
- return new Metric(data);
+ return new Metric(copyOf(copies));
}
/** Returns a Metric view of the subset of points in the given hyperplane; its dimensions must be a subset of those of this Metric. */
@@ -48,6 +46,21 @@ public class Metric {
.collect(toUnmodifiableMap(point -> point, statistics::get)));
}
+ /** Returns a version of this where statistics along the given hyperspace are aggregated. This does not preserve last, 95 and 99 percentile values. */
+ public Metric collapse(Set<String> hyperspace) {
+ return new Metric(statistics.keySet().stream()
+ .collect(toUnmodifiableMap(point -> point.keySet().stream()
+ .filter(dimension -> ! hyperspace.contains(dimension))
+ .collect(toUnmodifiableMap(dimension -> dimension, point::get)),
+ statistics::get,
+ Statistic::mergedWith)));
+ }
+
+ /** Returns a collapsed version of this, with all statistics aggregated. This does not preserve last, 95 and 99 percentile values. */
+ public Metric collapse() {
+ return collapse(statistics.keySet().iterator().next().keySet());
+ }
+
/** If this Metric contains a single point, returns the Statistic of that point; otherwise, throws an exception. */
public Statistic statistic() {
if (statistics.size() == 1)
diff --git a/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Metrics.java b/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Metrics.java
index c080d82a343..fb2528c4df5 100644
--- a/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Metrics.java
+++ b/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Metrics.java
@@ -28,17 +28,14 @@ public class Metrics {
private Metrics(Instant start, Instant end, Map<String, Metric> metrics) {
this.start = start;
this.end = end;
- this.metrics = copyOf(metrics);
+ this.metrics = metrics;
}
public static Metrics of(Instant start, Instant end, Map<String, Metric> metrics) {
- if (metrics.containsKey(null) || metrics.containsValue(null))
- throw new IllegalArgumentException("Metrics may not contain null keys or values: '" + metrics + "'.");
-
if ( ! start.isBefore(end))
throw new IllegalArgumentException("Given time interval must be positive: '" + start + "' to '" + end + "'.");
- return new Metrics(start, end, metrics);
+ return new Metrics(start, end, copyOf(metrics));
}
/** Returns the start of the time window from which these metrics were sampled, or throws if the status is {@code Status.down}. */
diff --git a/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Statistic.java b/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Statistic.java
index 65c6dc3ed3f..e3315bcd181 100644
--- a/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Statistic.java
+++ b/tenant-cd/src/main/java/com/yahoo/vespa/tenant/cd/metrics/Statistic.java
@@ -1,8 +1,11 @@
package com.yahoo.vespa.tenant.cd.metrics;
+import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.StringJoiner;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import static java.util.Map.copyOf;
@@ -17,14 +20,11 @@ public class Statistic {
/** Creates a new Statistic with a copy of the given data. */
private Statistic(Map<Type, Double> data) {
- this.data = copyOf(data);
+ this.data = data;
}
public static Statistic of(Map<Type, Double> data) {
- if (data.containsKey(null) || data.containsValue(null))
- throw new IllegalArgumentException("Data may not contain null keys or values: '" + data + "'.");
-
- return new Statistic(data);
+ return new Statistic(copyOf(data));
}
/** Returns the value of the given type, or throws a NoSuchElementException if this isn't known. */
@@ -40,6 +40,26 @@ public class Statistic {
return data;
}
+ Statistic mergedWith(Statistic other) {
+ if (data.keySet().equals(other.data.keySet()))
+ throw new IllegalArgumentException("Incompatible key sets '" + data.keySet() + "' and '" + other.data.keySet() + "'.");
+
+ Map<Type, Double> merged = new HashMap<>();
+ double n1 = get(Type.count), n2 = other.get(Type.count);
+ for (Type type : data.keySet()) switch (type) {
+ case count: merged.put(type, n1 + n2); break;
+ case rate: merged.put(type, get(Type.rate) + other.get(Type.rate)); break;
+ case max: merged.put(type, Math.max(get(Type.max), other.get(Type.max))); break;
+ case min: merged.put(type, Math.min(get(Type.min), other.get(Type.min))); break;
+ case average: merged.put(type, (n1 * get(Type.average) + n2 * other.get(Type.average)) / (n1 + n2)); break;
+ case last:
+ case percentile95:
+ case percentile99: break;
+ default: throw new IllegalArgumentException("Unexpected type '" + type + "'.");
+ }
+ return of(merged);
+ }
+
@Override
public String toString() {
return new StringJoiner(", ", Statistic.class.getSimpleName() + "[", "]")