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;
|
package org.lucares.pdb.plot.api;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.lucares.collections.LongObjHashMap;
|
||||||
import org.lucares.recommind.logs.GnuplotAxis;
|
import org.lucares.recommind.logs.GnuplotAxis;
|
||||||
|
|
||||||
public class BoxAggregator implements CustomAggregator, IndexedAggregator {
|
public class BoxAggregator implements CustomAggregator, IndexedAggregator {
|
||||||
|
|
||||||
private static final double SPACE_BETWEEN_BARS = 0.6;
|
|
||||||
private Long index = null;
|
private Long index = null;
|
||||||
private Long numberOfDataSeries;
|
private Long numberOfDataSeries;
|
||||||
|
|
||||||
@@ -17,19 +15,20 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator {
|
|||||||
|
|
||||||
private final Interval interval;
|
private final Interval interval;
|
||||||
|
|
||||||
private final Map<Long, PercentilesAggregator> buckets = new HashMap<>();
|
private final LongObjHashMap<PercentilesAggregator> buckets;
|
||||||
|
|
||||||
public BoxAggregator(final PlotSettings settings) {
|
public BoxAggregator(final PlotSettings settings) {
|
||||||
|
|
||||||
this.interval = settings.getInterval().get();
|
this.interval = settings.getInterval().get();
|
||||||
|
this.buckets = interval.getMiddleTimeBuckets(PercentilesAggregator::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addValue(final long epochMilli, final long value) {
|
public void addValue(final long epochMilli, final long value) {
|
||||||
|
|
||||||
final long bucketId = interval.toBucketMiddleTime(epochMilli);
|
final long bucketId = interval.toBucketMiddleTime(epochMilli);
|
||||||
buckets.putIfAbsent(bucketId, new PercentilesAggregator());
|
final PercentilesAggregator bucket = buckets.get(bucketId);
|
||||||
buckets.get(bucketId).addValue(epochMilli, value);
|
bucket.addValue(epochMilli, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -76,9 +75,9 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator {
|
|||||||
|
|
||||||
public String asCsv(final boolean renderLabels) {
|
public String asCsv(final boolean renderLabels) {
|
||||||
final StringBuilder csv = new StringBuilder();
|
final StringBuilder csv = new StringBuilder();
|
||||||
int i = 0;
|
|
||||||
for (final long bucketId : buckets.keySet()) {
|
buckets.forEachOrdered((final long bucketId, final PercentilesAggregator percentilesAggregator) -> {
|
||||||
final Percentiles percentiles = buckets.get(bucketId).getPercentiles();
|
final Percentiles percentiles = percentilesAggregator.getPercentiles();
|
||||||
csv.append(String.format(Locale.US, "%d,%d,%d,%d,%d,%d", //
|
csv.append(String.format(Locale.US, "%d,%d,%d,%d,%d,%d", //
|
||||||
bucketId / 1000, //
|
bucketId / 1000, //
|
||||||
percentiles.get("0.000"), //
|
percentiles.get("0.000"), //
|
||||||
@@ -88,8 +87,8 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator {
|
|||||||
percentiles.get("100.000")//
|
percentiles.get("100.000")//
|
||||||
));
|
));
|
||||||
csv.append("\n");
|
csv.append("\n");
|
||||||
i++;
|
});
|
||||||
}
|
|
||||||
return csv.toString();
|
return csv.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.lucares.collections.LongObjHashMap;
|
||||||
import org.lucares.pdb.api.DateTimeRange;
|
import org.lucares.pdb.api.DateTimeRange;
|
||||||
import org.lucares.pdb.datastore.internal.LongToDateBucket;
|
import org.lucares.pdb.datastore.internal.LongToDateBucket;
|
||||||
|
|
||||||
@@ -61,12 +62,15 @@ public class Interval {
|
|||||||
return epochMilli - epochMilli % 3600000 + 1800000;
|
return epochMilli - epochMilli % 3600000 + 1800000;
|
||||||
case DAY:
|
case DAY:
|
||||||
return epochMilli - epochMilli % 86400000 + 43200000;
|
return epochMilli - epochMilli % 86400000 + 43200000;
|
||||||
// case WEEK:
|
case WEEK:
|
||||||
// return "YYYY-ww"; // use week based year! Otherwise intervals over the year boundary will be wrong
|
return epochMilli - epochMilli % (7 * 24 * 3600 * 1000) + 7 * 24 * 3600 * 500; // use week based year!
|
||||||
// case MONTH:
|
// Otherwise intervals over
|
||||||
// return "yyyy-MM";
|
// the year boundary will be
|
||||||
// case YEAR:
|
// wrong
|
||||||
// return "yyyy";
|
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:
|
default:
|
||||||
throw new IllegalArgumentException("Unexpected value: " + intervalTimeUnit);
|
throw new IllegalArgumentException("Unexpected value: " + intervalTimeUnit);
|
||||||
}
|
}
|
||||||
@@ -104,4 +108,21 @@ public class Interval {
|
|||||||
|
|
||||||
return result;
|
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);
|
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