77
88package org .elasticsearch .xpack .esql .action ;
99
10+ import org .elasticsearch .action .admin .indices .create .CreateIndexRequestBuilder ;
1011import org .elasticsearch .common .settings .Settings ;
1112import org .elasticsearch .index .mapper .extras .MapperExtrasPlugin ;
1213import org .elasticsearch .plugins .Plugin ;
@@ -276,83 +277,42 @@ public void testLookupJoinOthers() {
276277 }
277278
278279 private void testLookupJoinTypes (String group ) {
279- initIndexes (group );
280- initData (group );
281- for (TestConfig config : testConfigurations .get (group ).configs .values ()) {
280+ TestConfigs configs = testConfigurations .get (group );
281+ initIndexes (configs );
282+ initData (configs );
283+ for (TestConfig config : configs .values ()) {
282284 if ((isValidDataType (config .mainType ()) && isValidDataType (config .lookupType ())) == false ) {
283285 continue ;
284286 }
285- String mainField = config .mainFieldName ();
286- String lookupField = config .lookupFieldName ();
287- String lookupIndex = config .lookupIndexName ();
288- String query = "FROM "
289- + MAIN_INDEX
290- + " | RENAME "
291- + mainField
292- + " AS "
293- + lookupField
294- + " | LOOKUP JOIN "
295- + lookupIndex
296- + " ON "
297- + lookupField
298- + " | KEEP other" ;
299287 config .validateMainIndex ();
300288 config .validateLookupIndex ();
301- config .testQuery (query );
289+
290+ config .doTest ();
302291 }
303292 }
304293
305- private void initIndexes (String group ) {
306- Collection <TestConfig > configs = testConfigurations .get (group ).configs .values ();
307- String propertyPrefix = "{\n \" properties\" : {\n " ;
308- String propertySuffix = " }\n }\n " ;
309- // The main index will have many fields, one of each type to use in later type specific joins
310- String mainFields = propertyPrefix + configs .stream ()
311- .map (TestConfig ::mainPropertySpec )
312- .distinct ()
313- .collect (Collectors .joining (",\n " )) + propertySuffix ;
314- assertAcked (prepareCreate (MAIN_INDEX ).setMapping (mainFields ));
315-
316- Settings .Builder settings = Settings .builder ()
317- .put ("index.number_of_shards" , 1 )
318- .put ("index.number_of_replicas" , 0 )
319- .put ("index.mode" , "lookup" );
320- configs .forEach (
321- // Each lookup index will get a document with a field to join on, and a results field to get back
322- (c ) -> assertAcked (
323- prepareCreate (c .lookupIndexName ()).setSettings (settings .build ())
324- .setMapping (propertyPrefix + c .lookupPropertySpec () + propertySuffix )
325- )
326- );
294+ private void initIndexes (TestConfigs configs ) {
295+ for (TestMapping mapping : configs .indices ()) {
296+ CreateIndexRequestBuilder builder = prepareCreate (mapping .indexName ).setMapping (mapping .properties );
297+ if (mapping .settings != null ) {
298+ builder = builder .setSettings (mapping .settings );
299+ }
300+ assertAcked (builder );
301+ }
327302 }
328303
329- private void initData (String group ) {
330- Collection <TestConfig > configs = testConfigurations .get (group ).configs .values ();
331- int docId = 0 ;
332- for (TestConfig config : configs ) {
333- String doc = String .format (Locale .ROOT , """
334- {
335- %s,
336- "other": "value"
337- }
338- """ , lookupPropertyFor (config ));
339- index (config .lookupIndexName (), "" + (++docId ), doc );
340- refresh (config .lookupIndexName ());
341- }
342- List <String > mainProperties = configs .stream ().map (this ::mainPropertyFor ).distinct ().collect (Collectors .toList ());
343- index (MAIN_INDEX , "1" , String .format (Locale .ROOT , """
344- {
345- %s
346- }
347- """ , String .join (",\n " , mainProperties )));
348- refresh (MAIN_INDEX );
304+ private void initData (TestConfigs configs ) {
305+ for (TestDocument doc : configs .docs ()) {
306+ index (doc .indexName , doc .id , doc .source );
307+ refresh (doc .indexName );
308+ }
349309 }
350310
351- private String lookupPropertyFor (TestConfig config ) {
311+ private static String lookupPropertyFor (TestConfig config ) {
352312 return String .format (Locale .ROOT , "\" %s\" : %s" , config .lookupFieldName (), sampleDataTextFor (config .lookupType ()));
353313 }
354314
355- private String mainPropertyFor (TestConfig config ) {
315+ private static String mainPropertyFor (TestConfig config ) {
356316 return String .format (Locale .ROOT , "\" %s\" : %s" , config .mainFieldName (), sampleDataTextFor (config .mainType ()));
357317 }
358318
@@ -388,6 +348,10 @@ private static Object sampleDataFor(DataType type) {
388348 };
389349 }
390350
351+ private record TestMapping (String indexName , String properties , Settings settings ) {};
352+
353+ private record TestDocument (String indexName , String id , String source ) {};
354+
391355 private static class TestConfigs {
392356 final String group ;
393357 final Map <String , TestConfig > configs ;
@@ -397,6 +361,66 @@ private static class TestConfigs {
397361 this .configs = new LinkedHashMap <>();
398362 }
399363
364+ protected List <TestMapping > indices () {
365+ List <TestMapping > results = new ArrayList <>();
366+
367+ String propertyPrefix = "{\n \" properties\" : {\n " ;
368+ String propertySuffix = " }\n }\n " ;
369+ // The main index will have many fields, one of each type to use in later type specific joins
370+ String mainFields = propertyPrefix + configs .values ()
371+ .stream ()
372+ .map (TestConfig ::mainPropertySpec )
373+ .distinct ()
374+ .collect (Collectors .joining (",\n " )) + propertySuffix ;
375+
376+ results .add (new TestMapping (MAIN_INDEX , mainFields , null ));
377+
378+ Settings .Builder settings = Settings .builder ()
379+ .put ("index.number_of_shards" , 1 )
380+ .put ("index.number_of_replicas" , 0 )
381+ .put ("index.mode" , "lookup" );
382+ configs .values ()
383+ .forEach (
384+ // Each lookup index will get a document with a field to join on, and a results field to get back
385+ (c ) -> results .add (
386+ new TestMapping (c .lookupIndexName (), propertyPrefix + c .lookupPropertySpec () + propertySuffix , settings .build ())
387+ )
388+ );
389+
390+ return results ;
391+ }
392+
393+ protected List <TestDocument > docs () {
394+ List <TestDocument > results = new ArrayList <>();
395+
396+ int docId = 0 ;
397+ for (TestConfig config : configs .values ()) {
398+ String doc = String .format (Locale .ROOT , """
399+ {
400+ %s,
401+ "other": "value"
402+ }
403+ """ , lookupPropertyFor (config ));
404+ results .add (new TestDocument (config .lookupIndexName (), "" + (++docId ), doc ));
405+ }
406+ List <String > mainProperties = configs .values ()
407+ .stream ()
408+ .map (LookupJoinTypesIT ::mainPropertyFor )
409+ .distinct ()
410+ .collect (Collectors .toList ());
411+ results .add (new TestDocument (MAIN_INDEX , "1" , String .format (Locale .ROOT , """
412+ {
413+ %s
414+ }
415+ """ , String .join (",\n " , mainProperties ))));
416+
417+ return results ;
418+ }
419+
420+ private Collection <TestConfig > values () {
421+ return configs .values ();
422+ }
423+
400424 private boolean exists (String indexName ) {
401425 return configs .containsKey (indexName );
402426 }
@@ -472,6 +496,13 @@ default String mainPropertySpec() {
472496 return propertySpecFor (mainFieldName (), mainType (), "" );
473497 }
474498
499+ /**
500+ * If the main field is supposed to be a union type, this will be the property spec for the second index.
501+ */
502+ default String secondMainPropertySpecForUnionTypes () {
503+ return propertySpecFor (mainFieldName (), mainType (), "" );
504+ }
505+
475506 default String lookupPropertySpec () {
476507 return propertySpecFor (lookupFieldName (), lookupType (), ", \" other\" : { \" type\" : \" keyword\" }" );
477508 }
@@ -486,7 +517,23 @@ default void validateLookupIndex() {
486517 validateIndex (lookupIndexName (), lookupFieldName (), sampleDataFor (lookupType ()));
487518 }
488519
489- void testQuery (String query );
520+ default String testQuery () {
521+ String mainField = mainFieldName ();
522+ String lookupField = lookupFieldName ();
523+ String lookupIndex = lookupIndexName ();
524+
525+ return String .format (
526+ Locale .ROOT ,
527+ "FROM %s | RENAME %s AS %s | LOOKUP JOIN %s ON %s | KEEP other" ,
528+ MAIN_INDEX ,
529+ mainField ,
530+ lookupField ,
531+ lookupIndex ,
532+ lookupField
533+ );
534+ }
535+
536+ void doTest ();
490537 }
491538
492539 private static String propertySpecFor (String fieldName , DataType type , String extra ) {
@@ -516,7 +563,8 @@ private static void validateIndex(String indexName, String fieldName, Object exp
516563
517564 private record TestConfigPasses (DataType mainType , DataType lookupType , boolean hasResults ) implements TestConfig {
518565 @ Override
519- public void testQuery (String query ) {
566+ public void doTest () {
567+ String query = testQuery ();
520568 try (var response = EsqlQueryRequestBuilder .newRequestBuilder (client ()).query (query ).get ()) {
521569 Iterator <Object > results = response .response ().column (0 ).iterator ();
522570 assertTrue ("Expected at least one result for query: " + query , results .hasNext ());
@@ -534,7 +582,8 @@ private record TestConfigFails<E extends Exception>(DataType mainType, DataType
534582 implements
535583 TestConfig {
536584 @ Override
537- public void testQuery (String query ) {
585+ public void doTest () {
586+ String query = testQuery ();
538587 E e = expectThrows (
539588 exception (),
540589 "Expected exception " + exception ().getSimpleName () + " but no exception was thrown: " + query ,
0 commit comments