• SpringBoot 2.x集成Elasticsearch


    环境配置:SpringBoot:2.6.0 ,Elasticsearch:7.16.2

    1、pom配置

    <properties>
         <elasticsearch.version>7.16.2</elasticsearch.version>
    </properties>
    
    
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>${elasticsearch.version}</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>transport</artifactId>
        <version>${elasticsearch.version}</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-client</artifactId>
        <version>${elasticsearch.version}</version>
    </dependency>
    <!-- ES 版本 -->
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>${elasticsearch.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-elasticsearch</artifactId>
        <version>4.1.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.elasticsearch.plugin/transport-netty4-client -->
    <dependency>
        <groupId>org.elasticsearch.plugin</groupId>
        <artifactId>transport-netty4-client</artifactId>
        <version>${elasticsearch.version}</version>
    </dependency>

    2、配置config,获取springBean工具类见下文SpringContextUtils

    import com.test.util.SpringContextUtils;
    import com.alibaba.fastjson.JSON;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.http.HttpHost;
    import org.elasticsearch.action.ActionListener;
    import org.elasticsearch.action.bulk.*;
    import org.elasticsearch.client.RequestOptions;
    import org.elasticsearch.client.RestClient;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.elasticsearch.common.unit.ByteSizeUnit;
    import org.elasticsearch.common.unit.ByteSizeValue;
    import org.elasticsearch.core.TimeValue;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.Iterator;
    import java.util.function.BiConsumer;
    
    /**
     * @Author bug
     * @create 2022/05/6 19:43
     * @Description
     */
    @Configuration
    @Slf4j
    public class ESConfig {
        @Value("${elasticsearch.hostlist}")
        private String hostlist;
    
        /**
         * Description: 高版本客户端
         *
         * @Author: bug
         * @Date: 2022/05/15 10:20
         * @Return: org.elasticsearch.client.RestHighLevelClient
         * @throws:
         */
        @Bean("restHighLevelClient")
        public RestHighLevelClient restHighLevelClient() {
            RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
            // 解析 hostlist 配置信息。假如以后有多个,则需要用 , 分开
            String[] split = hostlist.split(",");
            // 创建 HttpHost 数组,其中存放es主机和端口的配置信息
            HttpHost[] httpHostArray = new HttpHost[split.length];
            for (int i = 0; i < split.length; i++) {
                String item = split[i];
                httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
            }
            // 创建RestHighLevelClient客户端
            return new RestHighLevelClient(RestClient.builder(httpHostArray));
        }
    
        /**
         * Description: 项目主要使用 RestHighLevelClient,对于低级的客户端暂时不用
         *
         * @Author: bug
         * @Date: 2022/05/15 10:20
         * @Return: org.elasticsearch.client.RestClient
         * @throws:
         */
        @Bean
        public RestClient restClient() {
            // 解析hostlist配置信息
            String[] split = hostlist.split(",");
            // 创建HttpHost数组,其中存放es主机和端口的配置信息
            HttpHost[] httpHostArray = new HttpHost[split.length];
            for (int i = 0; i < split.length; i++) {
                String item = split[i];
                httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
            }
            return RestClient.builder(httpHostArray).build();
        }
    
        public static RestHighLevelClient getRestHighLevelClient() {
            RestHighLevelClient restHighLevelClient = null;
            try {
                restHighLevelClient = (RestHighLevelClient) SpringContextUtils.getBeanListOfType(RestHighLevelClient.class).get(0);
            } catch (Exception e) {
                log.error("获取restHighLevelClient失败:" + e.toString());
            }
            return restHighLevelClient;
        }
    
        /**
         * Description: 封装 bulkProcessor
         *
         * @Author: bug
         * @Date: 2022/05/15 10:19
         * @Return: org.elasticsearch.action.bulk.BulkProcessor
         * @throws:
         */
        @Bean(name = "bulkProcessor")
        public BulkProcessor bulkProcessor() {
            BiConsumer<BulkRequest, ActionListener<BulkResponse>> bulkConsumer =
                    (request, bulkListener) -> getRestHighLevelClient().bulkAsync(request, RequestOptions.DEFAULT, bulkListener);
            return BulkProcessor.builder(bulkConsumer, new BulkProcessor.Listener() {
                @Override
                public void beforeBulk(long executionId, BulkRequest request) {
                    // todo do something
                    int i = request.numberOfActions();
                    log.info("ES 同步数量 Executing bulk [{}] with {} requests",
                            executionId, i);
                }
    
                @Override
                public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
                    if (response.hasFailures()) {
                        log.error("Bulk [{}] executed with failures", executionId);
                    } else {
                        log.info("Bulk [{}] completed in {} milliseconds",
                                executionId, response.getTook().getMillis());
                    }
                    // todo do something
                    Iterator<BulkItemResponse> iterator = response.iterator();
                    while (iterator.hasNext()) {
                        log.info("afterBulk--->>>" + JSON.toJSONString(iterator.next()));
                    }
                }
    
                @Override
                public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
                    // todo do something
                    log.error("ES 同步失败  Failed to execute bulk", failure);
                }
                //达到刷新的条数,达到刷新的大小,固定刷新的时间频率,并发线程数,重试补偿策略
            }).setBulkActions(1000)
                    .setBulkSize(new ByteSizeValue(1, ByteSizeUnit.MB))
                    .setFlushInterval(TimeValue.timeValueMinutes(5))
                    .setConcurrentRequests(2)
                    .setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3))
                    .build();
    
        }
    }

    3、工具类SpringContextUtils.java

    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Author bug
     * @create 2022/05/6 16:12
     * @Description 获取srpingBean
     */
    @Component
    public class SpringContextUtils implements ApplicationContextAware {
        private static ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            SpringContextUtils.applicationContext = applicationContext;
        }
    
        public static <T> List<T> getBeanListOfType(Class<T> clazz) {
            List<T> result = new ArrayList<>();
            Map<String, T> map = applicationContext.getBeansOfType(clazz);
            if (null != map) {
                result.addAll(map.values());
            }
            return result;
        }
    
        public static <T> List<T> getBeanListOfName(String className) throws Exception {
            Class clazz = Class.forName(className);
            return getBeanListOfType(clazz);
        }
    
        public static void autowireBean(Object bean) {
            applicationContext.getAutowireCapableBeanFactory().autowireBean(bean);
        }
    
        public static <T> T getBean(String name,Class<T> clazz){
            return applicationContext.getBean(name, clazz);
        }
    }

    4、工具类ElasticsearchUtil.java

    import com.test.model.domain.EsPage;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
    import org.elasticsearch.action.bulk.BulkProcessor;
    import org.elasticsearch.action.bulk.BulkRequest;
    import org.elasticsearch.action.bulk.BulkResponse;
    import org.elasticsearch.action.delete.DeleteRequest;
    import org.elasticsearch.action.get.GetRequest;
    import org.elasticsearch.action.get.GetResponse;
    import org.elasticsearch.action.index.IndexRequest;
    import org.elasticsearch.action.index.IndexResponse;
    import org.elasticsearch.action.search.SearchRequest;
    import org.elasticsearch.action.search.SearchResponse;
    import org.elasticsearch.action.support.master.AcknowledgedResponse;
    import org.elasticsearch.action.update.UpdateRequest;
    import org.elasticsearch.client.RequestOptions;
    import org.elasticsearch.client.RestClient;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.elasticsearch.client.indices.CreateIndexRequest;
    import org.elasticsearch.client.indices.GetIndexRequest;
    import org.elasticsearch.common.Strings;
    import org.elasticsearch.common.text.Text;
    import org.elasticsearch.common.unit.DistanceUnit;
    import org.elasticsearch.index.query.*;
    import org.elasticsearch.search.SearchHit;
    import org.elasticsearch.search.builder.SearchSourceBuilder;
    import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
    import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
    import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
    import org.elasticsearch.search.sort.SortOrder;
    import org.elasticsearch.xcontent.XContentType;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Map;
    import java.util.List;
    import java.util.UUID;
    
    /**
     * @Author bug
     * @create 2022/05/7 13:45
     * @Description ES工具类 该工具类适用于7.*已上版本
     * 最好不要自定义id 会影响插入速度
     */
    @Component
    @Slf4j
    public class ElasticsearchUtil {
        @Autowired
        @Qualifier("restHighLevelClient")
        private RestHighLevelClient restHighLevelClient;
    
        @Autowired
        @Qualifier("bulkProcessor")
        private BulkProcessor bulkProcessor;
    
        /**
         * 关键字 .keyword
         */
        public static final String KEYWORD = ".keyword";
    
        /**
         * 关键字 *
         */
        public static final String WILD_CODE_A = "*";
    
        /**
         * 关键字 ?
         */
        public static final String WILD_CODE_B = "?";
    
        /**
         * 创建索引
         *
         * @param index
         * @return
         */
        public boolean createIndex(String index) throws IOException {
            if (isIndexExist(index)) {
                log.error("Index is  exits!");
                return false;
            }
            //1.创建索引请求
            CreateIndexRequest request = new CreateIndexRequest(index);
            //2.执行客户端请求
            org.elasticsearch.client.indices.CreateIndexResponse response = restHighLevelClient.indices()
                    .create(request, RequestOptions.DEFAULT);
            return response.isAcknowledged();
        }
    
        /**
         * 判断索引是否存在
         *
         * @param index
         * @return
         */
        public boolean isIndexExist(String index) throws IOException {
            GetIndexRequest request = new GetIndexRequest(index);
            boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
            return exists;
        }
    
        /**
         * 删除索引
         *
         * @param index
         * @return
         */
        public boolean deleteIndex(String index) throws IOException {
            if (!isIndexExist(index)) {
                log.error("Index is not exits!");
                return false;
            }
            DeleteIndexRequest request = new DeleteIndexRequest(index);
            AcknowledgedResponse delete = restHighLevelClient.indices()
                    .delete(request, RequestOptions.DEFAULT);
            return delete.isAcknowledged();
        }
    
        /**
         * 数据添加,自定义id
         *
         * @param object 要增加的数据
         * @param index  索引,类似数据库
         * @param type   类似数据表
         * @param id     数据ID,为null时es随机生成
         * @return
         */
        public String addData(Object object, String index, String type, String id) throws Exception {
            //创建请求
            IndexRequest request = new IndexRequest(index, type);
            //规则 put /test_index/_doc/1
            request.id(id);
            //将数据放入请求 json
            IndexRequest source = request.source(JacksonMapperUtils.obj2json(object), XContentType.JSON);
            //客户端发送请求
            IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
            return response.getId();
        }
    
        /**
         * 数据添加 随机id 可能存在性能问题
         *
         * @param object 要增加的数据
         * @param index  索引,类似数据库
         * @param type   类似数据表
         * @return
         */
        public String addData(Object object, String index, String type) throws Exception {
            return addData(object, index, type, UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
        }
    
        /**
         * 通过ID删除数据
         *
         * @param index 索引,类似数据库
         * @param type  类似数据表
         * @param id    数据ID
         * @return
         */
        public void deleteDataById(String index, String type, String id) throws IOException {
            DeleteRequest request = new DeleteRequest(index, type, id);
            restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        }
    
        /**
         * 通过ID 更新数据
         *
         * @param object 要更新数据
         * @param index  索引,类似数据库
         * @param type   类似数据表
         * @param id     数据ID
         * @return
         */
        public void updateDataById(Object object, String index, String type, String id) throws Exception {
            log.info("es更新--->>>esId:" + id);
            UpdateRequest update = new UpdateRequest(index, type, id);
            update.doc(JacksonMapperUtils.obj2json(object), XContentType.JSON);
            restHighLevelClient.update(update, RequestOptions.DEFAULT);
            log.info("es更新返回--->>>esId:" + id);
        }
    
        /**
         * 通过ID 更新数据
         *
         * @param object 要更新数据
         * @param index  索引,类似数据库
         * @param type   类似数据表
         * @param id     数据ID
         * @return
         */
        public void updateDocById(Map<String, Object> object, String index, String type, String id) throws Exception {
            log.info("es更新--->>>esId:" + id);
            UpdateRequest update = new UpdateRequest(index, type, id).doc(object);
            update.doc(JacksonMapperUtils.obj2json(object), XContentType.JSON);
            restHighLevelClient.update(update, RequestOptions.DEFAULT);
            log.info("es更新返回--->>>esId:" + id);
        }
    
        /**
         * Description: 批量更新
         *
         * @param: list
         * @param: index
         * @param: type
         * @param: keyId
         * @Author: 123107
         * @Date: 2022/05/15 10:34
         * @Return: void
         * @throws:
         */
        public void bulkUpdate(List<?> list, String index, String type, String keyId) throws Exception {
            log.info("es bulk 更新--->>>start");
            for(Object object : list){
                String json = JacksonMapperUtils.obj2json(object);
                Map<String, Object> map = JacksonMapperUtils.json2map(JacksonMapperUtils.obj2json(object));
                String id = String.valueOf(map.get(keyId));
                UpdateRequest update = new UpdateRequest(index, id).doc(json, XContentType.JSON);
                update.doc(json, XContentType.JSON);
                bulkProcessor.add(update);
            }
            log.info("es bulk 更新--->>end");
        }
    
        /**
         * 通过ID获取数据
         *
         * @param index  索引,类似数据库
         * @param type   类似数据表
         * @param id     数据ID
         * @param fields 需要显示的字段,逗号分隔(缺省为全部字段)
         * @return
         */
        public Map<String, Object> searchDataById(String index, String type, String id, String fields) throws IOException {
            GetRequest request = new GetRequest(index, type, id);
            if (StringUtils.isNotEmpty(fields)) {
                //只查询特定字段。如果需要查询所有字段则不设置该项。
                request.fetchSourceContext(new FetchSourceContext(true, fields.split(","), Strings.EMPTY_ARRAY));
            }
            GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
            return response.getSource();
        }
    
        /**
         * 通过ID判断文档是否存在
         *
         * @param index 索引,类似数据库
         * @param type  类似数据表
         * @param id    数据ID
         * @return
         */
        public boolean existsById(String index, String type, String id) throws IOException {
            GetRequest request = new GetRequest(index, type, id);
            //不获取返回的_source的上下文
            request.fetchSourceContext(new FetchSourceContext(false));
            request.storedFields("_none_");
            return restHighLevelClient.exists(request, RequestOptions.DEFAULT);
        }
    
        /**
         * 批量插入false成功
         *
         * @param index   索引,类似数据库
         * @param type    类似数据表
         * @param objects 数据
         * @return
         */
        public boolean bulkPost(String index, String type, List<?> objects) throws Exception{
            BulkRequest bulkRequest = new BulkRequest();
            BulkResponse response = null;
            //最大数量不得超过20万
            for (Object object : objects) {
                IndexRequest request = new IndexRequest(index, type);
                request.source(JacksonMapperUtils.obj2json(object), XContentType.JSON);
                bulkRequest.add(request);
            }
            try {
                response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return response.hasFailures();
        }
    
        /**
         * 根据经纬度查询范围查找location 经纬度字段,distance 距离中心范围KM,lat  lon 圆心经纬度
         *
         * @param index
         * @param longitude
         * @param latitude
         * @param distance
         * @return
         */
        public SearchResponse geoDistanceQuery(String index, Float longitude, Float latitude, String distance) throws IOException {
    
            if (longitude == null || latitude == null) {
                return null;
            }
            //拼接条件
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            //QueryBuilder isdeleteBuilder = QueryBuilders.termQuery("isdelete", false);
            // 以某点为中心,搜索指定范围
            GeoDistanceQueryBuilder distanceQueryBuilder = new GeoDistanceQueryBuilder("location");
            distanceQueryBuilder.point(latitude, longitude);
            //查询单位:km
            distanceQueryBuilder.distance(distance, DistanceUnit.KILOMETERS);
            boolQueryBuilder.filter(distanceQueryBuilder);
            //boolQueryBuilder.must(isdeleteBuilder);
    
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(boolQueryBuilder);
    
            SearchRequest searchRequest = new SearchRequest(index);
            searchRequest.source(searchSourceBuilder);
    
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            return searchResponse;
        }
    
        /**
         * 获取低水平客户端
         *
         * @return
         */
        public RestClient getLowLevelClient() {
            return restHighLevelClient.getLowLevelClient();
        }
    
        /**
         * 高亮结果集 特殊处理
         * map转对象 JSONObject.parseObject(JSONObject.toJSONString(map), Content.class)
         *
         * @param searchResponse
         * @param highlightField
         */
        private List<Map<String, Object>> setSearchResponse(SearchResponse searchResponse, String highlightField) {
            //解析结果
            ArrayList<Map<String, Object>> list = new ArrayList<>();
            for (SearchHit hit : searchResponse.getHits().getHits()) {
                Map<String, HighlightField> high = hit.getHighlightFields();
                HighlightField title = high.get(highlightField);
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();//原来的结果
                //解析高亮字段,将原来的字段换为高亮字段
                if (title != null) {
                    Text[] texts = title.fragments();
                    String nTitle = "";
                    for (Text text : texts) {
                        nTitle += text;
                    }
                    //替换
                    sourceAsMap.put(highlightField, nTitle);
                }
                list.add(sourceAsMap);
            }
            return list;
        }
    
        /**
         * 查询并分页
         * 单个匹配termQuery
         * //不分词查询 参数1: 字段名,参数2:字段查询值,因为不分词,所以汉字只能查询一个字,英语是一个单词.
         * QueryBuilder queryBuilder=QueryBuilders.termQuery("fieldName", "fieldlValue");
         * //分词查询,采用默认的分词器
         * QueryBuilder queryBuilder2 = QueryBuilders.matchQuery("fieldName", "fieldlValue");
         * 多个匹配
         * //不分词查询,参数1: 字段名,参数2:多个字段查询值,因为不分词,所以汉字只能查询一个字,英语是一个单词.
         * QueryBuilder queryBuilder=QueryBuilders.termsQuery("fieldName", "fieldlValue1","fieldlValue2...");
         * //分词查询,采用默认的分词器
         * QueryBuilder queryBuilder= QueryBuilders.multiMatchQuery("fieldlValue", "fieldName1", "fieldName2", "fieldName3");
         * //匹配所有文件,相当于就没有设置查询条件
         * QueryBuilder queryBuilder=QueryBuilders.matchAllQuery();
         * <p>
         * 模糊查询常见的5个方法如下
         * //1.常用的字符串查询-左右模糊
         * QueryBuilders.queryStringQuery("fieldValue").field("fieldName");
         * //2.常用的用于推荐相似内容的查询-如果不指定filedName,则默认全部,常用在相似内容的推荐上
         * QueryBuilders.moreLikeThisQuery(new String[] {"fieldName"}).addLikeText("pipeidhua");
         * //3.前缀查询  如果字段没分词,就匹配整个字段前缀
         * QueryBuilders.prefixQuery("fieldName","fieldValue");
         * //4.fuzzy query:分词模糊查询,通过增加fuzziness模糊属性来查询,如能够匹配hotelName为tel前或后加一个字母的文档,fuzziness 的含义是检索的term 前后增加或减少n个单词的匹配查询
         * QueryBuilders.fuzzyQuery("hotelName", "tel").fuzziness(Fuzziness.ONE);
         * //5.wildcard query:通配符查询,支持* 任意字符串;?任意一个字符
         * //前面是fieldname,后面是带匹配字符的字符串
         * QueryBuilders.wildcardQuery("fieldName","ctr*");
         * QueryBuilders.wildcardQuery("fieldName","c?r?");
         * <p>
         * 范围查询
         * //闭区间查询
         * QueryBuilder queryBuilder0 = QueryBuilders.rangeQuery("fieldName").from("fieldValue1").to("fieldValue2");
         * //开区间查询 默认是true,也就是包含
         * QueryBuilder queryBuilder1 = QueryBuilders.rangeQuery("fieldName").from("fieldValue1").to("fieldValue2").includeUpper(false).includeLower(false);
         * //大于
         * QueryBuilder queryBuilder2 = QueryBuilders.rangeQuery("fieldName").gt("fieldValue");
         * //大于等于
         * QueryBuilder queryBuilder3 = QueryBuilders.rangeQuery("fieldName").gte("fieldValue");
         * //小于
         * QueryBuilder queryBuilder4 = QueryBuilders.rangeQuery("fieldName").lt("fieldValue");
         * //小于等于
         * QueryBuilder queryBuilder5 = QueryBuilders.rangeQuery("fieldName").lte("fieldValue");
         * <p>
         * 合查询/多条件查询/布尔查询
         * QueryBuilders.boolQuery()
         * //文档必须完全匹配条件,相当于and
         * QueryBuilders.boolQuery().must();
         * //文档必须不匹配条件,相当于not
         * QueryBuilders.boolQuery().mustNot();
         * //至少满足一个条件,这个文档就符合should,相当于or
         * QueryBuilders.boolQuery().should();
         *
         * @param index          索引名称
         * @param type           类似数据表
         * @param query          查询条件
         * @param size           文档大小限制
         * @param startPage      第几页开始 默认0开始
         * @param fields         需要显示的字段,逗号分隔(缺省为全部字段)
         * @param sortField      排序字段
         * @param highlightField 高亮字段
         * @return
         */
        public EsPage searchListData(String index,
                                     String type,
                                     SearchSourceBuilder query,
                                     Integer size,
                                     Integer startPage,
                                     String fields,
                                     String sortField,
                                     String highlightField) throws IOException {
            SearchRequest request = new SearchRequest(index);
            //request.types(type);
            SearchSourceBuilder builder = query;
            if (StringUtils.isNotEmpty(fields)) {
                //只查询特定字段。如果需要查询所有字段则不设置该项。
                builder.fetchSource(new FetchSourceContext(true, fields.split(","), Strings.EMPTY_ARRAY));
            }
            startPage = startPage <= 0 ? 0 : startPage * size;
            //设置确定结果要从哪个索引开始搜索的from选项,默认为0
            builder.from(startPage);
            builder.size(size);
            if (StringUtils.isNotEmpty(sortField)) {
                //排序字段,注意如果proposal_no是text类型会默认带有keyword性质,需要拼接.keyword
                builder.sort(sortField + ".keyword", SortOrder.ASC);
            }
            //高亮
            if (StringUtils.isNotEmpty(highlightField)) {
                HighlightBuilder highlight = new HighlightBuilder();
                highlight.field(highlightField);
                //关闭多个高亮
                highlight.requireFieldMatch(false);
                highlight.preTags("<span style='color:red'>");
                highlight.postTags("</span>");
                builder.highlighter(highlight);
            }
            //不返回源数据。只有条数之类的数据。
            //builder.fetchSource(false);
    
            request.source(builder);
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            long totalHits = response.getHits().getTotalHits().value;
            log.info("totalHits==" + response.getHits().getTotalHits());
            if (response.status().getStatus() == 200) {
                // 解析对象
                List<Map<String, Object>> sourceList = setSearchResponse(response, highlightField);
                return new EsPage(startPage, size, (int) totalHits, sourceList);
            }
            return null;
        }
    
        /**
         * Description: 组装模糊查询参数
         *
         * @param: filds 模糊查询列
         * @param: querys 模糊查询内容
         * @param: mustFilds 必须匹配列
         * @param: mustQuerys 必须匹配内容
         * @Author: 123107
         * @Date: 2022/05/14 15:25
         * @Return: org.elasticsearch.index.query.BoolQueryBuilder
         * @throws:
         */
        public BoolQueryBuilder boolQueryBuilder(String filds, String querys, String mustFilds, String mustQuerys) {
            if (StringUtils.isBlank(filds) || StringUtils.isBlank(querys)) {
                return null;
            }
            String[] fildList = filds.split(",");
            String[] queryList = querys.split(",");
    
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            for (String fild : fildList) {
                for (String query : queryList) {
                    WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery(fild + KEYWORD, WILD_CODE_A + query + WILD_CODE_A);
                    boolQueryBuilder.should(wildcardQueryBuilder);
                }
            }
            boolQueryBuilder.minimumShouldMatch(1);
    
            //必须匹配条件
            if (StringUtils.isNotBlank(mustFilds) && StringUtils.isNotBlank(mustQuerys)) {
                String[] mfilds = mustFilds.split(",");
                String[] mquserys = mustQuerys.split(",");
                if (mfilds.length == mquserys.length) {
                    for (int i = 0; i < mfilds.length; i++) {
                        QueryBuilder queryBuilder = QueryBuilders.termQuery(mfilds[i], mquserys[i]);
                        boolQueryBuilder.must(queryBuilder);
                    }
                }
            }
            return boolQueryBuilder;
        }
    }

    5、EsPage类

    import java.util.Map;
    import java.util.List;
    
    /**
     * @Author bug
     * @create 2022/05/7 9:31
     * @Description
     */
    public class EsPage {
        /**
         * 当前页
         */
        private int currentPage;
        /**
         * 每页显示多少条
         */
        private int pageSize;
    
        /**
         * 总记录数
         */
        private int recordCount;
        /**
         * 本页的数据列表
         */
        private List<Map<String, Object>> recordList;
    
        /**
         * 总页数
         */
        private int pageCount;
        /**
         * 页码列表的开始索引(包含)
         */
        private int beginPageIndex;
        /**
         * 页码列表的结束索引(包含)
         */
        private int endPageIndex;
    
        /**
         * 只接受前4个必要的属性,会自动的计算出其他3个属性的值
         *
         * @param currentPage
         * @param pageSize
         * @param recordCount
         * @param recordList
         */
        public EsPage(int currentPage, int pageSize, int recordCount, List<Map<String, Object>> recordList) {
            this.currentPage = currentPage;
            this.pageSize = pageSize;
            this.recordCount = recordCount;
            this.recordList = recordList;
    
            // 计算总页码
            pageCount = (recordCount + pageSize - 1) / pageSize;
    
            // 计算 beginPageIndex 和 endPageIndex
            // >> 总页数不多于10页,则全部显示
            if (pageCount <= 10) {
                beginPageIndex = 1;
                endPageIndex = pageCount;
            }
            // >> 总页数多于10页,则显示当前页附近的共10个页码
            else {
                // 当前页附近的共10个页码(前4个 + 当前页 + 后5个)
                beginPageIndex = currentPage - 4;
                endPageIndex = currentPage + 5;
                // 当前面的页码不足4个时,则显示前10个页码
                if (beginPageIndex < 1) {
                    beginPageIndex = 1;
                    endPageIndex = 10;
                }
                // 当后面的页码不足5个时,则显示后10个页码
                if (endPageIndex > pageCount) {
                    endPageIndex = pageCount;
                    beginPageIndex = pageCount - 10 + 1;
                }
            }
        }
    
    
        public int getCurrentPage() {
            return currentPage;
        }
    
        public void setCurrentPage(int currentPage) {
            this.currentPage = currentPage;
        }
    
        public int getPageSize() {
            return pageSize;
        }
    
        public void setPageSize(int pageSize) {
            this.pageSize = pageSize;
        }
    
        public int getRecordCount() {
            return recordCount;
        }
    
        public void setRecordCount(int recordCount) {
            this.recordCount = recordCount;
        }
    
        public List<Map<String, Object>> getRecordList() {
            return recordList;
        }
    
        public void setRecordList(List<Map<String, Object>> recordList) {
            this.recordList = recordList;
        }
    
        public int getPageCount() {
            return pageCount;
        }
    
        public void setPageCount(int pageCount) {
            this.pageCount = pageCount;
        }
    
        public int getBeginPageIndex() {
            return beginPageIndex;
        }
    
        public void setBeginPageIndex(int beginPageIndex) {
            this.beginPageIndex = beginPageIndex;
        }
    
        public int getEndPageIndex() {
            return endPageIndex;
        }
    
        public void setEndPageIndex(int endPageIndex) {
            this.endPageIndex = endPageIndex;
        }
    }

    6、使用示例

    /**
         * Description: es 保存数据   //ES_INDEX 索引名称//ES_TYPE type
         * @param: obj 数据对象
         * @param: id  ES_id UUID.randomUUID().toString().replaceAll("-", "").toUpperCase()
         * @Author: bug
         * @Date: 2022/05/7 18:48
         * @Return: java.lang.String
         * @throws:
         */
        public String insertEs(Object obj, String id) throws Exception {
            try {
                boolean exists = elasticsearchUtil.isIndexExist(EsIndexConstant.ES_INDEX);
                log.info(EsIndexConstant.ES_INDEX + ":index--->>>" + exists);
                if (!exists) {
                    boolean create = elasticsearchUtil.createIndex(EsIndexConstant.ES_INDEX);
                    log.info(EsIndexConstant.ES_INDEX + ":create--->>>" + create);
                }
                elasticsearchUtil.addData(obj, EsIndexConstant.ES_INDEX, EsIndexConstant.ES_TYPE, id);
                log.info(EsIndexConstant.ES_INDEX + ":es保存返回id--->>>" + id);
                return id;
            } catch (Exception e) {
                log.error("es保存异常:" + e.toString());
                throw e;
            }
        }
    
    /**
         * Description: es 更新数据   //ES_INDEX 索引名称//ES_TYPE type
         * @param: obj 数据对象
         * @param: esNumber  ES_id 
         * @Author: bug
         * @Date: 2022/05/7 18:48
         * @Return: java.lang.String
         * @throws:
         */
        public void updateEs(Object obj, String esNumber) throws Exception {
            try {
                boolean exists = elasticsearchUtil.isIndexExist(EsIndexConstant.ES_INDEX);
                log.info(EsIndexConstant.ES_INDEX + ":index--->>>" + exists);
                if (!exists) {
                    boolean create = elasticsearchUtil.createIndex(EsIndexConstant.ES_INDEX);
                    log.info(EsIndexConstant.ES_INDEX + ":create--->>>" + create);
                }
                elasticsearchUtil.updateDataById(obj, EsIndexConstant.ES_INDEX, EsIndexConstant.ES_TYPE, esNumber);
                log.info(EsIndexConstant.ES_INDEX + ":es编辑返回id--->>>" + esNumber);
            } catch (Exception e) {
                log.error("es更新异常:" + e.toString());
                throw e;
            }
        }
    
    /**
         * Description: es 查询数据   从指定的txt字段中,查询含有words内容的数据//ES_INDEX 索引名称//ES_TYPE type
         * @param: words 要查询的内容
         * @param: esNumber  ES_id 
         * @Author: bug
         * @Date: 2022/05/7 18:48
         * @Return: java.lang.List
         * @throws:
         */
    public  List<Map<String, Object>> searchDataFromField(String words)
            int currentPage=0;
            int pageSize=10000;
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = elasticsearchUtil.boolQueryBuilder("txt", words, null, null);
            //增加筛选条件 userType ==1
            //BoolQueryBuilder boolQueryBuilder = elasticsearchUtil.boolQueryBuilder("txt", words, "userType","1"); 
            searchSourceBuilder.query(boolQueryBuilder);
            EsPage esPage = null;
           //要返回的数据字段    
           String fields = "esId,systemId,systemName,fileName,createTime";
            try {
                esPage = elasticsearchUtil.searchListData(EsIndexConstant.ES_INDEX, EsIndexConstant.ES_TYPE searchSourceBuilder, pageSize, currentPage, fields, null, null);
            } catch (IOException e) {
                e.printStackTrace();
            }
            List<Map<String, Object>> records = esPage.getRecordList();
            return records;
    }
  • 相关阅读:
    疫情数据背后,聊聊数据分析平台变迁史
    华为五大专家亲述:如何转型搞 AI?
    【华为云技术分享】LwM2M协议的学习与分享
    Spring5参考指南: BeanWrapper和PropertyEditor
    Spring5参考指南: Resources
    Spring5参考指南:事件Event
    Spring5参考指南:Environment
    Spring5参考指南:JSR 330标准注解
    Spring5参考指南:组件扫描
    Spring5参考指南:基于注解的容器配置
  • 原文地址:https://www.cnblogs.com/guliang/p/16406415.html
Copyright © 2020-2023  润新知