Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/132456.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 132456
summary: Some optimizations for constant blocks
area: ES|QL
type: enhancement
issues: []

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,13 @@ private void addRawInput(int positionOffset, IntBigArrayBlock groups, Block valu
* This method is called for count all.
*/
private void addRawInput(IntVector groups) {
for (int groupPosition = 0; groupPosition < groups.getPositionCount(); groupPosition++) {
int groupId = groups.getInt(groupPosition);
state.increment(groupId, 1);
if (groups.isConstant()) {
state.increment(groups.getInt(0), groups.getPositionCount());
} else {
for (int groupPosition = 0; groupPosition < groups.getPositionCount(); groupPosition++) {
int groupId = groups.getInt(groupPosition);
state.increment(groupId, 1);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,21 @@ static void addOrdinalInputVector(
IntVector ordinalIds,
IntVector hashIds
) {
for (int p = 0; p < groupIds.getPositionCount(); p++) {
int groupId = groupIds.getInt(p);
int ord = ordinalIds.getInt(p + positionOffset);
state.addValueOrdinal(groupId, hashIds.getInt(ord));
if (groupIds.isConstant() && hashIds.isConstant()) {
state.addValueOrdinal(groupIds.getInt(0), hashIds.getInt(0));
return;
}
int lastGroup = groupIds.getInt(0);
int lastOrd = ordinalIds.getInt(positionOffset);
state.addValueOrdinal(lastGroup, hashIds.getInt(lastOrd));
for (int p = 1; p < groupIds.getPositionCount(); p++) {
final int nextGroup = groupIds.getInt(p);
final int nextOrd = ordinalIds.getInt(p + positionOffset);
if (nextGroup != lastGroup || nextOrd != lastOrd) {
lastGroup = nextGroup;
lastOrd = nextOrd;
state.addValueOrdinal(lastGroup, hashIds.getInt(lastOrd));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,40 @@ public void add(IntBlock bytesHashes, LongBlock longsBlock, GroupingAggregatorFu
public IntVector add(IntVector bytesHashes, LongVector longsVector) {
int positions = bytesHashes.getPositionCount();
final int[] ords = new int[positions];
for (int i = 0; i < positions; i++) {
ords[i] = Math.toIntExact(hashOrdToGroup(finalHash.add(bytesHashes.getInt(i), longsVector.getLong(i))));
int lastByte = bytesHashes.getInt(0);
long lastLong = longsVector.getLong(0);
ords[0] = Math.toIntExact(hashOrdToGroup(finalHash.add(lastByte, lastLong)));
boolean constant = true;
if (bytesHashes.isConstant()) {
for (int i = 1; i < positions; i++) {
final long nextLong = longsVector.getLong(i);
if (nextLong == lastLong) {
ords[i] = ords[i - 1];
} else {
ords[i] = Math.toIntExact(hashOrdToGroup(finalHash.add(lastByte, nextLong)));
lastLong = nextLong;
constant = false;
}
}
} else {
for (int i = 1; i < positions; i++) {
final int nextByte = bytesHashes.getInt(i);
final long nextLong = longsVector.getLong(i);
if (nextByte == lastByte && nextLong == lastLong) {
ords[i] = ords[i - 1];
} else {
ords[i] = Math.toIntExact(hashOrdToGroup(finalHash.add(nextByte, nextLong)));
lastByte = nextByte;
lastLong = nextLong;
constant = false;
}
}
}
if (constant) {
return blockFactory.newConstantIntVector(ords[0], positions);
} else {
return blockFactory.newIntArrayVector(ords, positions);
}
return blockFactory.newIntArrayVector(ords, positions);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ final class $Type$BlockHash extends BlockHash {
*/
IntVector add($Type$Vector vector) {
$if(BytesRef)$
if (vector.isConstant()) {
BytesRef v = vector.getBytesRef(0, new BytesRef());
int groupId = Math.toIntExact(hashOrdToGroupNullReserved(hash.add(v)));
return blockFactory.newConstantIntVector(groupId, vector.getPositionCount());
}
var ordinals = vector.asOrdinals();
if (ordinals != null) {
return addOrdinalsVector(ordinals);
Expand Down Expand Up @@ -168,15 +173,18 @@ $endif$
$if(BytesRef)$
private IntVector addOrdinalsVector(OrdinalBytesRefVector inputBlock) {
IntVector inputOrds = inputBlock.getOrdinalsVector();
try (
var builder = blockFactory.newIntVectorBuilder(inputOrds.getPositionCount());
var hashOrds = add(inputBlock.getDictionaryVector())
) {
for (int p = 0; p < inputOrds.getPositionCount(); p++) {
int ord = hashOrds.getInt(inputOrds.getInt(p));
builder.appendInt(ord);
try (var hashOrds = add(inputBlock.getDictionaryVector())) {
if (inputOrds.isConstant()) {
int ord = hashOrds.getInt(inputOrds.getInt(0));
return blockFactory.newConstantIntVector(ord, inputOrds.getPositionCount());
}
try (var builder = blockFactory.newIntVectorBuilder(inputOrds.getPositionCount())) {
for (int p = 0; p < inputOrds.getPositionCount(); p++) {
int ord = hashOrds.getInt(inputOrds.getInt(p));
builder.appendInt(ord);
}
return builder.build();
}
return builder.build();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.elasticsearch.compute.data.BytesRefBlock;
import org.elasticsearch.compute.data.BytesRefVector;
import org.elasticsearch.compute.data.IntBlock;
import org.elasticsearch.compute.data.IntVector;
import org.elasticsearch.compute.data.OrdinalBytesRefBlock;
import org.elasticsearch.compute.operator.BreakingBytesRefBuilder;
import org.elasticsearch.core.Releasable;
Expand Down Expand Up @@ -64,6 +65,41 @@ public SingletonOrdinalsBuilder endPositionEntry() {
throw new UnsupportedOperationException("should only have one value per doc");
}

BytesRefBlock tryBuildConstantBlock() {
if (minOrd == maxOrd) {
boolean seenNulls = false;
for (int ord : ords) {
if (ord == -1) {
seenNulls = true;
break;
}
}
if (seenNulls == false) {
final BytesRef v;
try {
v = BytesRef.deepCopyOf(docValues.lookupOrd(minOrd));
} catch (IOException e) {
throw new UncheckedIOException("failed to lookup ordinals", e);
}
BytesRefVector bytes = null;
IntVector ordinals = null;
boolean success = false;
try {
bytes = blockFactory.newConstantBytesRefVector(v, 1);
ordinals = blockFactory.newConstantIntVector(0, ords.length);
final var result = new OrdinalBytesRefBlock(ordinals.asBlock(), bytes);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, we choose to return an ordinal constant block instead of a direct constant block to ensure that ordinal optimizations are applied if the constant optimization is not available.

success = true;
return result;
} finally {
if (success == false) {
Releasables.close(bytes, ordinals);
}
}
}
}
return null;
}

BytesRefBlock buildOrdinal() {
int valueCount = maxOrd - minOrd + 1;
long breakerSize = ordsSize(valueCount);
Expand Down Expand Up @@ -172,6 +208,10 @@ public long estimatedBytes() {

@Override
public BytesRefBlock build() {
var constantBlock = tryBuildConstantBlock();
if (constantBlock != null) {
return constantBlock;
}
return shouldBuildOrdinalsBlock() ? buildOrdinal() : buildRegularBlock();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1715,4 +1715,76 @@ private BlockHash buildBlockHash(int emitBatchSize, Block... values) {
? new PackedValuesBlockHash(specs, blockFactory, emitBatchSize)
: BlockHash.build(specs, blockFactory, emitBatchSize, true);
}

public void testConstant() {
try (
var hash = new BytesRefLongBlockHash(blockFactory, 0, 1, false, randomIntBetween(1, 1000));
var bytesHash = new BytesRefBlockHash(0, blockFactory)
) {
int iters = between(1, 20);
for (int i = 0; i < iters; i++) {
final BytesRefBlock bytes;
final LongBlock longs;
final boolean constantInput = randomBoolean();
final int positions = randomIntBetween(1, 100);
if (constantInput) {
bytes = blockFactory.newConstantBytesRefBlockWith(new BytesRef(randomAlphaOfLength(10)), positions);
if (randomBoolean()) {
try (IntVector hashIds = bytesHash.add(bytes.asVector())) {
assertTrue(hashIds.isConstant());
}
}
if (randomBoolean()) {
longs = blockFactory.newConstantLongBlockWith(randomNonNegativeLong(), positions);
} else {
long value = randomNonNegativeLong();
try (var builder = blockFactory.newLongVectorFixedBuilder(positions)) {
for (int p = 0; p < positions; p++) {
builder.appendLong(value);
}
longs = builder.build().asBlock();
}
}
} else {
try (var builder = blockFactory.newBytesRefBlockBuilder(positions)) {
for (int p = 0; p < positions; p++) {
builder.appendBytesRef(new BytesRef(randomAlphaOfLength(10)));
}
bytes = builder.build();
}
try (var builder = blockFactory.newLongVectorFixedBuilder(positions)) {
for (int p = 0; p < positions; p++) {
builder.appendLong(randomNonNegativeLong());
}
longs = builder.build().asBlock();
}
}
try (Page page = new Page(bytes, longs)) {
hash.add(page, new GroupingAggregatorFunction.AddInput() {
@Override
public void add(int positionOffset, IntArrayBlock groupIds) {
fail("should not call IntArrayBlock");
}

@Override
public void add(int positionOffset, IntBigArrayBlock groupIds) {
fail("should not call IntBigArrayBlock");
}

@Override
public void add(int positionOffset, IntVector groupIds) {
if (constantInput) {
assertTrue(groupIds.isConstant());
}
}

@Override
public void close() {

}
});
}
}
}
}
}
Loading