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、yaml配置

#elasticsearch 多个地址逗号隔开
elasticsearch:
  hostlist: ${eshostlist:10.1.13.235:9200}
  ips: 10.1.13.235
  port: 9300
  pool: 30
  cluster: elasticsearch

 

3、配置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();

    }
}

 

4、工具类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);
    }
}

 

5、工具类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;
    }
}

 

6、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;
    }
}

 

7、使用示例

/**
     * 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;
}

 

posted @ 2022-06-23 19:16  bug毁灭者  阅读(296)  评论(0编辑  收藏  举报