【ES常用查询】基于ElasticsearchRestTemplate及NativeSearchQuery的查询

包含当前es所有的查询,

需要什么代码直接照搬,改个参数就行!

用的好请务必给我点赞!!!感谢爱你们!!!

为啥写这篇文章呢:

大概是因为目前公司用的api跟以前的不太一样,

以前我们是基于高标准客户端直接做的,

但是目前这边同事是基于ElasticsearchRestTemplate跟NativeSearchQuery做的。


import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.index.query.WildcardQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/v/k/t/query")
public class EsTestController {

  //聚合2
    //参加聚合的字段必须是keyword、日期、数值、布尔类型
    @PostMapping("/es/agg2")
    public void agg2() throws IOException {

        // 1.创建Request对象
        SearchRequest request = new SearchRequest("298_ops-web-js_1");
        // 2.准备请求的参数:DSL语句
        request.source().size(0);
        //参数一:聚合查询的名字  参数二:根据appid做分组   参数三:最多显示10条
      //  TermsAggregationBuilder aggregationBuilder = AggregationBuilders.max("bsVersionAgg").field("appId");
        MaxAggregationBuilder maxAggs = AggregationBuilders.max("score").field("bsVersion");
        request.source().aggregation(
                maxAggs
        );

        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            Aggregations aggregations = response.getAggregations();
            Terms bsVersionAgg = aggregations.get("bsVersionAgg");
            List<? extends Terms.Bucket> buckets = bsVersionAgg.getBuckets();
            for (Terms.Bucket bucket : buckets) {
                String key = bucket.getKeyAsString();
                //getDocCount:该桶下的文档总数
                long docCount = bucket.getDocCount();
                log.info("key:{},docCount:{}", key, docCount);
            }
        } catch (IOException e) {
            log.error("es查询异常:{}", e.getMessage());
        }

    }



    //聚合
    //参加聚合的字段必须是keyword、日期、数值、布尔类型
    @PostMapping("/es/agg")
    public void agg() {
        // 1.创建Request对象
        SearchRequest request = new SearchRequest("298_ops-web-js_1");
        // 2.准备请求的参数:DSL语句
        request.source().size(0);
        //参数一:聚合查询的名字  参数二:根据appid做分组   参数三:最多显示10条
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("bsVersionAgg").field("appId").size(5);

        request.source().aggregation(
                aggregationBuilder
        );

        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            Aggregations aggregations = response.getAggregations();
            Terms bsVersionAgg = aggregations.get("bsVersionAgg");
            List<? extends Terms.Bucket> buckets = bsVersionAgg.getBuckets();
            for (Terms.Bucket bucket : buckets) {
                String key = bucket.getKeyAsString();
                //getDocCount:该桶下的文档总数
                long docCount = bucket.getDocCount();
                log.info("key:{},docCount:{}", key, docCount);
            }
        } catch (IOException e) {
            log.error("es查询异常:{}", e.getMessage());
        }
    }


    /************************************************************************
     ————————————————————————————以下为不携带聚合的查询————————————————————————————————————————————
     ************************************************************************/



    /**
     * 测试es各种查询方法*
     */

    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;

    //通配符查询
    @PostMapping("/es/wildcard")
    public void wildcard() {
        //*:匹配任意数量的字符(包括零个字符)。 *x*: 对x做前后N位做模糊查询,前后有多少值都可以查到(也可以左模糊或者右模糊)
        //?:用于匹配单个字符.    user?a: user?a   匹配user1a,但不匹配user123a
        //^:必须以某个字符开头,如^user*:必须以user开头
        //$:必须以某个字符结尾,如user$:必须以user结尾

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //wildcardQuery:通配符查询
        WildcardQueryBuilder bsVersion = QueryBuilders.wildcardQuery("bsVersion", "*1*");
        WildcardQueryBuilder bsVersion2 = QueryBuilders.wildcardQuery("type", "*j*");
        boolQueryBuilder.must(bsVersion).should(bsVersion2);

        NativeSearchQuery dsl = new NativeSearchQueryBuilder()
    }

    //高亮
    //默认情况下:只能对查询字段高亮!!!
    //加了.requireFieldMatch(false) 可以对非查询字段高亮,具体看下文
    @PostMapping("/es/highlight")
    public void highlight() {

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //wildcardQuery:通配符查询
        WildcardQueryBuilder bsVersion = QueryBuilders.wildcardQuery("bsVersion", "*1*");
        WildcardQueryBuilder bsVersion2 = QueryBuilders.wildcardQuery("type", "*j*");
        boolQueryBuilder.must(bsVersion).should(bsVersion2);

        NativeSearchQuery dsl = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withHighlightFields(
                        //.requireFieldMatch(false) : 加了可以对非查询字段高亮
                        new HighlightBuilder.Field("bsVersion").preTags("<em>").postTags("</em>").requireFieldMatch(false),
                        new HighlightBuilder.Field("provinceNameCn").preTags("<em>").postTags("</em>").requireFieldMatch(false),
                        new HighlightBuilder.Field("isp").preTags("<em>").postTags("</em>").requireFieldMatch(false),
                        new HighlightBuilder.Field("type").preTags("<em>").postTags("</em>").requireFieldMatch(false),
                        new HighlightBuilder.Field("agentId").preTags("<em>").postTags("</em>").requireFieldMatch(false)
                )
                .build();

        SearchHits<Map> search = elasticsearchRestTemplate.search(dsl, Map.class, IndexCoordinates.of("298_ops-web-js_1"));
        log.info("总条数:{}", search.getTotalHits());
        for (SearchHit<Map> searchHit : search.getSearchHits()) {
            // 高亮字段是个大MAP  高亮字段集合 = {bsVersion=[<em>115</em>]}  //K=字段名 V=高亮了的数据集合
            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
            System.out.println("获取高亮字段集合:bsVersion =  " + highlightFields.get("bsVersion"));
            System.out.println("获取高亮字段集合:provinceNameCn =  " + highlightFields.get("provinceNameCn"));
            System.out.println("获取高亮字段集合:isp =  " + highlightFields.get("isp"));
            System.out.println("获取高亮字段集合:type =  " + highlightFields.get("type"));
            System.out.println("获取高亮字段集合:agentId =  " + highlightFields.get("agentId"));
            List<String> bsVersionResult = highlightFields.get("bsVersion");
            for (String s : bsVersionResult) {
                System.out.println("bsVersion集合每一个值为 = " + s);
            }

//            highlightFields.forEach((k, v) -> {
//                //获取高亮字段:k = bsVersion v = [<em>115</em>]
//                System.out.println("获取高亮字段:k = " + k + " v = " + v);
//            });
        }
        log.info("总条数:{}", search.getTotalHits());
        System.out.println("search.getSearchHits().size() = " + search.getSearchHits().size());
    }

    //排序
    @PostMapping("/es/sort")
    public void sort() {
        MatchAllQueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();

        //备注:这里用的是NativeSearchQueryBuilder:xxxBuilder。最后一定要.build();,不然条件用不了
        NativeSearchQuery dsl = new NativeSearchQueryBuilder()
                .withQuery(matchAllQuery)
                //备注:应该是要keyword,paasword这一类才能排序。我用text类型排序报:非法字段异常
                .withSorts(SortBuilders.fieldSort("appId").order(SortOrder.ASC)) //排序:根据bsVersion升序排序
                .build();

        SearchHits<Map> search = elasticsearchRestTemplate.search(dsl, Map.class, IndexCoordinates.of("298_ops-web-js_1"));
        log.info("总条数:{}", search.getTotalHits());
        for (SearchHit<Map> searchHit : search.getSearchHits()) {
            System.out.println("单条文档的原数据 = " + searchHit.getContent());
            System.out.println("单条文档的id = " + searchHit.getId());
            System.out.println("单条文档的评分 = " + searchHit.getScore());
            System.out.println("单条文档索引名(表名) = " + searchHit.getIndex());//298_ops-web-js_1就是你输入的索引库名
        }

    }

    //分页
    @PostMapping("/es/page")
    public void page() {
        Integer page = 1;
        Integer size = 10;
        MatchAllQueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();
        NativeSearchQuery dsl = new NativeSearchQuery(matchAllQuery);
        //分页
        Pageable pageable = PageRequest.of((page - 1) * size, size);
        dsl.setPageable(pageable);

        SearchHits<Map> search = elasticsearchRestTemplate.search(dsl, Map.class, IndexCoordinates.of("298_ops-web-js_1"));
        log.info("总条数:{}", search.getTotalHits());

        // 获取当前页数
        log.info("当前页数:{}", page);

        // 获取当前页的条数
        int currentSize = search.getSearchHits().size();
        log.info("当前页条数:{}", currentSize);

        //数据列表:search.getSearchHits()  for出每一条,然后加到list中

        for (SearchHit<Map> searchHit : search.getSearchHits()) {
            System.out.println("单条文档的原数据 = " + searchHit.getContent());
            System.out.println("单条文档的id = " + searchHit.getId());
            System.out.println("单条文档的评分 = " + searchHit.getScore());
            System.out.println("单条文档索引名(表名) = " + searchHit.getIndex());//298_ops-web-js_1就是你输入的索引库名
        }

    }


    //布尔查询
    @PostMapping("/es/boolQueryBuilder")
    public void boolQueryBuilder() {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //must 必须满足且参与算分
        boolQueryBuilder.must(QueryBuilders.matchQuery("bsVersion", "114"));
        //mustNot 必须不满足   appID 300-700之间不参与查询(就是直接筛掉了)
        boolQueryBuilder.mustNot(QueryBuilders.rangeQuery("appId").gte("300").lte("700"));
        //filter 必须满足,且不参与算分
//        boolQueryBuilder.filter(QueryBuilders.termQuery("agentId", "298_ead348abbaf30f48"));
        NativeSearchQuery dsl = new NativeSearchQuery(boolQueryBuilder);
        SearchHits<Map> search = elasticsearchRestTemplate.search(dsl, Map.class, IndexCoordinates.of("298_ops-web-js_1"));
        log.info("总条数:{}", search.getTotalHits());
        for (SearchHit<Map> searchHit : search.getSearchHits()) {
            System.out.println("单条文档的原数据 = " + searchHit.getContent());
            System.out.println("单条文档的id = " + searchHit.getId());
            System.out.println("单条文档的评分 = " + searchHit.getScore());
            System.out.println("单条文档索引名(表名) = " + searchHit.getIndex());//298_ops-web-js_1就是你输入的索引库名
        }
    }


    //算分函数查询
    @PostMapping("/es/FunctionScoreQueryBuilder")
    public void FunctionScoreQueryBuilder() {
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(
                //原始查询
                QueryBuilders.matchAllQuery(),
                //算分数组
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                        //第一个元素
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                //过滤器
                                QueryBuilders.matchQuery("bsVersion", "114"),
                                //权重
                                ScoreFunctionBuilders.weightFactorFunction(10)
                        ),
                        //第二个元素
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                //过滤器
                                QueryBuilders.matchQuery("bsVersion", "115"),
                                //权重
                                ScoreFunctionBuilders.weightFactorFunction(10)
                        )
                }).boostMode(CombineFunction.REPLACE);

        NativeSearchQuery dsl = new NativeSearchQuery(functionScoreQueryBuilder);
        SearchHits<Map> search = elasticsearchRestTemplate.search(dsl, Map.class, IndexCoordinates.of("298_ops-web-js_1"));
        log.info("总条数:{}", search.getTotalHits());
        for (SearchHit<Map> searchHit : search.getSearchHits()) {
            System.out.println("单条文档的原数据 = " + searchHit.getContent());
            System.out.println("单条文档的id = " + searchHit.getId());
            System.out.println("单条文档的评分 = " + searchHit.getScore());
            System.out.println("单条文档索引名(表名) = " + searchHit.getIndex());//298_ops-web-js_1就是你输入的索引库名
        }
    }

    //范围查询
    @PostMapping("/es/rangeQuery")
    public void rangeQuery() {
        //范围查询 appId字段  >=0   <=200   的数据
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("appId").gte("0").lte("200");
        NativeSearchQuery dsl = new NativeSearchQuery(rangeQueryBuilder);
        SearchHits<Map> search = elasticsearchRestTemplate.search(dsl, Map.class, IndexCoordinates.of("298_ops-web-js_1"));
        log.info("总条数:{}", search.getTotalHits());
        for (SearchHit<Map> searchHit : search.getSearchHits()) {
            System.out.println("单条文档的原数据 = " + searchHit.getContent());
            System.out.println("单条文档的id = " + searchHit.getId());
            System.out.println("单条文档的评分 = " + searchHit.getScore());
            System.out.println("单条文档索引名(表名) = " + searchHit.getIndex());//298_ops-web-js_1就是你输入的索引库名
        }
    }

    //精确查询
    @PostMapping("/es/termQuery")
    public void termQuery() {
        //根据isp字段 精确查询 内网IP
        TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("isp", " 内网IP ");
        NativeSearchQuery dsl = new NativeSearchQuery(termsQueryBuilder);
        SearchHits<Map> search = elasticsearchRestTemplate.search(dsl, Map.class, IndexCoordinates.of("298_ops-web-js_1"));
        log.info("总条数:{}", search.getTotalHits());
        for (SearchHit<Map> searchHit : search.getSearchHits()) {
            System.out.println("单条文档的原数据 = " + searchHit.getContent());
            System.out.println("单条文档的id = " + searchHit.getId());
            System.out.println("单条文档的评分 = " + searchHit.getScore());
            System.out.println("单条文档索引名(表名) = " + searchHit.getIndex());//298_ops-web-js_1就是你输入的索引库名
        }
    }


    //多字段查询
    @PostMapping("/es/multiMatchQuery")
    public void multiMatchQuery() {
        //备注:字段必须是text类型,可以分词类型!!!!
        //查找keyword、数值、日期、boolean等会报错!!!
        //如果放入精确类型的字段,会报错!!!!
        MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery("114", "bsVersion", "type");//查询114根据"bsVersion","type"
        NativeSearchQuery dsl = new NativeSearchQuery(multiMatchQuery);
        SearchHits<Map> search = elasticsearchRestTemplate.search(dsl, Map.class, IndexCoordinates.of("298_ops-web-js_1"));
        log.info("总条数:{}", search.getTotalHits());
        for (SearchHit<Map> searchHit : search.getSearchHits()) {
            System.out.println("单条文档的原数据 = " + searchHit.getContent());
            System.out.println("单条文档的id = " + searchHit.getId());
            System.out.println("单条文档的评分 = " + searchHit.getScore());
            System.out.println("单条文档索引名(表名) = " + searchHit.getIndex());//298_ops-web-js_1就是你输入的索引库名
        }
    }

    //单字段查询
    @PostMapping("/es/matchQuery")
    public void matchQuery() {
        MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("bsVersion", "114");
        NativeSearchQuery dsl = new NativeSearchQuery(matchQuery);
        SearchHits<Map> search = elasticsearchRestTemplate.search(dsl, Map.class, IndexCoordinates.of("298_ops-web-js_1"));
        log.info("总条数:{}", search.getTotalHits());
        for (SearchHit<Map> searchHit : search.getSearchHits()) {
            System.out.println("单条文档的原数据 = " + searchHit.getContent());
            System.out.println("单条文档的id = " + searchHit.getId());
            System.out.println("单条文档的评分 = " + searchHit.getScore());
            System.out.println("单条文档索引名(表名) = " + searchHit.getIndex());//298_ops-web-js_1就是你输入的索引库名
        }
    }

    //查询所有
    @PostMapping("/es/matchAllQuery")
    public void matchAllQuery() {
        MatchAllQueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();
        NativeSearchQuery dsl = new NativeSearchQuery(matchAllQuery);
        SearchHits<Map> search = elasticsearchRestTemplate.search(dsl, Map.class, IndexCoordinates.of("298_ops-web-js_1"));
        log.info("总条数:{}", search.getTotalHits());
        log.info("查询原始对象:{}", search.getSearchHits());
        log.info("分数值:{}", search.getMaxScore());
        log.info("有无聚合:{}", search.hasAggregations());
        log.info("返回搜索命中数量的关系,例如精确值、估计值:{}", search.getTotalHitsRelation());
        log.info("判断是否存在搜索命中结果:{}", search.hasSearchHits());
        //原始结果的每一条数据
        for (SearchHit<Map> searchHit : search.getSearchHits()) {
            System.out.println("单条文档 = " + searchHit);
            System.out.println("单条文档的原数据 = " + searchHit.getContent());
        }
    }


}

