javaopensearchamazon-opensearch

Migrate Elasticsearch code to OpenSearch multi request search


I have this code:

import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.DocWriteResponse.Result;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BackoffPolicy;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.bulk.Retry;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetRequestBuilder;
import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.ClearScrollResponse;
import org.elasticsearch.action.search.MultiSearchRequestBuilder;
import org.elasticsearch.action.search.MultiSearchResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequestBuilder;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.engine.DocumentMissingException;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryAction;
import org.elasticsearch.index.reindex.DeleteByQueryRequestBuilder;
import org.elasticsearch.script.mustache.SearchTemplateRequestBuilder;
import org.elasticsearch.transport.client.PreBuiltTransportClient;

private TransportClient client;

public List<SearchResponse> multiSearch(List<SearchRequestBuilder> requestList) {
    try {
      MultiSearchRequestBuilder multiBuilder = client.prepareMultiSearch();

      for (SearchRequestBuilder request : requestList) {
        multiBuilder.add(request);
      }

      MultiSearchResponse searchResponse = multiBuilder.execute().actionGet();

      List<SearchResponse> responseList = new ArrayList<>();
      for (MultiSearchResponse.Item item : searchResponse.getResponses()) {
        responseList.add(item.getResponse());
      }
      return responseList;
    } catch (Exception exception) {
      throw new Exception();
    }
  }



import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.DocWriteResponse.Result;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BackoffPolicy;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.bulk.Retry;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetRequestBuilder;
import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.ClearScrollResponse;
import org.elasticsearch.action.search.MultiSearchRequestBuilder;
import org.elasticsearch.action.search.MultiSearchResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequestBuilder;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.engine.DocumentMissingException;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryAction;
import org.elasticsearch.index.reindex.DeleteByQueryRequestBuilder;
import org.elasticsearch.script.mustache.SearchTemplateRequestBuilder;
import org.elasticsearch.transport.client.PreBuiltTransportClient;

private TransportClient client


public class GroupSearchIndexRepository{

public SearchTemplateRequestBuilder getSearchTemplateRequestBuilder() {
    try {
      return new SearchTemplateRequestBuilder(client);
    } catch (Exception exception) {
      LOGGER.error("Search template request builder not available.", exception);
        new Exception("error");
    }
      return null;
  }

public SearchResponse searchScript(Map<String, Object> parameters, String scriptName) {
        SearchTemplateRequestBuilder searchTemplateRequestBuilder = getSearchTemplateRequestBuilder();
        SearchTemplateResponse response = searchTemplateRequestBuilder.setScript(scriptName)
                .setScriptType(ScriptType.STORED).setScriptParams(parameters)
                .setRequest(new SearchRequest(this.readIndex)).get();
        return response.getResponse();
    }
}

public class GroupSearchIndexRepository groupSearchIndexRepository
 

private JSONObject getGroupFromElastic(Map<String, Object> params, String searchTemplateName) {
    SearchResponse response = groupSearchIndexRepository.searchScript(params, searchTemplateName);

    if (response.getHits().getTotalHits() > 0) {
        try {
            SearchHit hit = response.getHits().getAt(0);
            String payload = hit.getSourceAsString();
            return new JSONObject(payload);
        } catch (Exception e) {
            logger.info("exception - elastic response {}", response);
            throw e;
        }

    } else {
        return null;
    }
  }

how to migrate this code to aws opensearch? I can't find a proper replacement.


Solution

  • According to official documentation TransportClient was removed after Elasticsearch 7.x and isn't supported by AWS OpenSearch. The replacement is the OpenSearch Java Client (org.opensearch.client:opensearch-java), which is the official client published by the OpenSearch You can migrate your existing logic like this:

    import org.opensearch.client.RestClient;
    import org.opensearch.client.opensearch.OpenSearchClient;
    import org.opensearch.client.transport.rest_client.RestClientTransport;
    import org.opensearch.client.json.jackson.JacksonJsonpMapper;
    import org.opensearch.client.opensearch.core.*;
    import org.opensearch.client.opensearch.core.msearch.*;
    import org.apache.http.HttpHost;
    import org.json.JSONObject;
    import java.io.IOException;
    import java.util.*;
    
    
    public class GroupSearchIndexRepository {
    
        private final OpenSearchClient client;
    
        public GroupSearchIndexRepository() {
            // here is a basic REST setup
            RestClient restClient = RestClient.builder(
                            new HttpHost("your-opensearch-domain", 443, "https"))
                    .build();
    
            //must create OpenSearch java client (new REST style, not Transport)
            this.client = new OpenSearchClient(
                    new RestClientTransport(restClient, new JacksonJsonpMapper()));
        }
    
        //the same idea as old multiSearch, just new API calls
        public List<SearchResponse<Map<String, Object>>> multiSearch(List<SearchRequest> requests) throws IOException {
            MsearchRequest.Builder builder = new MsearchRequest.Builder();
            for (SearchRequest req : requests) {
                // add each single search into the multi request
                builder.searches(s -> s.header(h -> h.index(req.index()))
                        .body(req.query()));
            }
    
            //multi search excution
            MsearchResponse<Map<String, Object>> response = client.msearch(builder.build(), Map.class);
    
            // collect all results back
            List<SearchResponse<Map<String, Object>>> results = new ArrayList<>();
            for (MultiSearchResponseItem<Map<String, Object>> item : response.responses()) {
                if (item.result() != null) results.add(item.result());
            }
            return results;
        }
    
        //stored script
        public SearchResponse<Map<String, Object>> searchScript(
                String index, String scriptId, Map<String, Object> params) throws IOException {
    
            //build and execute search template
            SearchTemplateRequest request = new SearchTemplateRequest.Builder()
                    .id(scriptId)
                    .params(params)
                    .build();
    
            return client.searchTemplate(request, Map.class);
        }
    
        // retrieve first hit as JSONObject
        public JSONObject getGroupFromElastic(String index, String scriptId, Map<String, Object> params) throws IOException {
            var response = searchScript(index, scriptId, params);
            if (response.hits().total() != null && response.hits().total().value() > 0) {
                var hit = response.hits().hits().get(0);
                return new JSONObject(hit.source());
            }
            return null;
        }
    }
    
    
    

    TransportClient is long gone after Elasticsearch7, and OpenSearch never shipped with it. The new OpenSearchClient is the official, a REST based replacement, it talk directly to the same HTTP endpoints and works fine with AWS OpenSearch Service. The migration can feel a bit noisy at first, but it's the right move if you want your code to stay compatible going forward...

    See the official OpenSearch Java Client docs : the GitHub repository , and the compatibility matrix for exact version details.