|
11 | 11 | import org.elasticsearch.common.unit.ByteSizeValue; |
12 | 12 | import org.elasticsearch.common.util.BigArrays; |
13 | 13 | import org.elasticsearch.common.util.BitArray; |
| 14 | +import org.elasticsearch.common.util.BytesRefArray; |
14 | 15 | import org.elasticsearch.common.util.LongLongHash; |
15 | 16 | import org.elasticsearch.compute.aggregation.GroupingAggregatorFunction; |
16 | 17 | import org.elasticsearch.compute.aggregation.SeenGroupIds; |
|
22 | 23 | import org.elasticsearch.compute.data.IntVector; |
23 | 24 | import org.elasticsearch.compute.data.LongBlock; |
24 | 25 | import org.elasticsearch.compute.data.LongVector; |
| 26 | +import org.elasticsearch.compute.data.OrdinalBytesRefBlock; |
25 | 27 | import org.elasticsearch.compute.data.Page; |
26 | 28 | import org.elasticsearch.compute.operator.mvdedupe.IntLongBlockAdd; |
27 | 29 | import org.elasticsearch.core.ReleasableIterator; |
@@ -143,28 +145,56 @@ public ReleasableIterator<IntBlock> lookup(Page page, ByteSizeValue targetBlockS |
143 | 145 |
|
144 | 146 | @Override |
145 | 147 | public Block[] getKeys() { |
146 | | - int positions = (int) finalHash.size(); |
147 | 148 | BytesRefBlock k1 = null; |
148 | 149 | LongVector k2 = null; |
149 | | - try ( |
150 | | - BytesRefBlock.Builder keys1 = blockFactory.newBytesRefBlockBuilder(positions); |
151 | | - LongVector.Builder keys2 = blockFactory.newLongVectorBuilder(positions) |
152 | | - ) { |
153 | | - BytesRef scratch = new BytesRef(); |
154 | | - for (long i = 0; i < positions; i++) { |
155 | | - keys2.appendLong(finalHash.getKey2(i)); |
156 | | - long h1 = finalHash.getKey1(i); |
157 | | - if (h1 == 0) { |
158 | | - keys1.appendNull(); |
159 | | - } else { |
160 | | - keys1.appendBytesRef(bytesHash.hash.get(h1 - 1, scratch)); |
| 150 | + int positions = (int) finalHash.size(); |
| 151 | + if (OrdinalBytesRefBlock.isDense(positions, bytesHash.hash.size())) { |
| 152 | + try (var ordinals = blockFactory.newIntBlockBuilder(positions); var longs = blockFactory.newLongVectorBuilder(positions)) { |
| 153 | + for (long p = 0; p < positions; p++) { |
| 154 | + long h1 = finalHash.getKey1(p); |
| 155 | + if (h1 == 0) { |
| 156 | + ordinals.appendNull(); |
| 157 | + } else { |
| 158 | + ordinals.appendInt(Math.toIntExact(h1 - 1)); |
| 159 | + } |
| 160 | + longs.appendLong(finalHash.getKey2(p)); |
| 161 | + } |
| 162 | + // TODO: make takeOwnershipOf work? |
| 163 | + BytesRefArray bytes = BytesRefArray.deepCopy(bytesHash.hash.getBytesRefs()); |
| 164 | + try { |
| 165 | + var dict = blockFactory.newBytesRefArrayVector(bytes, Math.toIntExact(bytes.size())); |
| 166 | + bytes = null; // transfer ownership to dict |
| 167 | + k1 = new OrdinalBytesRefBlock(ordinals.build(), dict); |
| 168 | + } finally { |
| 169 | + Releasables.closeExpectNoException(bytes); |
| 170 | + } |
| 171 | + k2 = longs.build(); |
| 172 | + } finally { |
| 173 | + if (k2 == null) { |
| 174 | + Releasables.closeExpectNoException(k1); |
161 | 175 | } |
162 | 176 | } |
163 | | - k1 = keys1.build(); |
164 | | - k2 = keys2.build(); |
165 | | - } finally { |
166 | | - if (k2 == null) { |
167 | | - Releasables.closeExpectNoException(k1); |
| 177 | + } else { |
| 178 | + try ( |
| 179 | + BytesRefBlock.Builder keys1 = blockFactory.newBytesRefBlockBuilder(positions); |
| 180 | + LongVector.Builder keys2 = blockFactory.newLongVectorBuilder(positions) |
| 181 | + ) { |
| 182 | + BytesRef scratch = new BytesRef(); |
| 183 | + for (long i = 0; i < positions; i++) { |
| 184 | + long h1 = finalHash.getKey1(i); |
| 185 | + if (h1 == 0) { |
| 186 | + keys1.appendNull(); |
| 187 | + } else { |
| 188 | + keys1.appendBytesRef(bytesHash.hash.get(h1 - 1, scratch)); |
| 189 | + } |
| 190 | + keys2.appendLong(finalHash.getKey2(i)); |
| 191 | + } |
| 192 | + k1 = keys1.build(); |
| 193 | + k2 = keys2.build(); |
| 194 | + } finally { |
| 195 | + if (k2 == null) { |
| 196 | + Releasables.closeExpectNoException(k1); |
| 197 | + } |
168 | 198 | } |
169 | 199 | } |
170 | 200 | if (reverseOutput) { |
|
0 commit comments