java中调用es的两种方式

思考:为啥会写这篇文章也是我最近工作中正好碰到了es的一些查询,当时公司的环境还不是我测试搭建的6.8.2版本还是5.6版本

我准备对某个索引表进行分组统计,试了好几种方式都不行,可能是我没找对方法或该版本实在太低导致查询一直会出现莫名奇妙的问题

然后我就在想为啥es查询不能够像普通的远程调用接口一样查询呢?,因为在postman中es和接口的查询并无两样,那么是不是就可以省掉很多的版本兼容方面的问题

只要在postman可以调用就可以在代码中调用

 

提前准备的es及数据(es我自己搭的单机es具体怎么搭可以看我之前的文章)

索引: test  _type: map

1.在代码中集成RestHighLevelClient调用es查询方法

pom中maven

这个<exclusions>是去除其它的es版本影响

<!--es检索-->
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>6.8.2</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>6.8.2</version>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch</groupId>
                    <artifactId>elasticsearch</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

es的参数配置文件

package com.chinaoly.utils.config.es;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;


/**
 * es配置文件,包含一些常见参数配置
 *
 * @author ljh
 * @date 2025/4/15
 **/
@Data
@ConfigurationProperties("es")
public class ElasticsearchProperties {

    @Value("${es.host}")
    private String esHost;

    @Value("${es.port}")
    private int esPort;

    @ApiModelProperty("连接地址")
    private String host = esHost;

    @ApiModelProperty("端口号")
    private int port = esPort;

    @ApiModelProperty("用户名")
    private String userName = "";

    @ApiModelProperty("密码")
    private String password = "";

    private String scheme = "http";

    @ApiModelProperty("http最大连接数设置")
    private int maxConnTotal = 30;

    @ApiModelProperty("最大路由连接数")
    private int maxConnPerRoute = 100;

    @ApiModelProperty("最大路由连接数")
    private int connectionRequestTimeoutMillis = 40000;

    @ApiModelProperty("连接超时时间")
    private int socketTimeout = 40000;

    @ApiModelProperty("连接超时时间")
    private int connectTimeout = 5000;

    @ApiModelProperty("http保持连接活跃时间")
    private Long keepAliveStrategy = 5000L;
}

es集成client的配置文件

package com.chinaoly.utils.config.es;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
 * 为了得到RestHighLevelClient类直接调用一些es方法等
 *
 * @author ljh
 * @date 2025/4/15
 **/
@Slf4j
@Configuration
@EnableConfigurationProperties(ElasticsearchProperties.class)
public class ElasticSearchConfiguration {

    //这里只是默认地址(不重要)
    public static String DEFAULT_ES_HOST = "127.0.0.1:9200";
    //这是引用配置文件
    private final ElasticsearchProperties properties;

    public ElasticSearchConfiguration(ElasticsearchProperties properties) {
        this.properties = properties;
    }

    /**
     * 这个close是调用RestHighLevelClient中的close
     *
     * @return
     */
    @Bean(destroyMethod = "close")
    @Scope("singleton")
    public RestHighLevelClient createInstance() {
        String host = properties.getHost();
        String username = properties.getUserName();
        String password = properties.getPassword();
        int maxConnectTotal = properties.getMaxConnTotal();
        int maxConnectPerRoute = properties.getMaxConnPerRoute();
        int connectionRequestTimeoutMillis = properties.getConnectionRequestTimeoutMillis();
        int socketTimeoutMillis = properties.getSocketTimeout();
        int connectTimeoutMillis = properties.getConnectionRequestTimeoutMillis();
        Long strategy = properties.getKeepAliveStrategy();
        try {
            if (StringUtils.isEmpty(host)) {
                host = DEFAULT_ES_HOST;
            }
            String[] hosts = host.split(",");
            HttpHost[] httpHosts = new HttpHost[hosts.length];
            for (int i = 0; i < httpHosts.length; i++) {
                httpHosts[i] = new HttpHost(properties.getHost(), properties.getPort(), properties.getScheme());
            }

            RestClientBuilder builder = RestClient.builder(httpHosts);
            builder.setRequestConfigCallback(requestConfigBuilder -> {
                requestConfigBuilder.setConnectTimeout(connectTimeoutMillis);
                requestConfigBuilder.setSocketTimeout(socketTimeoutMillis);
                requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeoutMillis);
                return requestConfigBuilder;
            });
            //这里有两种处理,有用户的和无用户的
            if (!StringUtils.isEmpty(username)) {
                final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                // es账号密码(默认用户名为elastic)
                credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));

                builder.setHttpClientConfigCallback(httpClientBuilder -> {
                    httpClientBuilder.disableAuthCaching();
                    httpClientBuilder.setMaxConnTotal(maxConnectTotal);
                    httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
                    httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    if (strategy > 0) {
                        httpClientBuilder.setKeepAliveStrategy((httpResponse, httpContext) -> strategy);
                    }
                    return httpClientBuilder;
                });
            } else {
                builder.setHttpClientConfigCallback(httpClientBuilder -> {
                    httpClientBuilder.disableAuthCaching();
                    httpClientBuilder.setMaxConnTotal(maxConnectTotal);
                    httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
                    if (strategy > 0) {
                        httpClientBuilder.setKeepAliveStrategy((httpResponse, httpContext) -> strategy);
                    }
                    return httpClientBuilder;
                });
            }

            return new RestHighLevelClient(builder);
        } catch (Exception e) {
            log.error("create RestHighLevelClient error:{}", e);
            return null;
        }
    }


}

接下来就可以在代码中愉快的使用RestHighLevelClient类了

