天天看点

elasticsearch7.0.1-Java RestClient API【伸手党福利】【基于Springboot2.1.3集成。非常详细的注释可直接在生产环境中使用】

直接忽略安装教程,网上一搜一大把,安装起来也比较简单。但是网上对于Java RestClient 能够集成很好的没有。接下来我将根据官方API集成了一套Java RestClient API操作模板。

环境说明:

SpringBoot2.1.3 + JDK1.8 + Maven(Springboot自带不好使用,建议按照自己的方式封装)

需要源代码的可以加我微信[JornTang]

application.yml

elasticsearch: 
  # ip地址,多个使用,分隔
  ipAddrs: 127.0.0.1:9200,127.0.0.1:9201
  client: 
    # 连接目标url最大超时
    connectTimeOut: 5000
    # 等待响应(读数据)最大超时
    socketTimeOut: 6000
    # 从连接池中获取可用连接最大超时时间
    connectionRequestTime: 3000
    # 连接池中的最大连接数
    maxConnectNum: 30
    # 连接同一个route最大的并发数
    maxConnectPerRoute: 10
           

pom.xml

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.0.1</version>
</dependency>
           

直接上代码。【ps: 代码待重构】

1、创建RestClientConfig配置类

@Configuration

public class RestClientConfig {

    @Value("${elasticsearch.ipAddrs}")

    private String[] ipAddrs;

    @Value("${elasticsearch.client.connectTimeOut}")

    private Integer connectTimeOut;

    @Value("${elasticsearch.client.socketTimeOut}")

    private Integer socketTimeOut;

    @Value("${elasticsearch.client.connectionRequestTime}")

    private Integer connectionRequestTime;

    @Value("${elasticsearch.client.maxConnectNum}")

    private Integer maxConnectNum;

    @Value("${elasticsearch.client.maxConnectPerRoute}")

    private Integer maxConnectPerRoute;

    @Bean

    public HttpHost[] httpHost(){

        HttpHost[] httpHosts = new HttpHost[ipAddrs.length];

        for (int i = 0; i < ipAddrs.length; i++) {

            String[] ipAddr = ipAddrs[i].split(":");

            httpHosts[i] = new HttpHost(ipAddr[0], Integer.valueOf(ipAddr[1]), "http");

        }

        return httpHosts;

    }

    @Bean(initMethod="init",destroyMethod="close")

    public ElasticRestClientFactory getFactory(){

        return ElasticRestClientFactory.

                build(httpHost(), connectTimeOut, socketTimeOut, connectionRequestTime, maxConnectNum, maxConnectPerRoute);

    }

    @Bean

    @Scope("singleton")

    public RestClient getRestClient(){

        return getFactory().getClient();

    }

    @Bean

    @Scope("singleton")

    public RestHighLevelClient getRestHighClient(){

        return getFactory().getRestHighClient();

    }

}

 2、创建ElasticRestClientFactory工厂类

public class ElasticRestClientFactory {

    private static Logger log = LoggerFactory.getLogger(ElasticRestClientFactory.class);

    // 连接目标url最大超时

    public static int CONNECT_TIMEOUT_MILLIS = 3000;

    // 等待响应(读数据)最大超时

    public static int SOCKET_TIMEOUT_MILLIS = 6000;

    // 从连接池中获取可用连接最大超时时间

    public static int CONNECTION_REQUEST_TIMEOUT_MILLIS = 2000;

    // 连接池中的最大连接数

    public static int MAX_CONN_TOTAL =15;

    // 连接同一个route最大的并发数

    public static int MAX_CONN_PER_ROUTE = 10;

    private static HttpHost[] HTTP_HOST;

    private RestClientBuilder builder;

    private RestClient restClient;

    private RestHighLevelClient restHighLevelClient;

    private static ElasticRestClientFactory restClientFactory = new ElasticRestClientFactory();

    private ElasticRestClientFactory(){}

    public static ElasticRestClientFactory build(HttpHost[] httpHost, Integer maxConnectNum, Integer maxConnectPerRoute){

        HTTP_HOST = httpHost;

        MAX_CONN_TOTAL = maxConnectNum;

        MAX_CONN_PER_ROUTE = maxConnectPerRoute;

        return  restClientFactory;

    }

