ElasticSearch公共方法封装

业务场景

1、RestClientBuilder初始化(同时支持单机与集群)
2、发送ES查询请求公共方法封装(支持sql、kql、代理访问、集群访问、鉴权支持)
3、判断ES索引是否存在(/_cat/indices/${indexName})
4、判断ES索引别名是否存在 (/_cat/aliases/${indexName})
5、判断ES索引指定字段/属性是否存在(这里字段支持多级,如:logObj.id)
6、判断ES索引指定字段/属性的类型(字段支持多级)
7、阻塞线程直至索引就绪(为了应对跨日时索引名短时间可能不存在的问题)
8、创建索引别名(可用于支持sql查询,索引名中有特殊字符不能用作表名,可通过创建别名来解决)
9、索引别名创建结果解析( 判断acknowledged)
10、KQL查询ES(Kibana语法查询ElasticSearch)
11、SQL查询ES(标准SQL语法查询ElasticSearch)
12、Java在本地通过代理访问ES(可用于解决网络不能直接的问题)
13、Java 客户端访问ES集群(同时支持单机与集群)
14、Java ES客户端鉴权(安全需求)

软件环境

ElasticSearch 7.17.23 下载地址

ElasticSearch 7.17.23 帮助文档

ElasticSearch 8.17.2 下载地址

ElasticSearch 8.17.2 帮助文档

说明:当前例子中用的7,理论上8也通用

Kibana查询效果

KQL查询ES

SQL查询ES

下面讲java代码实现

Java类方法详解

1、RestClientBuilder初始化

同时支持单机与集群

    /**
     * RestClientBuilder 初始化
     *
     * @param host 同时支持单机与集群
     *        单机:host和port各司其职
     *        集群时:port参数无效,host中包含IP和PORT,多个实例用逗号分隔
     *
     *    eg:
     *         10.***.6.247
     *     或: host:10.***.6.247:9200,10.***.6.34:9200,10.***.6.120:9200
     * @param port
     * @return
     */
    private RestClientBuilder buildClient(String host, Integer port){
        RestClientBuilder restClientBuilder = null;
        if(host.indexOf(",")==-1)
        {
            // 单机 host:10.***.6.247, 只有单机会使用port参数
            restClientBuilder = RestClient.builder(new HttpHost( host, port, "http" ) );
        }
        else
        {
            // 集群 host:10.***.6.247:9200,10.***.6.34:9200,10.***.6.120:9200,10.***.6.9:9200,10.***.6.183:9200
            String[] hostArr = host.split("\\,");
            HttpHost[] httpHosts = new HttpHost[hostArr.length];
            for( int i=0; i<hostArr.length; i++ )
            {
                String[] addrs = hostArr[i].split("\\:");
                HttpHost httpHost = new HttpHost( addrs[0],  Integer.valueOf(addrs[1]), "http" );
                httpHosts[i] = httpHost;
            }
            restClientBuilder = RestClient.builder( httpHosts );
        }
        return restClientBuilder;
    }

2、发送ES查询请求公共方法

  • SQL支持
  • KQL支持
  • 支持代理访问支持
  • 鉴权支持
    /**
     * 发送ES 查询请求
     *
     * @param host
     * @param port
     * @param username
     * @param password
     * @param method
     * @param endpoint ES接口
     *      eg:
     *        1、创建别名: "/_aliases"
     *        2、判断索引是否存在: "/_cat/indices/myIndexName"
     *        2、判断索引别名是否存在: "/_cat/aliases/indexName"
     *
     * @param jsonEntity 查询语句
     *      eg:
     *      1、为索引创建别名(可用于支持sql查询,如果使用sql查询时原索引名中有特殊字符不能用作表名,可通过创建别名来解决)
     *         String kqlJson = "{\"actions\" : [{ \"add\" : { \"index\" : \""+idxName+"\",\"alias\" : \""+idxAliases+"\" } }]}  ";
     *         String kqlJson= "";
     *      2、String jsonEntity = "{\"query\": \"" + sqlQuery2 + "\", " +
     *                 "\"params\": ["+cStart+","+cEnd+"]," +
     *                 " \"fetch_size\": 65536 }";
     *
     *  实际业务场景举例:
     *  POST _sql?format=txt
     * {
     *   "query": "SELECT tags.svc_code, sum(iif(tags.response_code.keyword='0000',1,0)) as success_count, count(metric) as total
     *               FROM order_service_****
     *              where create_time between '2025-02-27T11:00:00+0800' and '2025-02-27T13:59:00+0800'
     *              group by tags.svc_code having count(metric)>=50
     *              order by 3 desc",
     *   "fetch_size": 65536
     * }
     *
     * @return
     * @throws IOException
     */
    public String request(String host, Integer port,
                          String username, String password,
                          String method, String endpoint, String jsonEntity) throws IOException {

        RestClientBuilder restClientBuilder = buildClient( host, port );

        if(!StringUtils.isEmpty(username)){
            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
            restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                @Override
                public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                    httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    //线程设置
                    httpClientBuilder.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(2).build());

                    /* ******
                    *  能直连ES的不需要;如果本地不能直连ES的则加上,IP根据实际调整
                    *
                    *  */
                    if("dev".equals(profile) && host.indexOf("10.***.137")==0 ) {
                        httpClientBuilder.setProxy(
                                new HttpHost("10.***.248.54", 8443, "http")  //设置代理服务

                        );
                    }else if("dev".equals(profile)  && host.indexOf("10.***.6")==0  ){
                        httpClientBuilder.setProxy(
                                new HttpHost( "192.***.66.30", 8443,"http")  //设置代理服务
                        );
                    }
                    return httpClientBuilder;
                }
            });
        }

        RestClient restClient = restClientBuilder.build();

        Request request = new Request(method, endpoint );
        request.setJsonEntity( jsonEntity );

        Response response = restClient.performRequest(request);
        HttpEntity entity=response.getEntity();

        restClient.close();

        entity = new BufferedHttpEntity(entity);

        return EntityUtils.toString(entity);
    }

