Search code examples
javaspringelasticsearchspring-dataspring-data-elasticsearch

Does Spring Data Elasticsearch support Multi Search API?


I'm using Spring Data Elasticsearch, and am interested in utilizing Elasticsearch 6.2's Multi Search API in order to execute more than one search in a single API request.

https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-multi-search.html

Currently using Spring Data Elasticsearch's NativeSearchQueryBuilder to build search queries, and ElasticsearchTemplate to execute search requests. I haven't managed to find any methods exposed by either of these for constructing or submitting Multi Search requests after looking through the Spring Data code and browsing documentation.

Does Spring Data Elasticsearch support Multi Search API, via their ElasticsearchTemplate or some other client/mechanism I may be unaware of?

Elasticsearch offers this functionality in their Java API, so what I am after is something analogous to the following, but unfortunately I am bound to using Spring Data Elasticsearch.

https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.2/java-search-msearch.html


Solution

  • No, Spring Data Elasticsearch doesn't support multi search for the time being. I also met the same problem, and I am working a PR to add this feature. Now, I come up with the following workarounds:

    @Override
    public YYY findBy(XXX xxx) {
      Client client = template.getClient();
      MultiSearchRequest request = new MultiSearchRequest();
      // build searchQuery like normal
      for (NativeSearchQuery searchQuery : queries) {
        request.add(prepareSearch(client, searchQuery));
      }
      ActionFuture<MultiSearchResponse> future = client
          .multiSearch(request);
      MultiSearchResponse response = future.actionGet();
      Item[] items = response.getResponses();
      for (int i = 0; i < items.length; i++) {
        AggregatedPage<XXX> ts = resultMapper.mapResults(items[i].getResponse(), XXX.class, page);
        // do with page
      }
    }
    
    private SearchRequestBuilder prepareSearch(Client client, SearchQuery searchQuery) {
      Assert.notNull(searchQuery.getIndices(), "No index defined for Query");
      Assert.notNull(searchQuery.getTypes(), "No type defined for Query");
    
      int startRecord = 0;
      SearchRequestBuilder searchRequest = client.prepareSearch(toArray(searchQuery.getIndices()))
          .setSearchType(searchQuery.getSearchType()).setTypes(toArray(searchQuery.getTypes()));
    
      if (searchQuery.getSourceFilter() != null) {
        SourceFilter sourceFilter = searchQuery.getSourceFilter();
        searchRequest.setFetchSource(sourceFilter.getIncludes(), sourceFilter.getExcludes());
      }
    
      if (searchQuery.getPageable().isPaged()) {
        startRecord = searchQuery.getPageable().getPageNumber() * searchQuery.getPageable().getPageSize();
        searchRequest.setSize(searchQuery.getPageable().getPageSize());
      }
      searchRequest.setFrom(startRecord);
    
      if (!searchQuery.getFields().isEmpty()) {
        searchRequest.setFetchSource(toArray(searchQuery.getFields()), null);
      }
    
      if (searchQuery.getSort() != null) {
        for (Sort.Order order : searchQuery.getSort()) {
          searchRequest.addSort(order.getProperty(),
              order.getDirection() == Sort.Direction.DESC ? SortOrder.DESC : SortOrder.ASC);
        }
      }
    
      if (searchQuery.getMinScore() > 0) {
        searchRequest.setMinScore(searchQuery.getMinScore());
      }
    
      if (searchQuery.getFilter() != null) {
        searchRequest.setPostFilter(searchQuery.getFilter());
      }
    
      if (!isEmpty(searchQuery.getElasticsearchSorts())) {
        for (SortBuilder sort : searchQuery.getElasticsearchSorts()) {
          searchRequest.addSort(sort);
        }
      }
    
      if (!searchQuery.getScriptFields().isEmpty()) {
        //_source should be return all the time
        //searchRequest.addStoredField("_source");
        for (ScriptField scriptedField : searchQuery.getScriptFields()) {
          searchRequest.addScriptField(scriptedField.fieldName(), scriptedField.script());
        }
      }
    
      if (searchQuery.getHighlightFields() != null) {
        for (HighlightBuilder.Field highlightField : searchQuery.getHighlightFields()) {
          searchRequest.highlighter(new HighlightBuilder().field(highlightField));
        }
      }
    
      if (!isEmpty(searchQuery.getIndicesBoost())) {
        for (IndexBoost indexBoost : searchQuery.getIndicesBoost()) {
          searchRequest.addIndexBoost(indexBoost.getIndexName(), indexBoost.getBoost());
        }
      }
    
      if (!isEmpty(searchQuery.getAggregations())) {
        for (AbstractAggregationBuilder aggregationBuilder : searchQuery.getAggregations()) {
          searchRequest.addAggregation(aggregationBuilder);
        }
      }
    
      if (!isEmpty(searchQuery.getFacets())) {
        for (FacetRequest aggregatedFacet : searchQuery.getFacets()) {
          searchRequest.addAggregation(aggregatedFacet.getFacet());
        }
      }
    
      return searchRequest.setQuery(searchQuery.getQuery());
    }