|
@@ -30,8 +30,6 @@ import org.elasticsearch.core.Releasable;
|
|
|
import org.elasticsearch.core.ReleasableIterator;
|
|
|
import org.elasticsearch.core.Releasables;
|
|
|
|
|
|
-import java.util.Objects;
|
|
|
-
|
|
|
/**
|
|
|
* An optimized block hash that receives two blocks: tsid and timestamp, which are sorted.
|
|
|
* Since the incoming data is sorted, this block hash appends the incoming data to the internal arrays without lookup.
|
|
@@ -41,7 +39,7 @@ public final class TimeSeriesBlockHash extends BlockHash {
|
|
|
private final int tsHashChannel;
|
|
|
private final int timestampIntervalChannel;
|
|
|
|
|
|
- private final BytesRef lastTsid = new BytesRef();
|
|
|
+ private int lastTsidPosition = 0;
|
|
|
private final BytesRefArrayWithSize tsidArray;
|
|
|
|
|
|
private long lastTimestamp;
|
|
@@ -64,19 +62,70 @@ public final class TimeSeriesBlockHash extends BlockHash {
|
|
|
Releasables.close(tsidArray, timestampArray, perTsidCountArray);
|
|
|
}
|
|
|
|
|
|
+ private OrdinalBytesRefVector getTsidVector(Page page) {
|
|
|
+ BytesRefBlock block = page.getBlock(tsHashChannel);
|
|
|
+ var ordinalBlock = block.asOrdinals();
|
|
|
+ if (ordinalBlock == null) {
|
|
|
+ throw new IllegalStateException("expected ordinal block for tsid");
|
|
|
+ }
|
|
|
+ var ordinalVector = ordinalBlock.asVector();
|
|
|
+ if (ordinalVector == null) {
|
|
|
+ throw new IllegalStateException("expected ordinal vector for tsid");
|
|
|
+ }
|
|
|
+ return ordinalVector;
|
|
|
+ }
|
|
|
+
|
|
|
+ private LongVector getTimestampVector(Page page) {
|
|
|
+ final LongBlock timestampsBlock = page.getBlock(timestampIntervalChannel);
|
|
|
+ LongVector timestampsVector = timestampsBlock.asVector();
|
|
|
+ if (timestampsVector == null) {
|
|
|
+ throw new IllegalStateException("expected long vector for timestamp");
|
|
|
+ }
|
|
|
+ return timestampsVector;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public void add(Page page, GroupingAggregatorFunction.AddInput addInput) {
|
|
|
- final BytesRefBlock tsidBlock = page.getBlock(tsHashChannel);
|
|
|
- final BytesRefVector tsidVector = Objects.requireNonNull(tsidBlock.asVector(), "tsid input must be a vector");
|
|
|
- final LongBlock timestampBlock = page.getBlock(timestampIntervalChannel);
|
|
|
- final LongVector timestampVector = Objects.requireNonNull(timestampBlock.asVector(), "timestamp input must be a vector");
|
|
|
- try (var ordsBuilder = blockFactory.newIntVectorBuilder(tsidVector.getPositionCount())) {
|
|
|
+ final BytesRefVector tsidDict;
|
|
|
+ final IntVector tsidOrdinals;
|
|
|
+ {
|
|
|
+ final var tsidVector = getTsidVector(page);
|
|
|
+ tsidDict = tsidVector.getDictionaryVector();
|
|
|
+ tsidOrdinals = tsidVector.getOrdinalsVector();
|
|
|
+ }
|
|
|
+ try (var ordsBuilder = blockFactory.newIntVectorBuilder(tsidOrdinals.getPositionCount())) {
|
|
|
final BytesRef spare = new BytesRef();
|
|
|
- // TODO: optimize incoming ordinal block
|
|
|
- for (int i = 0; i < tsidVector.getPositionCount(); i++) {
|
|
|
- final BytesRef tsid = tsidVector.getBytesRef(i, spare);
|
|
|
+ final BytesRef lastTsid = new BytesRef();
|
|
|
+ final LongVector timestampVector = getTimestampVector(page);
|
|
|
+ int lastOrd = -1;
|
|
|
+ for (int i = 0; i < tsidOrdinals.getPositionCount(); i++) {
|
|
|
+ final int newOrd = tsidOrdinals.getInt(i);
|
|
|
+ boolean newGroup = false;
|
|
|
+ if (lastOrd != newOrd) {
|
|
|
+ final var newTsid = tsidDict.getBytesRef(newOrd, spare);
|
|
|
+ if (positionCount() == 0) {
|
|
|
+ newGroup = true;
|
|
|
+ } else if (lastOrd == -1) {
|
|
|
+ tsidArray.get(lastTsidPosition, lastTsid);
|
|
|
+ newGroup = lastTsid.equals(newTsid) == false;
|
|
|
+ } else {
|
|
|
+ newGroup = true;
|
|
|
+ }
|
|
|
+ if (newGroup) {
|
|
|
+ endTsidGroup();
|
|
|
+ lastTsidPosition = tsidArray.count;
|
|
|
+ tsidArray.append(newTsid);
|
|
|
+ }
|
|
|
+ lastOrd = newOrd;
|
|
|
+ }
|
|
|
final long timestamp = timestampVector.getLong(i);
|
|
|
- ordsBuilder.appendInt(addOnePosition(tsid, timestamp));
|
|
|
+ if (newGroup || timestamp != lastTimestamp) {
|
|
|
+ assert newGroup || lastTimestamp >= timestamp : "@timestamp goes backward " + lastTimestamp + " < " + timestamp;
|
|
|
+ timestampArray.append(timestamp);
|
|
|
+ lastTimestamp = timestamp;
|
|
|
+ currentTimestampCount++;
|
|
|
+ }
|
|
|
+ ordsBuilder.appendInt(timestampArray.count - 1);
|
|
|
}
|
|
|
try (var ords = ordsBuilder.build()) {
|
|
|
addInput.add(0, ords);
|
|
@@ -84,24 +133,6 @@ public final class TimeSeriesBlockHash extends BlockHash {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private int addOnePosition(BytesRef tsid, long timestamp) {
|
|
|
- boolean newGroup = false;
|
|
|
- if (positionCount() == 0 || lastTsid.equals(tsid) == false) {
|
|
|
- assert positionCount() == 0 || lastTsid.compareTo(tsid) < 0 : "tsid goes backward ";
|
|
|
- endTsidGroup();
|
|
|
- tsidArray.append(tsid);
|
|
|
- tsidArray.get(tsidArray.count - 1, lastTsid);
|
|
|
- newGroup = true;
|
|
|
- }
|
|
|
- if (newGroup || timestamp != lastTimestamp) {
|
|
|
- assert newGroup || lastTimestamp >= timestamp : "@timestamp goes backward " + lastTimestamp + " < " + timestamp;
|
|
|
- timestampArray.append(timestamp);
|
|
|
- lastTimestamp = timestamp;
|
|
|
- currentTimestampCount++;
|
|
|
- }
|
|
|
- return positionCount() - 1;
|
|
|
- }
|
|
|
-
|
|
|
private void endTsidGroup() {
|
|
|
if (currentTimestampCount > 0) {
|
|
|
perTsidCountArray.append(currentTimestampCount);
|
|
@@ -270,7 +301,6 @@ public final class TimeSeriesBlockHash extends BlockHash {
|
|
|
|
|
|
BytesRefVector toVector() {
|
|
|
BytesRefVector vector = blockFactory.newBytesRefArrayVector(array, count);
|
|
|
- blockFactory.adjustBreaker(vector.ramBytesUsed() - array.bigArraysRamBytesUsed());
|
|
|
array = null;
|
|
|
return vector;
|
|
|
}
|