performance improvement
* pre-fill the buckets * use LongObjHashMap to avoid boxing
This commit is contained in:
@@ -1,15 +1,13 @@
|
||||
package org.lucares.pdb.plot.api;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.lucares.collections.LongObjHashMap;
|
||||
import org.lucares.recommind.logs.GnuplotAxis;
|
||||
|
||||
public class BoxAggregator implements CustomAggregator, IndexedAggregator {
|
||||
|
||||
private static final double SPACE_BETWEEN_BARS = 0.6;
|
||||
private Long index = null;
|
||||
private Long numberOfDataSeries;
|
||||
|
||||
@@ -17,19 +15,20 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator {
|
||||
|
||||
private final Interval interval;
|
||||
|
||||
private final Map<Long, PercentilesAggregator> buckets = new HashMap<>();
|
||||
private final LongObjHashMap<PercentilesAggregator> buckets;
|
||||
|
||||
public BoxAggregator(final PlotSettings settings) {
|
||||
|
||||
this.interval = settings.getInterval().get();
|
||||
this.buckets = interval.getMiddleTimeBuckets(PercentilesAggregator::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addValue(final long epochMilli, final long value) {
|
||||
|
||||
final long bucketId = interval.toBucketMiddleTime(epochMilli);
|
||||
buckets.putIfAbsent(bucketId, new PercentilesAggregator());
|
||||
buckets.get(bucketId).addValue(epochMilli, value);
|
||||
final PercentilesAggregator bucket = buckets.get(bucketId);
|
||||
bucket.addValue(epochMilli, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,9 +75,9 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator {
|
||||
|
||||
public String asCsv(final boolean renderLabels) {
|
||||
final StringBuilder csv = new StringBuilder();
|
||||
int i = 0;
|
||||
for (final long bucketId : buckets.keySet()) {
|
||||
final Percentiles percentiles = buckets.get(bucketId).getPercentiles();
|
||||
|
||||
buckets.forEachOrdered((final long bucketId, final PercentilesAggregator percentilesAggregator) -> {
|
||||
final Percentiles percentiles = percentilesAggregator.getPercentiles();
|
||||
csv.append(String.format(Locale.US, "%d,%d,%d,%d,%d,%d", //
|
||||
bucketId / 1000, //
|
||||
percentiles.get("0.000"), //
|
||||
@@ -88,8 +87,8 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator {
|
||||
percentiles.get("100.000")//
|
||||
));
|
||||
csv.append("\n");
|
||||
i++;
|
||||
}
|
||||
});
|
||||
|
||||
return csv.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.lucares.collections.LongObjHashMap;
|
||||
import org.lucares.pdb.api.DateTimeRange;
|
||||
import org.lucares.pdb.datastore.internal.LongToDateBucket;
|
||||
|
||||
@@ -61,12 +62,15 @@ public class Interval {
|
||||
return epochMilli - epochMilli % 3600000 + 1800000;
|
||||
case DAY:
|
||||
return epochMilli - epochMilli % 86400000 + 43200000;
|
||||
// case WEEK:
|
||||
// return "YYYY-ww"; // use week based year! Otherwise intervals over the year boundary will be wrong
|
||||
// case MONTH:
|
||||
// return "yyyy-MM";
|
||||
// case YEAR:
|
||||
// return "yyyy";
|
||||
case WEEK:
|
||||
return epochMilli - epochMilli % (7 * 24 * 3600 * 1000) + 7 * 24 * 3600 * 500; // use week based year!
|
||||
// Otherwise intervals over
|
||||
// the year boundary will be
|
||||
// wrong
|
||||
case MONTH:
|
||||
return epochMilli - epochMilli % (30 * 24 * 3600 * 1000L) + 30 * 24 * 3600 * 500L;
|
||||
case YEAR:
|
||||
return epochMilli - epochMilli % (365 * 24 * 3600 * 1000L) + 365 * 24 * 3600 * 500L;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected value: " + intervalTimeUnit);
|
||||
}
|
||||
@@ -104,4 +108,21 @@ public class Interval {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T> LongObjHashMap<T> getMiddleTimeBuckets(final Supplier<T> initialValueSupplier) {
|
||||
final LongObjHashMap<T> result = new LongObjHashMap<>();
|
||||
|
||||
long current = dateTimeRange.getStart().toInstant().toEpochMilli();
|
||||
final long end = dateTimeRange.getEnd().toInstant().toEpochMilli() + intervalTimeUnit.toMillis();
|
||||
|
||||
while (current <= end) {
|
||||
|
||||
final long id = toBucketMiddleTime(current);
|
||||
System.out.println("add bucket: " + id);
|
||||
result.put(id, initialValueSupplier.get());
|
||||
current += intervalTimeUnit.toMillis();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,4 +34,25 @@ public enum IntervalTimeUnit {
|
||||
throw new IllegalArgumentException("Unexpected value: " + this);
|
||||
}
|
||||
}
|
||||
|
||||
public long toMillis() {
|
||||
switch (this) {
|
||||
case SECOND:
|
||||
return 1000;
|
||||
case MINUTE:
|
||||
return 60 * 1000;
|
||||
case HOUR:
|
||||
return 3600 * 1000;
|
||||
case DAY:
|
||||
return 24 * 3600 * 1000;
|
||||
case WEEK:
|
||||
return 7 * 24 * 3600 * 1000;
|
||||
case MONTH:
|
||||
return 30 * 24 * 3600 * 1000L;
|
||||
case YEAR:
|
||||
return 365 * 24 * 3600 * 1000L;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected value: " + this);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user