【问题标题】:Does Spring Data Elasticsearch support Multi Search API?Spring Data Elasticsearch 是否支持 Multi Search API?
【发布时间】:2018-10-15 23:45:47
【问题描述】:

我正在使用 Spring Data Elasticsearch,并且有兴趣利用 Elasticsearch 6.2 的 Multi Search API 在单个 API 请求中执行多个搜索。

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

目前使用 Spring Data Elasticsearch 的 NativeSearchQueryBuilder 构建搜索查询,并使用 ElasticsearchTemplate 执行搜索请求。在查看 Spring Data 代码和浏览文档后,我还没有找到任何这些方法公开的用于构造或提交 Multi Search 请求的方法。

Spring Data Elasticsearch 是否支持 Multi Search API,通过他们的 ElasticsearchTemplate 或其他一些我可能不知道的客户端/机制?

Elasticsearch 在他们的 Java API 中提供了这个功能,所以我追求的是类似于下面的东西,但不幸的是我必须使用 Spring Data Elasticsearch。

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

【问题讨论】:

    标签: java spring elasticsearch spring-data spring-data-elasticsearch


    【解决方案1】:

    可能为时已晚,但是当我遇到同样的问题时,我没有任何答案就提出了问题。我希望我的解决方案对其他搜索者有所帮助。 Spring data elasticsearch有很多限制,但是你可以使用ElasticSearch的java客户端做任何事情。

    这里是maven依赖:

    <!--ELASTICSEARCH-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.plugin</groupId>
            <artifactId>transport-netty4-client</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
    

    这是我的解决方案:

    @Service
    public class UniversalSearchHelper {
        @Autowired
        protected Client client;
    
        public List<SearchResult> matchQuery(String term) {
            MultiSearchRequest request = new MultiSearchRequest();
            request.add(searchRequest(QueryBuilders.boolQuery()
                    .should(QueryBuilders.matchQuery("name", term))
                    .should(QueryBuilders.matchQuery("full_name", term)), "movie_index"));
            request.add(searchRequest(QueryBuilders.matchQuery("name", term), "taxonomy_index"));
            ActionFuture<MultiSearchResponse> r = client.multiSearch(request);
            return getTopTen(r.actionGet(2000));
        }
    
        public List<SearchResult> fuzzyQuery(String term) {
            MultiSearchRequest request = new MultiSearchRequest();
            request.add(searchRequest(QueryBuilders.boolQuery()
                    .should(QueryBuilders.fuzzyQuery("name", term))
                    .should(QueryBuilders.fuzzyQuery("full_name", term)), "movie_index"));
            request.add(searchRequest((QueryBuilders.fuzzyQuery("name", term), "taxonomy_index"));
            ActionFuture<MultiSearchResponse> r = client.multiSearch(request);
            return getTopTen(r.actionGet(2000));
        }
    
        private SearchRequest searchRequest(QueryBuilder queryBuilder, String... indices) {
            SearchSourceBuilder search = new SearchSourceBuilder();
            search.query(queryBuilder);
            SearchRequest request = new SearchRequest();
            request.indices(indices);
            request.source(search);
            return request;
        }
    
        private List<SearchResult> getTopTen(MultiSearchResponse response) {
            List<SearchResult> results = new ArrayList<>();
            response.iterator().forEachRemaining(item -> {
                if (!item.isFailure()) {
                    item.getResponse().getHits().iterator().forEachRemaining(hit -> results.add(new SearchResult(hit)));
                }
            });
    
            results.sort((searchResult1, searchResult2) -> (int) (searchResult2.getScore() - searchResult1.getScore()));
            return results.stream().filter(sr -> sr.getTaxonomy() != null).limit(10).collect(Collectors.toList());
        }
    }
    

    和实体获取结果:

    import org.elasticsearch.search.SearchHit;
    
    public class SearchResult {
        private Object id;
        private float score;
        private String term;
        private String type;
        private String taxonomy;
    
        public Object getId() {
            return id;
        }
    
        public SearchResult setId(Object id) {
            this.id = id;
            return this;
        }
    
        public float getScore() {
            return score;
        }
    
        public SearchResult setScore(float score) {
            this.score = score;
            return this;
        }
    
        public String getTerm() {
            return term;
        }
    
        public SearchResult setTerm(String term) {
            this.term = term;
            return this;
        }
    
        public String getType() {
            return type;
        }
    
        public SearchResult setType(String type) {
            this.type = type;
            return this;
        }
    
        public String getTaxonomy() {
            return taxonomy;
        }
    
        public void setTaxonomy(String taxonomy) {
            this.taxonomy = taxonomy;
        }
    
        public SearchResult() {
        }
    
        public SearchResult(SearchHit hit) {
            this.id = hit.getSource().get("id");
            this.term = (String)hit.getSource().get("name");
            this.score = hit.getScore();
            this.type = hit.getType();
            this.taxonomy = (String) hit.getSource().get("taxonomy");
        }
    }
    

    【讨论】:

      【解决方案2】:

      不,Spring Data Elasticsearch 暂时不支持多搜索。我也遇到了同样的问题,我是working a PR添加这个功能。现在,我想出了以下解决方法:

      @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());
      }
      

      【讨论】:

        猜你喜欢
        • 2016-03-04
        • 2022-09-25
        • 2017-06-19
        • 2016-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-23
        • 2017-12-14
        相关资源
        最近更新 更多