编辑代码

package org.linxidev.utils;

import jakarta.annotation.Resource;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 林夕
 * @Date: 2025/6/18
 * @Description: ES查询工具类 (text类型: key.keyword)
 */
@Component
public class ElasticSearchUtil {

    @Resource
    private RestHighLevelClient esClient;

    /**
     * 检查索引是否存在
     * @param indexName 索引名称
     * @return 是否存在
     * @throws IOException
     * @throws InterruptedException
     */
    public boolean isIndexExist(String indexName) throws IOException {
        GetIndexRequest existsRequest = new GetIndexRequest();
        existsRequest.indices(indexName);
        return esClient.indices().exists(existsRequest, RequestOptions.DEFAULT);
    }

    /**
     * 执行任意 SearchRequest 查询
     * @param searchRequest 查询请求
     * @return 搜索响应
     * @throws IOException
     */
    public SearchResponse search(SearchRequest searchRequest) throws IOException {
        return esClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    /**
     * 获取索引的文档总数
     * @param index 索引名
     * @return 文档总数
     * @throws IOException
     */
    public long countDocuments(String index) throws IOException {
        SearchRequest request = new SearchRequest(index);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.size(0);
        request.source(sourceBuilder);
        SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
        return response.getHits().getTotalHits();
    }

    /**
     * 内部查询构建类,支持链式调用
     */
    public static class QueryBuilder {
        private final SearchRequest searchRequest;
        private final SearchSourceBuilder source;
        private final BoolQueryBuilder bool;

        /**
         * 创建一个查询构建器
         * @param indices 索引名称
         */
        private QueryBuilder(String... indices) {
            this.searchRequest = new SearchRequest(indices);
            this.source = new SearchSourceBuilder();
            this.bool = QueryBuilders.boolQuery();
            this.source.query(bool);
            this.searchRequest.source(source);
        }

        /**
         * 创建一个查询构建器
         * @param indices 索引名称
         * @return 查询构建器
         */
        public static QueryBuilder build(String... indices) {
            return new QueryBuilder(indices);
        }

        /**
         * 大于等于
         * @param column
         * @param val
         * @return
         */
        public QueryBuilder ge(String column, Object val) {
            this.bool.must(QueryBuilders.rangeQuery(column).gte(val));
            return this;
        }

        /**
         * 小于等于
         * @param column
         * @param val
         * @return
         */
        public QueryBuilder le(String column, Object val) {
            this.bool.must(QueryBuilders.rangeQuery(column).lte(val));
            return this;
        }

        /**
         *  或
         * @param other
         * @return
         */
        public QueryBuilder or(QueryBuilder other) {
            this.bool.should(other.bool);
            return this;
        }

        /**
         * 筛选
         * @param other
         * @return
         */
        public QueryBuilder filter(QueryBuilder other) {
            this.bool.filter(other.bool);
            return this;
        }

        /**
         *  非
         * @param other
         * @return
         */
        public QueryBuilder not(QueryBuilder other) {
            this.bool.mustNot(other.bool);
            return this;
        }

        /**
         *  与
         * @param queryBuilder
         * @return
         */
        public QueryBuilder and(QueryBuilder queryBuilder) {
            this.bool.must(queryBuilder.bool);
            return this;
        }

        /**
         *  或
         * @param queryBuilder
         * @return
         */
        public QueryBuilder or(org.elasticsearch.index.query.QueryBuilder queryBuilder) {
            this.bool.should(queryBuilder);
            return this;
        }

        /**
         * 最小匹配数量 与 or 联合使用
         * @param num
         */
        public void minimum(int num) {
            this.bool.minimumShouldMatch(num);
        }

        /**
         * 筛选
         * @param queryBuilder
         * @return
         */
        public QueryBuilder filter(org.elasticsearch.index.query.QueryBuilder queryBuilder) {
            this.bool.filter(queryBuilder);
            return this;
        }

        /**
         *  非
         * @param queryBuilder
         * @return
         */
        public QueryBuilder not(org.elasticsearch.index.query.QueryBuilder queryBuilder) {
            this.bool.mustNot(queryBuilder);
            return this;
        }

        /**
         * 模糊
         * @param column
         * @param val
         * @return
         */
        public QueryBuilder like(String column, String val) {
            this.bool.must(QueryBuilders.wildcardQuery(column, "*".concat(val).concat("*")));
            return this;
        }

        /**
         * 左模糊
         * @param column
         * @param val
         * @return
         */
        public QueryBuilder leftLike(String column, String val) {
            this.bool.must(QueryBuilders.wildcardQuery(column, "*".concat(val)));
            return this;
        }

        /**
         * 右模糊
         * @param column
         * @param val
         * @return
         */
        public QueryBuilder rightLike(String column, String val) {
            this.bool.must(QueryBuilders.wildcardQuery(column, val.concat("*")));
            return this;
        }

        /**
         * 大于
         * @param column
         * @param val
         * @return
         */
        public QueryBuilder gt(String column, Object val) {
            this.bool.must(QueryBuilders.rangeQuery(column).gt(val));
            return this;
        }

        /**
         * 小于
         * @param column
         * @param val
         * @return
         */
        public QueryBuilder lt(String column, Object val) {
            this.bool.must(QueryBuilders.rangeQuery(column).lt(val));
            return this;
        }

        /**
         * 区间
         * @param column
         * @param from
         * @param to
         * @return
         */
        public QueryBuilder between(String column, Object from, Object to) {
            this.bool.must(QueryBuilders.rangeQuery(column).gt(from).lte(to));
            return this;
        }

        /**
         * 等于
         * @param column
         * @param val
         * @return
         */
        public QueryBuilder equals(String column, Object val) {
            this.bool.must(QueryBuilders.termQuery(column, val));
            return this;
        }

        /**
         *  包含
         * @param column
         * @param val
         * @return
         */
        public QueryBuilder in(String column, Object... val) {
            this.bool.must(QueryBuilders.termsQuery(column, val));
            return this;
        }

        /**
         *  包含
         * @param column
         * @param inList
         * @return
         */
        public QueryBuilder in(String column, Collection<?> inList) {
            this.bool.must(QueryBuilders.termsQuery(column, inList));
            return this;
        }

        /**
         * 匹配 字段
         * @param column
         * @param text
         * @return
         */
        public QueryBuilder match(String column, Object text) {
            this.bool.must(QueryBuilders.matchQuery(column, text));
            return this;
        }

        /**
         * 匹配多个字段
         * @param text
         * @param fields
         * @return
         */
        public QueryBuilder multiMatch(Object text, String... fields) {
            this.bool.must(QueryBuilders.multiMatchQuery(text, fields));
            return this;
        }

        /**
         * 批量查询IDS
         * @param ids
         * @return
         */
        public QueryBuilder ids(String... ids) {
            this.bool.must(QueryBuilders.idsQuery().addIds(ids));
            return this;
        }

        /**
         * 正则
         * @param field
         * @param pattern
         * @return
         */
        public QueryBuilder regexp(String field, String pattern) {
            this.bool.must(QueryBuilders.regexpQuery(field, pattern));
            return this;
        }

        /**
         * 分页
         * @param pageNum
         * @param pageSize
         * @return
         */
        public QueryBuilder page(int pageNum, int pageSize) {
            this.source.from((pageNum - 1) * pageSize);
            this.source.size(pageSize);
            return this;
        }

        /**
         * 分页(页码 0 开始)
         * @param from
         * @return
         */
        public QueryBuilder from(int from) {
            this.source.from(from);
            return this;
        }

        /**
         * 分页(页面大小)
         * @param size
         * @return
         */
        public QueryBuilder size(int size) {
            this.source.size(size);
            return this;
        }

        /**
         * 正序
         * @param field
         * @return
         */
        public QueryBuilder asc(String field) {
            this.source.sort(field, SortOrder.ASC);
            return this;
        }

        /**
         * 倒序
         * @param field
         * @return
         */
        public QueryBuilder desc(String field) {
            this.source.sort(field, SortOrder.DESC);
            return this;
        }

        /**
         * 获取查询语句
         * @return
         */
        public String toStr() {
            return this.bool.toString();
        }

        /**
         * 构建查询语句
         * @return
         */
        public SearchRequest build() {
            return searchRequest;
        }
    }


    /**
     * 执行查询
     * @param queryBuilder
     * @return
     * @throws IOException
     */
    public SearchResponse executeSearch(QueryBuilder queryBuilder) throws IOException {
        SearchRequest request = queryBuilder.build();
        return search(request);
    }

    /**
     * 使用示例(链式调用)
     */
    public void main(String[] args) {
        // IPage<Map<String, Object>> page = new Page<>(esLogsVo.getPageNum(), esLogsVo.getPageSize());
        try {
            SearchResponse response = this.executeSearch(
                    ElasticSearchUtil.QueryBuilder.build("esb_test")
                            // 1. ge
                            .ge("age", 20)
                            // 2. le
                            .le("age", 30)
                            // 3. or (QueryBuilder)
                            .or(QueryBuilder.build("user_index").equals("status", "active"))
                            // 4. filter (QueryBuilder)
                            .filter(QueryBuilder.build("user_index").gt("score", 80))
                            // 5. not (QueryBuilder)
                            .not(QueryBuilder.build("user_index").in("tags", "spam"))
                            // 6. and (QueryBuilder)
                            .and(QueryBuilder.build("user_index").like("name", "John"))
                            // 7. or (ES QueryBuilder)
                            .or(QueryBuilders.matchQuery("description", "test"))
                            // 8. filter (ES QueryBuilder)
                            .filter(QueryBuilders.termQuery("category", "books"))
                            // 9. not (ES QueryBuilder)
                            .not(QueryBuilders.rangeQuery("price").lt(100))
                            // 10. like
                            .like("email", "example.com")
                            // 11. leftLike
                            .leftLike("username", "admin")
                            // 12. rightLike
                            .rightLike("city", "ville")
                            // 13. gt
                            .gt("balance", 1000)
                            // 14. lt
                            .lt("discount", 0.1)
                            // 15. between
                            .between("date", "2023-01-01", "2023-12-31")
                            // 16. equals
                            .equals("gender", "male")
                            // 17. in (varargs)
                            .in("colors", "red", "blue")
                            // 18. in (Collection)
                            .in("sizes", Arrays.asList("M", "L"))
                            // 19. match
                            .match("content", "important document")
                            // 20. multiMatch
                            .multiMatch("search term", "title", "body")
                            // 21. ids
                            .ids("1", "2", "3")
                            // 22. regexp
                            .regexp("product_code", "A[0-9]{3}")
                            // 23. page
                            .page(1, 10)
                            // 24. from
                            .from(0)
                            // 25. size
                            .size(5)
                            // 26. asc
                            .asc("created_at")
                            // 27. desc
                            .desc("modified_at")
            );
            // 关键字查询(或条件)
            //if (!ObjectUtils.isEmpty(esLogsVo.getKeyword())){
            //    org.elasticsearch.index.query.QueryBuilder data = QueryBuilders.matchQuery("data", esLogsVo.getKeyword());
            //    org.elasticsearch.index.query.QueryBuilder response = QueryBuilders.matchQuery("response", esLogsVo.getKeyword());
            //    query.or(data).or(response).minimum(1);
            //}
            SearchHits hits = response.getHits();
            List<Map<String, Object>> collect = Arrays.stream(hits.getHits()).map(SearchHit::getSourceAsMap).toList();
            System.out.println(collect.size());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}