es的方法调用

  @Resource
    private RestHighLevelClient client;

    /**
     * 在代码中集成RestHighLevelClient调用es查询方法
     */
    public Map<String, Object> clientEs() {
        //定义索引名称
        SearchRequest request = new SearchRequest("test");
        request.types("map");

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //条件组装区
        BoolQueryBuilder boolQuery = new BoolQueryBuilder();
        boolQuery.must(QueryBuilders.matchQuery("name", "王娜"));

        //将条件装进request
        sourceBuilder.query(boolQuery);
        request.source(sourceBuilder);

        try {
            //调用es查询方法
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            //遍历hits结果
            for (SearchHit hit : response.getHits().getHits()) {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                log.info("返回参数 data:{}", sourceAsMap);
                return sourceAsMap;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;

    }

上述方法返回结果展示

{
  "code": 200,
  "message": "执行成功",
  "data": {
    "name": "王娜",
    "xb": 2
  }
}

当然这里我只展示了es的普通查询,还有很多查询没有一一展示出来(例如:模糊匹配、批量查询、不规则图形、圆形等)

2.普通的远程调用方法请求es结果

先在postman测试下

远程调用方法

/**
     * 简单的post远程调用方法
     */
    public static String pushEsData(String url, JSONObject json) {
        final CloseableHttpClient httpclient =  HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            //设置url
            HttpPost httpPost = new HttpPost(url);

            //设置请求头
            httpPost.addHeader("Content-Type", "application/json; charset=utf-8");
            httpPost.setHeader("Accept", "*/*");
            //装载参数
            httpPost.setEntity(new StringEntity(json.toString(), StandardCharsets.UTF_8));
            //远程调用接口
            response = httpclient.execute(httpPost);
            //返回结果转成String
            resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            log.info("返回调用结果 resultString:{}", resultString);
            return resultString;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (httpclient!=null) {
                    httpclient.close();
                }
                if (response!=null) {
                    response.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return "";
    }

在代码中调用远程es方法

#查询json
{
    "from": 0,
    "size": 5,
    "query": {
        "bool": {
            "must": {
                "match": {
                    "name": "王娜"
                }
            }
        }
    }
}

 

 /**
     * 普通的远程调用方法请求es结果(postman能调这里也就能调)
     */
    public JSON httpPostEs() {
        //es请求地址
        String url = "http://101.43.67.3:9286/test/map/_search";
        //es的请求body(参数王娜可动态替换)
        String json = "{\n" +
                "    \"query\": {\n" +
                "        \"bool\": {\n" +
                "            \"must\": [\n" +
                "               {\n" +
                "                \"match\":{\n" +
                "                    \"name\":\"王娜\"\n" +
                "                }\n" +
                "               }\n" +
                "            ],\n" +
                "            \"adjust_pure_negative\": true,\n" +
                "            \"boost\": 1.0\n" +
                "        }\n" +
                "    }\n" +
                "}";
        //远程调用
        String resultString = pushEsData(url, JSON.parseObject(json));
        log.info("返回调用结果 resultString:{}", resultString);
        return JSON.parseObject(resultString);
    }

上述调用返回结果展示

{
  "code": 200,
  "message": "执行成功",
  "data": {
    "_shards": {
      "total": 5,
      "failed": 0,
      "successful": 5,
      "skipped": 0
    },
    "hits": {
      "hits": [
        {
          "_index": "test",
          "_type": "map",
          "_source": {
            "name": "王娜",
            "xb": 2
          },
          "_id": "1",
          "_score": 0.5753642
        }
      ],
      "total": 1,
      "max_score": 0.5753642
    },
    "took": 2,
    "timed_out": false
  }
}

可以看到es确实可以做到像普通的远程接口调用一样

远程调用es分组

#分组统计json
{
    "from": 0,
    "size": 0,
    "aggs": {
        "group_by_tags": {
            "terms": {
                "field": "xb",
                "size": 5
            }
        }
    }
}

 

/**
     * 普通的远程调用方法请求es结果(postman能调这里也就能调)
     * 分组统计(aggs)
     */
    public JSON httpPostEsByGroup() {
        //es请求地址
        String url = "http://101.43.67.3:9286/test/map/_search";
        //es的请求body

        /**
         * from,size是es翻页的关键字,这里设为0代表不查询列表只返回分组统计数据
         * group_by_tags: 这是可以自己定义的分组名称
         * field:输入自己需要分组的字段
         * size: 定义只返回分组的数量
         */
        String json = "{\n" +
                "    \"from\": 0,\n" +
                "    \"size\": 0,\n" +
                "    \"aggs\": {\n" +
                "        \"group_by_tags\": {\n" +
                "            \"terms\": {\n" +
                "                \"field\": \"xb\",\n" +
                "                \"size\": 5\n" +
                "            }\n" +
                "        }\n" +
                "    }\n" +
                "}";
        //远程调用
        String resultString = pushEsData(url, JSON.parseObject(json));
        log.info("返回调用结果 resultString:{}", resultString);
        return JSON.parseObject(resultString);
    }

分组返回结果展示(性别为1的确实有两条数据在buckets下)

{
  "code": 200,
  "message": "执行成功",
  "data": {
    "_shards": {
      "total": 5,
      "failed": 0,
      "successful": 5,
      "skipped": 0
    },
    "hits": {
      "hits": [],
      "total": 3,
      "max_score": 0
    },
    "took": 3,
    "timed_out": false,
    "aggregations": {
      "group_by_tags": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "doc_count": 2,
            "key": "1"
          },
          {
            "doc_count": 1,
            "key": "2"
          }
        ]
      }
    }
  }
}

 

posted @ 2025-04-16 14:33  马革皮  阅读(258)  评论(0)    收藏  举报