1919import org .elasticsearch .core .Releasables ;
2020
2121import java .util .ArrayList ;
22+ import java .util .Arrays ;
2223import java .util .List ;
2324import java .util .function .Consumer ;
2425
2526import static org .hamcrest .Matchers .equalTo ;
27+ import static org .hamcrest .Matchers .greaterThan ;
2628
2729public class TopNBlockHashTests extends BlockHashTestCase {
2830
@@ -73,7 +75,7 @@ public void testLongHash() {
7375 } else {
7476 assertThat (
7577 ordsAndKeys .description (),
76- equalTo ("LongTopNBlockHash{channel=0, " + topNParametersString (4 ) + ", hasNull=false}" )
78+ equalTo ("LongTopNBlockHash{channel=0, " + topNParametersString (4 , 0 ) + ", hasNull=false}" )
7779 );
7880 if (limit == LIMIT_HIGH ) {
7981 assertKeys (ordsAndKeys .keys (), 2L , 1L , 4L , 3L );
@@ -94,6 +96,40 @@ public void testLongHash() {
9496 }, blockFactory .newLongArrayVector (values , values .length ).asBlock ());
9597 }
9698
99+ public void testLongHashBatched () {
100+ long [][] arrays = { new long [] { 2 , 1 , 4 , 2 }, new long [] { 4 , 1 , 3 , 4 } };
101+
102+ hashBatchesCallbackOnLast (ordsAndKeys -> {
103+ if (forcePackedHash ) {
104+ // TODO: Not tested yet
105+ } else {
106+ assertThat (
107+ ordsAndKeys .description (),
108+ equalTo ("LongTopNBlockHash{channel=0, " + topNParametersString (4 , asc ? 0 : 1 ) + ", hasNull=false}" )
109+ );
110+ if (limit == LIMIT_HIGH ) {
111+ assertKeys (ordsAndKeys .keys (), 2L , 1L , 4L , 3L );
112+ assertOrds (ordsAndKeys .ords (), 3 , 2 , 4 , 3 );
113+ assertThat (ordsAndKeys .nonEmpty (), equalTo (intRange (1 , 5 )));
114+ } else {
115+ if (asc ) {
116+ assertKeys (ordsAndKeys .keys (), 2L , 1L );
117+ assertOrds (ordsAndKeys .ords (), null , 2 , null , null );
118+ assertThat (ordsAndKeys .nonEmpty (), equalTo (intVector (1 , 2 )));
119+ } else {
120+ assertKeys (ordsAndKeys .keys (), 4L , 3L );
121+ assertOrds (ordsAndKeys .ords (), 2 , null , 3 , 2 );
122+ assertThat (ordsAndKeys .nonEmpty (), equalTo (intVector (2 , 3 )));
123+ }
124+ }
125+ }
126+ },
127+ Arrays .stream (arrays )
128+ .map (array -> new Block [] { blockFactory .newLongArrayVector (array , array .length ).asBlock () })
129+ .toArray (Block [][]::new )
130+ );
131+ }
132+
97133 public void testLongHashWithNulls () {
98134 try (LongBlock .Builder builder = blockFactory .newLongBlockBuilder (4 )) {
99135 builder .appendLong (0 );
@@ -111,7 +147,7 @@ public void testLongHashWithNulls() {
111147 ordsAndKeys .description (),
112148 equalTo (
113149 "LongTopNBlockHash{channel=0, "
114- + topNParametersString (hasTwoNonNullValues ? 2 : 1 )
150+ + topNParametersString (hasTwoNonNullValues ? 2 : 1 , 0 )
115151 + ", hasNull="
116152 + hasNull
117153 + "}"
@@ -172,7 +208,7 @@ public void testLongHashWithMultiValuedFields() {
172208 if (limit == LIMIT_HIGH ) {
173209 assertThat (
174210 ordsAndKeys .description (),
175- equalTo ("LongTopNBlockHash{channel=0, " + topNParametersString (3 ) + ", hasNull=true}" )
211+ equalTo ("LongTopNBlockHash{channel=0, " + topNParametersString (3 , 0 ) + ", hasNull=true}" )
176212 );
177213 assertOrds (
178214 ordsAndKeys .ords (),
@@ -188,7 +224,11 @@ public void testLongHashWithMultiValuedFields() {
188224 assertThat (
189225 ordsAndKeys .description (),
190226 equalTo (
191- "LongTopNBlockHash{channel=0, " + topNParametersString (nullsFirst ? 1 : 2 ) + ", hasNull=" + nullsFirst + "}"
227+ "LongTopNBlockHash{channel=0, "
228+ + topNParametersString (nullsFirst ? 1 : 2 , 0 )
229+ + ", hasNull="
230+ + nullsFirst
231+ + "}"
192232 )
193233 );
194234 if (nullsFirst ) {
@@ -279,12 +319,44 @@ private void hash(Consumer<OrdsAndKeys> callback, Block... values) {
279319 }
280320 }
281321
282- private void hash (Consumer <OrdsAndKeys > callback , int emitBatchSize , Block .Builder ... values ) {
283- Block [] blocks = Block .Builder .buildAll (values );
284- try (BlockHash hash = buildBlockHash (emitBatchSize , blocks )) {
285- hash (true , hash , callback , blocks );
322+ // TODO: Randomize this instead?
323+ /**
324+ * Hashes multiple separated batches of values.
325+ *
326+ * @param callback Callback with the OrdsAndKeys for the last batch
327+ */
328+ private void hashBatchesCallbackOnLast (Consumer <OrdsAndKeys > callback , Block []... batches ) {
329+ // Ensure all batches share the same specs
330+ assertThat (batches .length , greaterThan (0 ));
331+ for (Block [] batch : batches ) {
332+ assertThat (batch .length , equalTo (batches [0 ].length ));
333+ for (int i = 0 ; i < batch .length ; i ++) {
334+ assertThat (batches [0 ][i ].elementType (), equalTo (batch [i ].elementType ()));
335+ }
336+ }
337+
338+ boolean [] called = new boolean [] { false };
339+ try (BlockHash hash = buildBlockHash (16 * 1024 , batches [0 ])) {
340+ for (Block [] batch : batches ) {
341+ called [0 ] = false ;
342+ hash (true , hash , ordsAndKeys -> {
343+ if (called [0 ]) {
344+ throw new IllegalStateException ("hash produced more than one block" );
345+ }
346+ called [0 ] = true ;
347+ if (batch == batches [batches .length - 1 ]) {
348+ callback .accept (ordsAndKeys );
349+ }
350+ try (ReleasableIterator <IntBlock > lookup = hash .lookup (new Page (batch ), ByteSizeValue .ofKb (between (1 , 100 )))) {
351+ assertThat (lookup .hasNext (), equalTo (true ));
352+ try (IntBlock ords = lookup .next ()) {
353+ assertThat (ords , equalTo (ordsAndKeys .ords ()));
354+ }
355+ }
356+ }, batch );
357+ }
286358 } finally {
287- Releasables .closeExpectNoException ( blocks );
359+ Releasables .close ( Arrays . stream ( batches ). flatMap ( Arrays :: stream ). toList () );
288360 }
289361 }
290362
@@ -304,7 +376,14 @@ private BlockHash buildBlockHash(int emitBatchSize, Block... values) {
304376 /**
305377 * Returns the common toString() part of the TopNBlockHash using the test parameters.
306378 */
307- private String topNParametersString (int differentValues ) {
308- return "asc=" + asc + ", nullsFirst=" + nullsFirst + ", limit=" + limit + ", entries=" + Math .min (differentValues , limit );
379+ private String topNParametersString (int differentValues , int unusedInsertedValues ) {
380+ return "asc="
381+ + asc
382+ + ", nullsFirst="
383+ + nullsFirst
384+ + ", limit="
385+ + limit
386+ + ", entries="
387+ + Math .min (differentValues , limit + unusedInsertedValues );
309388 }
310389}
0 commit comments