3、判断ES索引是否存在

    /**
     *  判断索引名是否存在
     *
     * @param host
     * @param port
     * @param username
     * @param password
     * @param indexName 索引名
     * @return
     * @throws IOException
     */
    public boolean isExistsIndex( String host, Integer port,
                                  String username, String password,
                                  String indexName ) throws IOException {

        RestClientBuilder restClientBuilder = buildClient( host, port );

        if(!StringUtils.isEmpty(username)){
            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
            restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                @Override
                public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                    httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    //线程设置
                    httpClientBuilder.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(2).build());

                    return httpClientBuilder;
                }
            });
        }

        RestClient restClient = restClientBuilder.build();

        Request request = new Request("GET", "/_cat/indices/"+indexName );
        try{
            Response response = restClient.performRequest(request);
            HttpEntity entity=response.getEntity();
            entity = new BufferedHttpEntity(entity);
            if (!StringUtils.hasLength(EntityUtils.toString(entity))) {
                System.out.println("Index exists.");
                return true;
            } else {
                System.out.println("Index does not exist.");
                return false;
            }
        }catch (Exception e){
            //如果不存在会报404的错误,返回false创建别名
            return false;
        }finally {
            restClient.close();
        }
    }

4、判断ES索引别名是否存在

    /**
     * 判断索引别名是否存在
     *
     * @param host
     * @param port
     * @param username
     * @param password
     * @param indexName
     * @return
     * @throws IOException
     */
    public boolean isExistsAliases( String host, Integer port,
                                    String username, String password,
                                    String indexName ) throws IOException {

        RestClientBuilder restClientBuilder = buildClient( host, port );

        if(!StringUtils.isEmpty(username)){
            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
            restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                @Override
                public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                    httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    //线程设置
                    httpClientBuilder.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(2).build());

                    return httpClientBuilder;
                }
            });
        }

        RestClient restClient = restClientBuilder.build();

        Request request = new Request("GET", "/_cat/aliases/"+indexName );

        Response response = restClient.performRequest(request);
        HttpEntity entity=response.getEntity();

        restClient.close();

        entity = new BufferedHttpEntity(entity);

        if (!StringUtils.isEmpty(EntityUtils.toString(entity))) {
            System.out.println("Index alias exists.");
            return true;
        } else {
            System.out.println("Index alias does not exist.");
            return false;
        }
    }

5、获取ES索引指定字段/属性是否存在

这里字段支持多级,如:logObj.id
    /**
     * 判断索引 某个字段/属性是否存在
     *   说明: 这里字段支持多级,如:logObj.id
     *
     * @param host
     * @param port
     * @param username
     * @param password
     * @param indexName
     * @param property  eg:id、  logObj.id
     * @return
     * @throws IOException
     */
    public boolean isExistsProperty( String host, Integer port,
                                     String username, String password,
                                     String indexName, String property ) throws IOException {

        RestClientBuilder restClientBuilder = buildClient( host, port );

        if(!StringUtils.isEmpty(username)){
            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
            restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                @Override
                public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                    httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    //线程设置
                    httpClientBuilder.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(2).build());

                    return httpClientBuilder;
                }
            });
        }

        RestClient restClient = restClientBuilder.build();

        Request request = new Request("GET", "/"+indexName+"/_mapping" );

        Response response = restClient.performRequest(request);
        HttpEntity entity=response.getEntity();

        restClient.close();
        entity = new BufferedHttpEntity(entity);

        JSONObject obj = JSONObject.parseObject(EntityUtils.toString(entity));

        JSONObject properties = obj.getJSONObject( obj.keySet().iterator().next() )
                .getJSONObject("mappings" )
                .getJSONObject("properties" );

        String[] arr = property.split("\\.");

        for( int i=0; i<arr.length; i++ ){
            if(i==arr.length-1){

            }else{
                if(properties.containsKey( arr[i] )){
                    properties = properties.getJSONObject(arr[i]).getJSONObject("properties" );
                }else{
                    return false;
                }
            }
        }

        boolean bool =  properties.containsKey( arr[arr.length-1] );

        log.info("property:{} , isExist:{}", property, bool );
        return bool;
    }

6、获取ES索引指定字段/属性的类型

同一个索引的同一字段,不同时间的数据类型可能不一样,从而影响sql语句的写法(sql语法不一样),所以个别场景要做判断

    /**
     * 判断索引某个字段/属性的类型
     *   说明: 这里字段支持多级,如:logObj.id
     *
     * @param host
     * @param port
     * @param username
     * @param password
     * @param indexName
     * @param property  eg:id、  logObj.id
     * @return
     * @throws IOException
     */
    public String getIndexPropertyType( String host, Integer port,
                                    String username, String password,
                                    String indexName, String property ) throws IOException {

        RestClientBuilder restClientBuilder = buildClient( host, port );

        if(!StringUtils.isEmpty(username)){
            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
            restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                @O
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞火流星02027

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值