29
29
import java .io .IOException ;
30
30
import java .time .Duration ;
31
31
import java .util .ArrayList ;
32
+ import java .util .Collections ;
32
33
import java .util .HashMap ;
33
34
import java .util .Iterator ;
34
35
import java .util .List ;
72
73
* @author Peter-Josef Meisch
73
74
* @author Hamid Rahimi
74
75
* @author Illia Ulianov
76
+ * @author Haibo Liu
75
77
* @since 4.4
76
78
*/
77
79
public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
@@ -437,13 +439,10 @@ public <T> List<SearchHits<T>> multiSearch(List<? extends Query> queries, Class<
437
439
Assert .notNull (queries , "queries must not be null" );
438
440
Assert .notNull (clazz , "clazz must not be null" );
439
441
440
- List <MultiSearchQueryParameter > multiSearchQueryParameters = new ArrayList <>(queries .size ());
441
- for (Query query : queries ) {
442
- multiSearchQueryParameters .add (new MultiSearchQueryParameter (query , clazz , getIndexCoordinatesFor (clazz )));
443
- }
444
-
442
+ int size = queries .size ();
445
443
// noinspection unchecked
446
- return doMultiSearch (multiSearchQueryParameters ).stream ().map (searchHits -> (SearchHits <T >) searchHits )
444
+ return multiSearch (queries , Collections .nCopies (size , clazz ), Collections .nCopies (size , index ))
445
+ .stream ().map (searchHits -> (SearchHits <T >) searchHits )
447
446
.collect (Collectors .toList ());
448
447
}
449
448
@@ -454,14 +453,7 @@ public List<SearchHits<?>> multiSearch(List<? extends Query> queries, List<Class
454
453
Assert .notNull (classes , "classes must not be null" );
455
454
Assert .isTrue (queries .size () == classes .size (), "queries and classes must have the same size" );
456
455
457
- List <MultiSearchQueryParameter > multiSearchQueryParameters = new ArrayList <>(queries .size ());
458
- Iterator <Class <?>> it = classes .iterator ();
459
- for (Query query : queries ) {
460
- Class <?> clazz = it .next ();
461
- multiSearchQueryParameters .add (new MultiSearchQueryParameter (query , clazz , getIndexCoordinatesFor (clazz )));
462
- }
463
-
464
- return doMultiSearch (multiSearchQueryParameters );
456
+ return multiSearch (queries , classes , classes .stream ().map (this ::getIndexCoordinatesFor ).toList ());
465
457
}
466
458
467
459
@ Override
@@ -473,14 +465,7 @@ public List<SearchHits<?>> multiSearch(List<? extends Query> queries, List<Class
473
465
Assert .notNull (index , "index must not be null" );
474
466
Assert .isTrue (queries .size () == classes .size (), "queries and classes must have the same size" );
475
467
476
- List <MultiSearchQueryParameter > multiSearchQueryParameters = new ArrayList <>(queries .size ());
477
- Iterator <Class <?>> it = classes .iterator ();
478
- for (Query query : queries ) {
479
- Class <?> clazz = it .next ();
480
- multiSearchQueryParameters .add (new MultiSearchQueryParameter (query , clazz , index ));
481
- }
482
-
483
- return doMultiSearch (multiSearchQueryParameters );
468
+ return multiSearch (queries , classes , Collections .nCopies (queries .size (), index ));
484
469
}
485
470
486
471
@ Override
@@ -497,16 +482,49 @@ public List<SearchHits<?>> multiSearch(List<? extends Query> queries, List<Class
497
482
Iterator <Class <?>> it = classes .iterator ();
498
483
Iterator <IndexCoordinates > indexesIt = indexes .iterator ();
499
484
485
+ Assert .isTrue (!queries .isEmpty (), "queries should have at least 1 query" );
486
+ boolean isSearchTemplateQuery = queries .get (0 ) instanceof SearchTemplateQuery ;
487
+
500
488
for (Query query : queries ) {
489
+ Assert .isTrue ((query instanceof SearchTemplateQuery ) == isSearchTemplateQuery ,
490
+ "SearchTemplateQuery can't be mixed with other types of query in multiple search" );
491
+
501
492
Class <?> clazz = it .next ();
502
493
IndexCoordinates index = indexesIt .next ();
503
494
multiSearchQueryParameters .add (new MultiSearchQueryParameter (query , clazz , index ));
504
495
}
505
496
506
- return doMultiSearch (multiSearchQueryParameters );
497
+ return multiSearch (multiSearchQueryParameters , isSearchTemplateQuery );
498
+ }
499
+
500
+ private List <SearchHits <?>> multiSearch (List <MultiSearchQueryParameter > multiSearchQueryParameters ,
501
+ boolean isSearchTemplateQuery ) {
502
+ return isSearchTemplateQuery ?
503
+ doMultiTemplateSearch (multiSearchQueryParameters .stream ()
504
+ .map (p -> new MultiSearchTemplateQueryParameter ((SearchTemplateQuery ) p .query , p .clazz , p .index ))
505
+ .toList ())
506
+ : doMultiSearch (multiSearchQueryParameters );
507
+ }
508
+
509
+ private List <SearchHits <?>> doMultiTemplateSearch (List <MultiSearchTemplateQueryParameter > mSearchTemplateQueryParameters ) {
510
+ MsearchTemplateRequest request = requestConverter .searchMsearchTemplateRequest (mSearchTemplateQueryParameters ,
511
+ routingResolver .getRouting ());
512
+
513
+ MsearchTemplateResponse <EntityAsMap > response = execute (client -> client .msearchTemplate (request , EntityAsMap .class ));
514
+ List <MultiSearchResponseItem <EntityAsMap >> responseItems = response .responses ();
515
+
516
+ Assert .isTrue (mSearchTemplateQueryParameters .size () == responseItems .size (),
517
+ "number of response items does not match number of requests" );
518
+
519
+ int size = mSearchTemplateQueryParameters .size ();
520
+ List <Class <?>> classes = mSearchTemplateQueryParameters
521
+ .stream ().map (MultiSearchTemplateQueryParameter ::clazz ).collect (Collectors .toList ());
522
+ List <IndexCoordinates > indices = mSearchTemplateQueryParameters
523
+ .stream ().map (MultiSearchTemplateQueryParameter ::index ).collect (Collectors .toList ());
524
+
525
+ return getSearchHitsFromMsearchResponse (size , classes , indices , responseItems );
507
526
}
508
527
509
- @ SuppressWarnings ({ "unchecked" , "rawtypes" })
510
528
private List <SearchHits <?>> doMultiSearch (List <MultiSearchQueryParameter > multiSearchQueryParameters ) {
511
529
512
530
MsearchRequest request = requestConverter .searchMsearchRequest (multiSearchQueryParameters ,
@@ -518,31 +536,46 @@ private List<SearchHits<?>> doMultiSearch(List<MultiSearchQueryParameter> multiS
518
536
Assert .isTrue (multiSearchQueryParameters .size () == responseItems .size (),
519
537
"number of response items does not match number of requests" );
520
538
521
- List <SearchHits <?>> searchHitsList = new ArrayList <>(multiSearchQueryParameters .size ());
539
+ int size = multiSearchQueryParameters .size ();
540
+ List <Class <?>> classes = multiSearchQueryParameters
541
+ .stream ().map (MultiSearchQueryParameter ::clazz ).collect (Collectors .toList ());
542
+ List <IndexCoordinates > indices = multiSearchQueryParameters
543
+ .stream ().map (MultiSearchQueryParameter ::index ).collect (Collectors .toList ());
522
544
523
- Iterator <MultiSearchQueryParameter > queryIterator = multiSearchQueryParameters .iterator ();
545
+ return getSearchHitsFromMsearchResponse (size , classes , indices , responseItems );
546
+ }
547
+
548
+ /**
549
+ * {@link MsearchResponse} and {@link MsearchTemplateResponse} share the same {@link MultiSearchResponseItem}
550
+ */
551
+ @ SuppressWarnings ({ "unchecked" , "rawtypes" })
552
+ private List <SearchHits <?>> getSearchHitsFromMsearchResponse (int size , List <Class <?>> classes ,
553
+ List <IndexCoordinates > indices , List <MultiSearchResponseItem <EntityAsMap >> responseItems ) {
554
+ List <SearchHits <?>> searchHitsList = new ArrayList <>(size );
555
+ Iterator <Class <?>> clazzIter = classes .iterator ();
556
+ Iterator <IndexCoordinates > indexIter = indices .iterator ();
524
557
Iterator <MultiSearchResponseItem <EntityAsMap >> responseIterator = responseItems .iterator ();
525
558
526
- while (queryIterator .hasNext ()) {
527
- MultiSearchQueryParameter queryParameter = queryIterator .next ();
559
+ while (clazzIter .hasNext () && indexIter .hasNext ()) {
528
560
MultiSearchResponseItem <EntityAsMap > responseItem = responseIterator .next ();
529
561
530
562
if (responseItem .isResult ()) {
531
563
532
- Class clazz = queryParameter .clazz ;
564
+ Class clazz = clazzIter .next ();
565
+ IndexCoordinates index = indexIter .next ();
533
566
ReadDocumentCallback <?> documentCallback = new ReadDocumentCallback <>(elasticsearchConverter , clazz ,
534
- queryParameter . index );
567
+ index );
535
568
SearchDocumentResponseCallback <SearchHits <?>> callback = new ReadSearchDocumentResponseCallback <>(clazz ,
536
- queryParameter . index );
569
+ index );
537
570
538
571
SearchHits <?> searchHits = callback .doWith (
539
572
SearchDocumentResponseBuilder .from (responseItem .result (), getEntityCreator (documentCallback ), jsonpMapper ));
540
573
541
574
searchHitsList .add (searchHits );
542
575
} else {
543
576
if (LOGGER .isWarnEnabled ()) {
544
- LOGGER
545
- . warn ( String . format ( "multisearch responsecontains failure: {}" , responseItem .failure ().error ().reason ()));
577
+ LOGGER . warn ( String . format ( "multisearch response contains failure: %s" ,
578
+ responseItem .failure ().error ().reason ()));
546
579
}
547
580
}
548
581
}
@@ -556,6 +589,12 @@ private List<SearchHits<?>> doMultiSearch(List<MultiSearchQueryParameter> multiS
556
589
record MultiSearchQueryParameter (Query query , Class <?> clazz , IndexCoordinates index ) {
557
590
}
558
591
592
+ /**
593
+ * value class combining the information needed for a single query in a template multisearch request.
594
+ */
595
+ record MultiSearchTemplateQueryParameter (SearchTemplateQuery query , Class <?> clazz , IndexCoordinates index ) {
596
+ }
597
+
559
598
@ Override
560
599
public String openPointInTime (IndexCoordinates index , Duration keepAlive , Boolean ignoreUnavailable ) {
561
600
0 commit comments