diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java index 951b54687..04a07f20c 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java @@ -69,6 +69,7 @@ import org.springframework.util.Assert; * Elasticsearch client. * * @author Peter-Josef Meisch + * @author Hamid Rahimi * @since 4.4 */ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate { @@ -465,6 +466,29 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate { return doMultiSearch(multiSearchQueryParameters); } + @Override + public List> multiSearch(List queries, List> classes, + List indexes) { + + Assert.notNull(queries, "queries must not be null"); + Assert.notNull(classes, "classes must not be null"); + Assert.notNull(indexes, "indexes must not be null"); + Assert.isTrue(queries.size() == classes.size() && queries.size() == indexes.size(), + "queries, classes and indexes must have the same size"); + + List multiSearchQueryParameters = new ArrayList<>(queries.size()); + Iterator> it = classes.iterator(); + Iterator indexesIt = indexes.iterator(); + + for (Query query : queries) { + Class clazz = it.next(); + IndexCoordinates index = indexesIt.next(); + multiSearchQueryParameters.add(new MultiSearchQueryParameter(query, clazz, index)); + } + + return doMultiSearch(multiSearchQueryParameters); + } + @SuppressWarnings({ "unchecked", "rawtypes" }) private List> doMultiSearch(List multiSearchQueryParameters) { diff --git a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ElasticsearchRestTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ElasticsearchRestTemplate.java index 4eff9b7bd..dea1a3403 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ElasticsearchRestTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ElasticsearchRestTemplate.java @@ -112,6 +112,7 @@ import org.springframework.util.Assert; * @author Massimiliano Poggi * @author Farid Faoudi * @author Sijia Liu + * @author Hamid Rahimi * @since 4.4 * @deprecated since 5.0 */ @@ -558,6 +559,42 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate { return res; } + @Override + public List> multiSearch(List queries, List> classes, + List indexes) { + + Assert.notNull(queries, "queries must not be null"); + Assert.notNull(classes, "classes must not be null"); + Assert.notNull(indexes, "indexes must not be null"); + Assert.isTrue(queries.size() == classes.size() && queries.size() == indexes.size(), + "queries, classes and indexes must have the same size"); + + MultiSearchRequest request = new MultiSearchRequest(); + Iterator> it = classes.iterator(); + Iterator indexesIt = indexes.iterator(); + for (Query query : queries) { + request.add(requestFactory.searchRequest(query, it.next(), indexesIt.next())); + } + + MultiSearchResponse.Item[] items = getMultiSearchResult(request); + + List> res = new ArrayList<>(queries.size()); + Iterator> it1 = classes.iterator(); + Iterator indexesIt1 = indexes.iterator(); + for (int i = 0; i < queries.size(); i++) { + Class entityClass = it1.next(); + IndexCoordinates index = indexesIt1.next(); + + ReadDocumentCallback documentCallback = new ReadDocumentCallback<>(elasticsearchConverter, entityClass, index); + SearchDocumentResponseCallback> callback = new ReadSearchDocumentResponseCallback<>(entityClass, + index); + + SearchResponse response = items[i].getResponse(); + res.add(callback.doWith(SearchDocumentResponseBuilder.from(response, getEntityCreator(documentCallback)))); + } + return res; + } + protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request) { MultiSearchResponse response = execute(client -> client.msearch(request, RequestOptions.DEFAULT)); MultiSearchResponse.Item[] items = response.getResponses(); diff --git a/src/main/java/org/springframework/data/elasticsearch/core/SearchOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/SearchOperations.java index 3cc7021f5..3a3947cc3 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/SearchOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/SearchOperations.java @@ -30,6 +30,7 @@ import org.springframework.lang.Nullable; * * @author Peter-Josef Meisch * @author Sascha Woo + * @author Hamid Rahimi * @since 4.0 */ public interface SearchOperations { @@ -127,11 +128,21 @@ public interface SearchOperations { * * @param queries the queries to execute * @param classes the entity classes used for property mapping - * @param index the index to run the query against + * @param index the index to run the queries against * @return list of SearchHits */ List> multiSearch(List queries, List> classes, IndexCoordinates index); + /** + * Execute the multi search query against elasticsearch and return result as {@link List} of {@link SearchHits}. + * + * @param queries the queries to execute + * @param classes the entity classes used for property mapping + * @param indexes the indexes to run the queries against + * @return list of SearchHits + */ + List> multiSearch(List queries, List> classes, List indexes); + /** * Execute the criteria query against elasticsearch and return result as {@link SearchHits} * diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java index 57788d458..0d37336fc 100755 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java @@ -108,6 +108,7 @@ import org.springframework.lang.Nullable; * @author Sijia Liu * @author Haibo Liu * @author scoobyzhang + * @author Hamid Rahimi */ @SpringIntegrationTest public abstract class ElasticsearchIntegrationTests { @@ -1764,6 +1765,40 @@ public abstract class ElasticsearchIntegrationTests { assertThat(searchHit1.getContent().getClass()).isEqualTo(Book.class); } + @Test // #2434 + public void shouldReturnDifferentEntityForMultiSearchWithMultipleIndexCoordinates() { + + IndexOperations bookIndexOperations = operations.indexOps(Book.class); + bookIndexOperations.delete(); + bookIndexOperations.createWithMapping(); + bookIndexOperations.refresh(); + IndexCoordinates bookIndex = IndexCoordinates.of("i-need-my-own-index"); + operations.index(buildIndex(SampleEntity.builder().id("1").message("ab").build()), + IndexCoordinates.of(indexNameProvider.indexName())); + operations.index(buildIndex(Book.builder().id("2").description("bc").build()), bookIndex); + bookIndexOperations.refresh(); + + List queries = new ArrayList<>(); + queries.add(getTermQuery("message", "ab")); + queries.add(getTermQuery("description", "bc")); + + List> searchHitsList = operations.multiSearch(queries, + Lists.newArrayList(SampleEntity.class, Book.class), + List.of(IndexCoordinates.of(indexNameProvider.indexName()), + IndexCoordinates.of(bookIndex.getIndexName()))); + + bookIndexOperations.delete(); + + SearchHits searchHits0 = searchHitsList.get(0); + assertThat(searchHits0.getTotalHits()).isEqualTo(1L); + SearchHit searchHit0 = (SearchHit) searchHits0.getSearchHit(0); + assertThat(searchHit0.getContent().getClass()).isEqualTo(SampleEntity.class); + SearchHits searchHits1 = searchHitsList.get(1); + assertThat(searchHits1.getTotalHits()).isEqualTo(1L); + SearchHit searchHit1 = (SearchHit) searchHits1.getSearchHit(0); + assertThat(searchHit1.getContent().getClass()).isEqualTo(Book.class); + } + @Test public void shouldIndexDocumentForSpecifiedSource() {