    public static ElasticRestClientFactory build(HttpHost[] httpHost,Integer connectTimeOut, Integer socketTimeOut,

                                              Integer connectionRequestTime,Integer maxConnectNum, Integer maxConnectPerRoute){

        HTTP_HOST = httpHost;

        CONNECT_TIMEOUT_MILLIS = connectTimeOut;

        SOCKET_TIMEOUT_MILLIS = socketTimeOut;

        CONNECTION_REQUEST_TIMEOUT_MILLIS = connectionRequestTime;

        MAX_CONN_TOTAL = maxConnectNum;

        MAX_CONN_PER_ROUTE = maxConnectPerRoute;

        return  restClientFactory;

    }

    public void init(){

        builder = RestClient.builder(HTTP_HOST);

        setConnectTimeOutConfig();

        setMutiConnectConfig();

        restClient = builder.build();

        restHighLevelClient = new RestHighLevelClient(builder);

        log.info("Elasticsearch highLevelRestClient init successful");

    }

    // 配置连接延时时间

    public void setConnectTimeOutConfig(){

        builder.setRequestConfigCallback(requestConfigBuilder -> {

            requestConfigBuilder.setConnectTimeout(CONNECT_TIMEOUT_MILLIS);

            requestConfigBuilder.setSocketTimeout(SOCKET_TIMEOUT_MILLIS);

            requestConfigBuilder.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT_MILLIS);

            return requestConfigBuilder;

        });

    }

    // 使用异步httpclient时设置并发连接数

    public void setMutiConnectConfig(){

        builder.setHttpClientConfigCallback(httpClientBuilder -> {

            httpClientBuilder.setMaxConnTotal(MAX_CONN_TOTAL);

            httpClientBuilder.setMaxConnPerRoute(MAX_CONN_PER_ROUTE);

            return httpClientBuilder;

        });

    }

    public RestClient getClient(){

        return restClient;

    }

    public RestHighLevelClient getRestHighClient(){

        return restHighLevelClient;

    }

    public void close() {

        if (restClient != null) {

            try {

                restClient.close();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

        log.info("Elasticsearch highLevelRestClient closed");

    }

}

3、创建QueryResult查询结果封装类

public class QueryResult {

    private boolean succesful;

    private long took;

    private boolean timedout;

    private long hitsTotal;

    private float maxScore;

    private Map<String,Integer> shardsInfo;

    private List<Map<String,Object>> hitsBody;

    public QueryResult() {

    }

    public QueryResult(boolean succesful) {

        this.succesful = succesful;

    }

    public boolean getSuccesful() {

        return succesful;

    }

    public void setSuccesful(boolean succesful) {

        this.succesful = succesful;

    }

    public long getTook() {

        return took;

    }

    public void setTook(long took) {

        this.took = took;

    }

    public boolean isTimedout() {

        return timedout;

    }

    public void setTimedout(boolean timedout) {

        this.timedout = timedout;

    }

    public long getHitsTotal() {

        return hitsTotal;

    }

    public void setHitsTotal(long hitsTotal) {

        this.hitsTotal = hitsTotal;

    }

    public float getMaxScore() {

        return maxScore;

    }

    public void setMaxScore(float maxScore) {

        this.maxScore = maxScore;

    }

    public Map<String, Integer> getShardsInfo() {

        return shardsInfo;

    }

    public void setShardsInfo(Map<String, Integer> shardsInfo) {

        this.shardsInfo = shardsInfo;

    }

    public List<Map<String, Object>> getHitsBody() {

        return hitsBody;

    }

    public void setHitsBody(List<Map<String, Object>> hitsBody) {

        this.hitsBody = hitsBody;

    }

}

4、创建ElasticQueryDSLTemplates模板类【基于Query DSL】后续会增加基于SQL一套模板方法

@Component

public class ElasticQueryDSLTemplates {

    private static Logger log = LoggerFactory.getLogger(ElasticQueryDSLTemplates.class);

    @Autowired

    private RestHighLevelClient restHighLevelClient;

    public boolean createIndex(String indexName, Builder builder) throws IOException {

        Assert.notNull(indexName, "索引名称不能为空");

        CreateIndexRequest request = new CreateIndexRequest(indexName);

        request.settings(Settings.builder() 

                .put("index.number_of_shards", 3) // 分片

                .put("index.number_of_replicas", 1) //副本

                .put("refresh_interval", "10s")

            );

        // 创建fullText属性

        Map<String, Object> fullText = new HashMap<>();

        fullText.put("type", "text");

        fullText.put("analyzer", "ik_max_word"); // 可选ik_max_word、ik_smart

        fullText.put("search_analyzer", "ik_smart"); // 可选ik_max_word、ik_smart

        fullText.put("term_vector", "with_positions_offsets"); // 全文检索fvh设置

        // 创建fondCode属性

        Map<String, Object> fondCode = new HashMap<>();

        fondCode.put("type", "keyword");

        Map<String, Object> properties = new HashMap<>();

        properties.put("fullText", fullText);

        properties.put("fondCode", fondCode);

        Map<String, Object> mapping = new HashMap<>();

        mapping.put("properties", properties);

        request.mapping(mapping);

        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);

        boolean acknowledged = createIndexResponse.isAcknowledged();

        return acknowledged;

    }

    public boolean deleteIndex(String indexName) throws IOException {

        Assert.notNull(indexName, "索引名称不能为空");

        DeleteIndexRequest request = new DeleteIndexRequest(indexName);

        AcknowledgedResponse deleteIndexResponse = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);

        return deleteIndexResponse.isAcknowledged();

    }

    public boolean existsIndex(String indexName) throws IOException {

        Assert.notNull(indexName, "索引名称不能为空");

        GetIndexRequest request = new GetIndexRequest(indexName);

        return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);

    }

    public List<AnalyzeResponse.AnalyzeToken> analyzeText(String analyzer, String analyzeText) throws IOException {

        Assert.notNull(analyzer, "分析器不能为空");

        Assert.notNull(analyzeText, "分析文本不能为空");

        AnalyzeRequest analyzeRequest = new AnalyzeRequest();

        analyzeRequest.analyzer(analyzer);        

        analyzeRequest.text(analyzeText);

        AnalyzeResponse response = restHighLevelClient.indices().analyze(analyzeRequest, RequestOptions.DEFAULT);

        return response.getTokens();

    }

    public boolean addDocument(String indexName, String id, Map<String, Object> docMap) {

        boolean optFlag = Boolean.TRUE;

        try {

            Assert.notNull(indexName, "索引名称不能为空");

            Assert.notNull(id, "索引文档ID不能为空");

            Assert.notNull(docMap, "索引文档docMap不能为空");

            IndexRequest indexRequest = new IndexRequest(indexName).id(id).source(docMap);

            indexRequest.opType(DocWriteRequest.OpType.CREATE);

            restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);

        } catch (Exception e) {

            log.error("添加索引文档失败异常。索引名称【{}】,索引文档ID【{}】", indexName, id, e);

            optFlag = Boolean.FALSE;

        }

        return optFlag;

    }

    public Map<String, Object> getDocument(String indexName, String id) {

        Map<String, Object> docMap = null;

        try {

            Assert.notNull(indexName, "索引名称不能为空");

            Assert.notNull(id, "索引文档ID不能为空");

            GetRequest request = new GetRequest(indexName, id);

            GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);

            docMap = response.getSourceAsMap();

        } catch (Exception e) {

            log.error("根据ID获取索引文档异常。索引名称【{}】,索引文档ID【{}】", indexName, id, e);

        }

        return docMap;

    }

    public boolean existsDocument(String indexName, String id) {

        boolean optFlag = Boolean.TRUE;

        try {

            Assert.notNull(indexName, "索引名称不能为空");

            Assert.notNull(id, "索引文档ID不能为空");

            GetRequest request = new GetRequest(indexName, id);    

            request.fetchSourceContext(new FetchSourceContext(false)); 

            request.storedFields("_none_");

            optFlag = restHighLevelClient.exists(request, RequestOptions.DEFAULT);

        } catch (Exception e) {

            log.error("根据ID判断索引文档是否存在异常。索引名称【{}】,索引文档ID【{}】", indexName, id, e);

        }

        return optFlag;

    }

    public boolean deleteDocument(String indexName, String id) {

        boolean optFlag = Boolean.TRUE;

        try {

            Assert.notNull(indexName, "索引名称不能为空");

            Assert.notNull(id, "索引文档ID不能为空");

            GetRequest request = new GetRequest(indexName, id);    

            request.fetchSourceContext(new FetchSourceContext(false)); 

            request.storedFields("_none_");

            optFlag = restHighLevelClient.exists(request, RequestOptions.DEFAULT);

        } catch (Exception e) {

            log.error("根据ID删除索引文档异常。索引名称【{}】,索引文档ID【{}】", indexName, id, e);

        }

        return optFlag;

    }

    public boolean updateDocument(String indexName, String id, Map<String, Object> docMap) {

        boolean optFlag = Boolean.TRUE;

        try {

            Assert.notNull(indexName, "索引名称不能为空");

            Assert.notNull(id, "索引文档ID不能为空");

            Assert.notNull(docMap, "索引文档docMap不能为空");

            UpdateRequest request = new UpdateRequest(indexName, id).doc(docMap);

            restHighLevelClient.update(request, RequestOptions.DEFAULT);

        } catch (Exception e) {

            log.error("根据ID修改索引文档异常。索引名称【{}】,索引文档ID【{}】", indexName, id, e);

        }

        return optFlag;

    }

    public boolean bulkAddDocument(String indexName, List<Map<String, Object>> docMaps) {

        boolean optFlag = Boolean.TRUE;

        try {

            Assert.notNull(indexName, "索引名称不能为空");

            Assert.notNull(docMaps, "索引文档docMaps不能为空");

            BulkRequest bulkRequest = new BulkRequest();

            for (int i = 0; i < docMaps.size(); i++) {

                Map<String, Object> docMap = docMaps.get(i);

                bulkRequest.add(new IndexRequest(indexName).id(docMap.get("id")+"").source(docMaps).opType(DocWriteRequest.OpType.CREATE));

            }

            restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

        } catch (Exception e) {

            log.error("批量添加索引文档异常。索引名称【{}】", indexName, e);

        }

        return optFlag;

    }

    public boolean bulkUpdateDocument(String indexName, List<Map<String, Object>> docMaps) {

        boolean optFlag = Boolean.TRUE;

        try {

            Assert.notNull(indexName, "索引名称不能为空");

            Assert.notNull(docMaps, "索引文档docMaps不能为空");

            BulkRequest bulkRequest = new BulkRequest();

            for (int i = 0; i < docMaps.size(); i++) {

                Map<String, Object> docMap = docMaps.get(i);

                bulkRequest.add(new UpdateRequest(indexName, docMap.get("id")+"").doc(docMap));

            }

            restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

        } catch (Exception e) {

            log.error("批量修改索引文档异常。索引名称【{}】", indexName, e);

        }

        return optFlag;

    }

    public boolean bulkDeleteDocument(String indexName, List<Map<String, Object>> docMaps) {

        boolean optFlag = Boolean.TRUE;

        try {

            Assert.notNull(indexName, "索引名称不能为空");

            Assert.notNull(docMaps, "索引文档docMaps不能为空");

            BulkRequest bulkRequest = new BulkRequest();

            for (int i = 0; i < docMaps.size(); i++) {

                Map<String, Object> docMap = docMaps.get(i);

                bulkRequest.add(new DeleteRequest(indexName, docMap.get("id")+""));

            }

            restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

        } catch (Exception e) {

            log.error("批量修改索引文档异常。索引名称【{}】", indexName, e);

        }

        return optFlag;

    }

    public QueryResult searchForTermsQuery(String indexName, String fieldName, Object... terms ) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(terms, "精准查询条件terms不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            sourceBuilder.query(QueryBuilders.termsQuery(fieldName, terms));

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("精准匹配检索异常。索引名称【{}】, terms查询字段【{}】,查询条件【{}】", indexName, fieldName, JSONObject.toJSONString(terms), e);

        }

        return qr;

    }

    public QueryResult searchForTermsQuery(String indexName, String fieldName, int offset, int pageSize, Object... terms ) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(terms, "精准查询条件terms不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            sourceBuilder.query(QueryBuilders.termsQuery(fieldName, terms));

            // 设置分页

            sourceBuilder.from(offset).size(pageSize);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("精准匹配分页检索异常。索引名称【{}】, terms查询字段【{}】,查询条件【{}】", indexName, fieldName, JSONObject.toJSONString(terms), e);

        }

        return qr;

    }

    public QueryResult searchForRangeQuery(String indexName, String fieldName, Map<String, Object> terms, String format) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(terms, "范围查询条件terms不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            // 设置range查询条件

            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(fieldName);

            for (String key: terms.keySet()) {

                switch (key) {

                    case "gte":

                        rangeQueryBuilder.gte(terms.get(key));

                        continue;

                    case "gt":

                        rangeQueryBuilder.gt(terms.get(key));

                        continue;

                    case "lte":

                        rangeQueryBuilder.lte(terms.get(key));

                        continue;

                    case "lt":

                        rangeQueryBuilder.lt(terms.get(key));

                        continue;

                    default:

                        break;

                    }

            }

            // 设置转换规则 一般针对时间属性 dd/MM/yyyy||yyyy

            if(StringUtils.isNotEmpty(format)) {

                rangeQueryBuilder.format(format);

            }

            sourceBuilder.query(rangeQueryBuilder);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("单属性范围匹配检索异常。索引名称【{}】, range查询字段【{}】,查询条件【{}】", indexName, fieldName, JSONObject.toJSONString(terms), e);

        }

        return qr;

    }

    public QueryResult searchForRangeQuery(String indexName, String fieldName, int offset, int pageSize, Map<String, Object> terms, String format) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(terms, "范围查询条件terms不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            // 设置range查询条件

            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(fieldName);

            for (String key: terms.keySet()) {

                switch (key) {

                    case "gte":

                        rangeQueryBuilder.gte(terms.get(key));

                        continue;

                    case "gt":

                        rangeQueryBuilder.gt(terms.get(key));

                        continue;

                    case "lte":

                        rangeQueryBuilder.lte(terms.get(key));

                        continue;

                    case "lt":

                        rangeQueryBuilder.lt(terms.get(key));

                        continue;

                    default:

                        break;

                    }

            }

            // 设置转换规则 一般针对时间属性 dd/MM/yyyy||yyyy

            if(StringUtils.isNotEmpty(format)) {

                rangeQueryBuilder.format(format);

            }

            sourceBuilder.query(rangeQueryBuilder);

            // 设置分页

            sourceBuilder.from(offset).size(pageSize);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("单属性范围匹配分页检索异常。索引名称【{}】, range查询字段【{}】,查询条件【{}】", indexName, fieldName, JSONObject.toJSONString(terms), e);

        }

        return qr;

    }

    public QueryResult searchForPrefixQuery(String indexName, String fieldName, String term) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(term, "前缀模糊检索条件term不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            sourceBuilder.query(QueryBuilders.prefixQuery(fieldName, term));

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error(" 前缀模糊匹配检索异常。索引名称【{}】, terms查询字段【{}】,查询条件【{}】", indexName, fieldName, term, e);

        }

        return qr;

    }

    public QueryResult searchForPrefixQuery(String indexName, String fieldName, int offset, int pageSize, String term ) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(term, "前缀模糊检索条件term不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            sourceBuilder.query(QueryBuilders.prefixQuery(fieldName, term));

            //设置分页

            sourceBuilder.from(offset).size(pageSize);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error(" 前缀模糊匹配分页检索异常。索引名称【{}】, terms查询字段【{}】,查询条件【{}】", indexName, fieldName, term, e);

        }

        return qr;

    }

    public QueryResult searchForWildcardQuery(String indexName, String fieldName, String term) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(term, "通配符模糊检索条件term不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            sourceBuilder.query(QueryBuilders.wildcardQuery(fieldName, term));

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error(" 通配符模糊匹配检索异常。索引名称【{}】, term查询字段【{}】,查询条件【{}】", indexName, fieldName, term, e);

        }

        return qr;

    }

    public QueryResult searchForWildcardQuery(String indexName, String fieldName, int offset, int pageSize, String term ) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(term, "通配符模糊检索条件term不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            sourceBuilder.query(QueryBuilders.wildcardQuery(fieldName, term));

            // 设置分页

            sourceBuilder.from(offset).size(pageSize);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error(" 通配符模糊匹配检索异常。索引名称【{}】, term查询字段【{}】,查询条件【{}】", indexName, fieldName, term, e);

        }

        return qr;

    }

    public QueryResult searchForFuzzyQuery(String indexName, String fieldName, Object term) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(term, "模糊检索条件term不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            sourceBuilder.query(QueryBuilders.fuzzyQuery(fieldName, term));

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error(" 模糊匹配检索异常。索引名称【{}】, term查询字段【{}】,查询条件【{}】", indexName, fieldName, term, e);

        }

        return qr;

    }

    public QueryResult searchForFuzzyQuery(String indexName, String fieldName, int offset, int pageSize, Object term ) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(term, "模糊检索条件term不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            sourceBuilder.query(QueryBuilders.fuzzyQuery(fieldName, term));

            // 设置分页

            sourceBuilder.from(offset).size(pageSize);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("模糊匹配检索异常。索引名称【{}】, term查询字段【{}】,查询条件【{}】", indexName, fieldName, term, e);

        }

        return qr;

    }

    public QueryResult searchForIdsQuery(String indexName, String fieldName, String... terms ) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(terms, "ids检索条件term不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            sourceBuilder.query(QueryBuilders.idsQuery(terms));

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("根据ids匹配检索异常。索引名称【{}】, term查询字段【{}】,查询条件【{}】", indexName, fieldName, JSONObject.toJSONString(terms), e);

        }

        return qr;

    }

    public QueryResult searchForIdsQuery(String indexName, String fieldName, int offset, int pageSize, String... terms ) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            Assert.notNull(terms, "ids检索条件term不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            sourceBuilder.query(QueryBuilders.idsQuery(terms));

            // 设置分页

            sourceBuilder.from(offset).size(pageSize);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("根据ids匹配分页检索异常。索引名称【{}】, term查询字段【{}】,查询条件【{}】", indexName, fieldName, JSONObject.toJSONString(terms), e);

        }

        return qr;

    }

    public QueryResult searchForBoolQuery(String indexName, Map<String, List<QueryBuilder>> terms) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            //Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            //Assert.notNull(terms, "范围查询条件terms不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            // 设置复合查询

            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            for (String key: terms.keySet()) {

                switch (key) {

                    case "must":

                        List<QueryBuilder> mustQbs = terms.get(key);

                        for(QueryBuilder qb: mustQbs) {

                            boolQueryBuilder.must(qb);

                        }

                        continue;

                    case "filter":

                        List<QueryBuilder> filterQbs = terms.get(key);

                        for(QueryBuilder qb: filterQbs) {

                            boolQueryBuilder.filter(qb);

                        }

                        continue;

                    case "mustNot":

                        List<QueryBuilder> mustNotQbs = terms.get(key);

                        for(QueryBuilder qb: mustNotQbs) {

                            boolQueryBuilder.mustNot(qb);

                        }

                        continue;

                    case "should":

                        List<QueryBuilder> shouldQbs = terms.get(key);

                        for(QueryBuilder qb: shouldQbs) {

                            boolQueryBuilder.should(qb);

                        }

                        continue;

                    default:

                        break;

                    }

            }

            sourceBuilder.query(boolQueryBuilder);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("复合匹配检索异常。索引名称【{}】", indexName, e);

        }

        return qr;

    }

    public QueryResult searchForBoolQuery(String indexName, int offset, int pageSize, Map<String, List<QueryBuilder>> terms) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            //Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            //Assert.notNull(terms, "范围查询条件terms不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            // 设置复合查询

            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            for (String key: terms.keySet()) {

                switch (key) {

                    case "must":

                        List<QueryBuilder> mustQbs = terms.get(key);

                        for(QueryBuilder qb: mustQbs) {

                            boolQueryBuilder.must(qb);

                        }

                        continue;

                    case "filter":

                        List<QueryBuilder> filterQbs = terms.get(key);

                        for(QueryBuilder qb: filterQbs) {

                            boolQueryBuilder.filter(qb);

                        }

                        continue;

                    case "mustNot":

                        List<QueryBuilder> mustNotQbs = terms.get(key);

                        for(QueryBuilder qb: mustNotQbs) {

                            boolQueryBuilder.mustNot(qb);

                        }

                        continue;

                    case "should":

                        List<QueryBuilder> shouldQbs = terms.get(key);

                        for(QueryBuilder qb: shouldQbs) {

                            boolQueryBuilder.should(qb);

                        }

                        continue;

                    default:

                        break;

                    }

            }

            sourceBuilder.query(boolQueryBuilder);

            // 设置分页

            sourceBuilder.from(offset).size(pageSize);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("复合匹配分页检索异常。索引名称【{}】", indexName, e);

        }

        return qr;

    }

    public QueryResult searchForHighlightBoolQuery(String indexName, Map<String, List<QueryBuilder>> terms) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            //Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            //Assert.notNull(terms, "范围查询条件terms不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            // 设置复合查询

            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            for (String key: terms.keySet()) {

                switch (key) {

                    case "must":

                        List<QueryBuilder> mustQbs = terms.get(key);

                        for(QueryBuilder qb: mustQbs) {

                            boolQueryBuilder.must(qb);

                        }

                        continue;

                    case "filter":

                        List<QueryBuilder> filterQbs = terms.get(key);

                        for(QueryBuilder qb: filterQbs) {

                            boolQueryBuilder.filter(qb);

                        }

                        continue;

                    case "mustNot":

                        List<QueryBuilder> mustNotQbs = terms.get(key);

                        for(QueryBuilder qb: mustNotQbs) {

                            boolQueryBuilder.mustNot(qb);

                        }

                        continue;

                    case "should":

                        List<QueryBuilder> shouldQbs = terms.get(key);

                        for(QueryBuilder qb: shouldQbs) {

                            boolQueryBuilder.should(qb);

                        }

                        continue;

                    default:

                        break;

                    }

            }

            sourceBuilder.query(boolQueryBuilder);

            // 高亮构造器

            HighlightBuilder highlightBuilder = new HighlightBuilder(); 

            // 全局设置

            highlightBuilder.numOfFragments(1);

            highlightBuilder.fragmentSize(900);

            // 自定义高亮标签

            highlightBuilder.preTags("<em class='searcHighlight'>");

            highlightBuilder.postTags("</em>");

            HighlightBuilder.Field highlightFullText =new HighlightBuilder.Field("fullText");

            // 设置显示器。支持unified、plain、fvh。默认unified

            highlightFullText.highlighterType("fvh");

            // 设置片段长度,默认100

            highlightFullText.fragmentOffset(300);

            // 设置返回的片段数, 默认5

            highlightFullText.numOfFragments(10);

            highlightBuilder.field(highlightFullText);  

            // 添加更多高亮字段

            //HighlightBuilder.Field highlightUser = new HighlightBuilder.Field("ip_addr");

            //highlightBuilder.field(highlightUser);

            // 设置高亮构造器

            sourceBuilder.highlighter(highlightBuilder);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("复合匹配高亮检索异常。索引名称【{}】", indexName, e);

        }

        return qr;

    }

    public QueryResult searchForHighlightBoolQuery(String indexName, int offset, int pageSize, Map<String, List<QueryBuilder>> terms) {

        QueryResult qr = new QueryResult(Boolean.TRUE);

        try {

            Assert.notNull(indexName, "索引名称indexName不能为空");

            //Assert.notNull(fieldName, "查询目标属性fieldName不能为空");

            //Assert.notNull(terms, "范围查询条件terms不能为空");

            SearchRequest searchRequest = new SearchRequest();

            // 设置要查询的索引名称

            searchRequest.indices(indexName);

            // 构造查询器

            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            // 设置复合查询

            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            for (String key: terms.keySet()) {

                switch (key) {

                    case "must":

                        List<QueryBuilder> mustQbs = terms.get(key);

                        for(QueryBuilder qb: mustQbs) {

                            boolQueryBuilder.must(qb);

                        }

                        continue;

                    case "filter":

                        List<QueryBuilder> filterQbs = terms.get(key);

                        for(QueryBuilder qb: filterQbs) {

                            boolQueryBuilder.filter(qb);

                        }

                        continue;

                    case "mustNot":

                        List<QueryBuilder> mustNotQbs = terms.get(key);

                        for(QueryBuilder qb: mustNotQbs) {

                            boolQueryBuilder.mustNot(qb);

                        }

                        continue;

                    case "should":

                        List<QueryBuilder> shouldQbs = terms.get(key);

                        for(QueryBuilder qb: shouldQbs) {

                            boolQueryBuilder.should(qb);

                        }

                        continue;

                    default:

                        break;

                    }

            }

            sourceBuilder.query(boolQueryBuilder);

            // 高亮构造器

            HighlightBuilder highlightBuilder = new HighlightBuilder(); 

            // 全局设置

            highlightBuilder.numOfFragments(5);

            highlightBuilder.fragmentSize(100);

            // 自定义高亮标签

            highlightBuilder.preTags("<em class='searcHighlight'>");

            highlightBuilder.postTags("</em>");

            HighlightBuilder.Field highlightFullText =new HighlightBuilder.Field("fullText");

            // 设置显示器。支持unified、plain、fvh。默认unified

            highlightFullText.highlighterType("fvh");

            // 设置片段长度,默认100

            highlightFullText.fragmentOffset(100);

            // 设置返回的片段数, 默认5

            highlightFullText.numOfFragments(5);

            highlightBuilder.field(highlightFullText);  

            // 添加更多高亮字段

            //HighlightBuilder.Field highlightUser = new HighlightBuilder.Field("ip_addr");

            //highlightBuilder.field(highlightUser);

            // 设置高亮构造器

            sourceBuilder.highlighter(highlightBuilder);

            // 设置分页

            sourceBuilder.from(offset).size(pageSize);

            // 执行查询

            excuteQuery(searchRequest, sourceBuilder, qr);

        } catch (Exception e) {

            log.error("复合匹配高亮分页检索异常。索引名称【{}】", indexName, e);

        }

        return qr;

    }

    public void excuteQuery(SearchRequest searchRequest, SearchSourceBuilder sourceBuilder, QueryResult qr) throws IOException {

        // 设置超时

        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        // 按查询评分降序 排序支持四种:Field-, Score-, GeoDistance-, ScriptSortBuilder

        sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));

        // 设置查询器

        searchRequest.source(sourceBuilder);

        // 执行查询

        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        // 封装查询结果

        doQueryResult(searchResponse, qr);

    }

    public void doQueryResult(SearchResponse searchResponse, QueryResult qr) {

        // 查询耗时

        TimeValue took = searchResponse.getTook();

        qr.setTook(took.getMillis());

        // 是否超时

        qr.setTimedout(searchResponse.isTimedOut());

        // 查询总数

        qr.setHitsTotal(searchResponse.getHits().getTotalHits().value);

        // 最高评分

        qr.setMaxScore(searchResponse.getHits().getMaxScore());

        // 分片信息

        Map<String, Integer> shardsInfo = new HashMap<String, Integer>();

        shardsInfo.put("total", searchResponse.getTotalShards());

        shardsInfo.put("successful", searchResponse.getSuccessfulShards());

        shardsInfo.put("skipped", searchResponse.getSkippedShards());

        shardsInfo.put("failed", searchResponse.getFailedShards());

        qr.setShardsInfo(shardsInfo);

        // 获取查询结果

        List<Map<String, Object>> hitsBody = new ArrayList<Map<String, Object>>();

        SearchHits termhts=searchResponse.getHits();

        for(SearchHit hit:termhts){

            Map<String, Object> hitMap = hit.getSourceAsMap();

            // 高亮内容封装

            if(hitMap!= null) {

                Map<String, HighlightField> highMap = hit.getHighlightFields();

                Map<String, String> highTextMap = new HashMap<String, String>();

                if(highMap != null) {

                    for (String highKey: highMap.keySet()) {

                        String fieldName = highMap.get(highKey).getName();

                        Text highText = (highMap.get(highKey).fragments())[0];

                        highTextMap.put(fieldName, highText.toString());

                    }

                    hitMap.put("highlight", highTextMap);

                }

            }

            hitsBody.add(hitMap);

        }

         qr.setHitsBody(hitsBody);

    }

}