————————————————————————————————————

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以参考以下代码实现一个基于ElasticsearchRestTemplate查询工具类: ```java import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.SearchResultMapper; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.List; @Component public class ElasticsearchQueryUtils { private final ElasticsearchRestTemplate elasticsearchRestTemplate; @Autowired public ElasticsearchQueryUtils(ElasticsearchRestTemplate elasticsearchRestTemplate) { this.elasticsearchRestTemplate = elasticsearchRestTemplate; } public <T> List<T> query(QueryBuilder queryBuilder, Class<T> clazz) throws IOException { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(queryBuilder); NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); nativeSearchQueryBuilder.withSourceFilter(searchSourceBuilder.fetchSource()); nativeSearchQueryBuilder.withQuery(queryBuilder); SearchResultMapper searchResultMapper = elasticsearchRestTemplate.getResultsMapper(); SearchResponse searchResponse = elasticsearchRestTemplate.query(nativeSearchQueryBuilder.build(), response -> response, RequestOptions.DEFAULT); return searchResultMapper.mapResults(searchResponse, clazz); } } ``` 这个工具类提供了一个`query`方法,根据查询条件QueryBuilder执行查询,返回符合条件的对象列表。 其中,`query`方法使用了`SearchResultMapper`将查询结果映射为对象列表,因此需要在项目中定义一个`SearchResultMapper`的实现类。这个实现类需要实现`mapResults`方法,将ES查询结果映射为指定类型的对象列表,例如: ```java import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.search.SearchHit; import org.springframework.data.elasticsearch.core.SearchResultMapper; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Map; @Component public class MySearchResultMapper implements SearchResultMapper { @Override public <T> List<T> mapResults(SearchResponse response, Class<T> clazz, SearchHitMapper mapper) { List<T> list = new ArrayList<>(); for (SearchHit hit : response.getHits()) { Map<String, Object> source = hit.getSourceAsMap(); T obj = mapper.mapToObject(source, clazz); list.add(obj); } return list; } } ``` 这个`MySearchResultMapper`类将ES查询结果映射为指定类型的对象列表。这里使用了一个`SearchHitMapper`接口,用于将ES查询结果转换为对象,例如: ```java public interface SearchHitMapper { /** * 将ES查询结果转换为对象 * * @param source 查询结果 * @param clazz 对象类型 * @param <T> 对象泛型 * @return 对象 */ <T> T mapToObject(Map<String, Object> source, Class<T> clazz); } ``` 这个接口的实现类可以根据具体的业务需求来实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值