Java操作方案
直接使用 HTTP
直接使用 HTTP 请求,去操作 Es。HTTP 请求工具,可以使用 Java 自带的 HttpUrlConnection
,也可以使用一些 HTTP 请求库,例如 HttpClient
、OKHttp
、Spring 中的 RestTemplate
都可以。这种方式有一个弊端,就是要自己组装请求参数,自己去解析响应的 JSON。
Low Level REST Client
用于 Es 的官方的低级客户端。这种方式允许通过 HTTP 与 Es 集群进行通信,但是请求时候的 JSON 参数和响应的 JSON 参数交给用户去处理。这种方式好处就是兼容所有的 Es 版本。但是就是数据处理比较麻烦。
High Level REST Client
用户 Es 的官方的高级客户端。这种方式允许通过 HTTP 与 Es 集群进行通信,它是基于 Low Level REST Client,但是提供了很多 API,开发者不需要自己去组装参数,也不需要自己去解析响应 JSON 。这种方式使用起来更加直接。但是需要注意,这种方式,所使用的依赖库的版本要和 Es 对应。
TransportClient
TransportClient 在 Es7 中已经被弃用,在 Es8 中将被完全删除。
下面我们将通过 High Level REST Client
作为演示。
添加 Maven 依赖,注意:使用该依赖需要确保版本跟 elasticsearch 版本一致
代码语言:javascript复制<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.4.2</version>
</dependency>
注意:如果你是在 SpringBoot 环境下学习测试,必须查看版本是否正确。例如下面这种情况,既有7.6.2又有7.4.2,原因就是 SpringBoot 帮我们管理了一个 elasticsearch 版本,只需要在 pom 中指定版本,覆盖掉 SpringBoot 的配置即可。
创建配置类,这里我就起名 LaketradingElasticsearchConfig
@Configuration
public class LaketradingElasticsearchConfig {
public static final RequestOptions COMMON_OPTIONS;
static {
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
//builder.addHeader("Authorization", "Bearer " TOKEN);
//builder.setHttpAsyncResponseConsumerFactory(
// new HttpAsyncResponseConsumerFactory
// .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));
COMMON_OPTIONS = builder.build();
}
@Bean
public RestHighLevelClient esRestClient(){
return new RestHighLevelClient(
RestClient.builder(
new HttpHost("192.168.56.10", 9200, "http")));
}
}
官方的API文档地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high-supported-apis.html
建议读一遍官方文档,了解一个大概,用时查阅即可。
举例测试
接下来我们对之前在高级检索博客中的一些例子,在 java 中用代码实现。
首先是一个匹配的问题,我们对 "address" = "mill lane" 的结果进行筛选。
代码语言:javascript复制@RunWith(SpringRunner.class)
@SpringBootTest
public class LaketradingSearchApplicationTests {
@Autowired
private RestHighLevelClient client;
@Test
public void searchData() throws IOException {
// 创建索引请求
SearchRequest searchRequest = new SearchRequest();
// 指定索引
searchRequest.indices("bank");
// 构造索引条件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery("address","mill lane"));
System.out.println("检索条件:" sourceBuilder.toString());
searchRequest.source(sourceBuilder);
// 执行
SearchResponse searchResponse = client.search(searchRequest, LaketradingElasticsearchConfig.COMMON_OPTIONS);
System.out.println(searchResponse.toString());
}
}
在控制台打印出来的结果可以看出跟我们之前测试一模一样。接下来我们去测试聚合检索。
结果:31岁的人有61个,他们的平均工资为28312。
代码语言:javascript复制"aggregations" : {
"ageAgg" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 463,
"buckets" : [
{
"key" : 31,
"doc_count" : 61,
"balanceAvg" : {
"value" : 28312.918032786885
}
},
...
]
}
}
java代码
代码语言:javascript复制@Test
public void searchData() throws IOException {
// 创建索引请求
SearchRequest searchRequest = new SearchRequest();
// 指定索引
searchRequest.indices("bank");
// 构造索引条件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 聚合条件工具类
AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").subAggregation(balanceAvg);
sourceBuilder.aggregation(ageAgg);
// 因为这次是聚合检索,我们就不看查询结果了,直接看聚合结果。
sourceBuilder.size(0);
System.out.println("检索条件:" sourceBuilder.toString());
searchRequest.source(sourceBuilder);
// 执行
SearchResponse searchResponse = client.search(searchRequest, LaketradingElasticsearchConfig.COMMON_OPTIONS);
System.out.println(searchResponse.toString());
}
当然我们也可以在年龄聚合外来计算平均工资,也就是计算所有人的平均工资,那就把 balanceAvg 跟 ageAgg 同级即可。
代码语言:javascript复制AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age");
sourceBuilder.aggregation(ageAgg).aggregation(balanceAvg);
接下来我们要对命中记录进行分析,在官方文档中有一个 searchResponse.getHits()
方法。
文档位置:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high-search.html
完整的代码测试
代码语言:javascript复制@RunWith(SpringRunner.class)
@SpringBootTest
public class LaketradingSearchApplicationTests {
@Autowired
private RestHighLevelClient client;
@Test
public void search2Data() throws IOException {
// 创建索引请求
SearchRequest searchRequest = new SearchRequest();
// 指定索引
searchRequest.indices("bank");
// 构造索引条件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));
// 聚合条件工具类
AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age");
sourceBuilder.aggregation(ageAgg).aggregation(balanceAvg);
searchRequest.source(sourceBuilder);
// 执行
SearchResponse searchResponse = client.search(searchRequest, LaketradingElasticsearchConfig.COMMON_OPTIONS);
// 获取命中结果
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
// 拿到完整结果字符串
String sourceAsString = hit.getSourceAsString();
// 转换成实体类
Source source = JSON.parseObject(sourceAsString, Source.class);
System.out.println("source:" source );
}
// 获取聚合结果
Aggregations aggregations = searchResponse.getAggregations();
Terms age = aggregations.get("ageAgg");
age.getBuckets().forEach(bucket -> System.out.println("年龄: " bucket.getKeyAsString() ",人数:" bucket.getDocCount()));
Avg balance = aggregations.get("balanceAvg");
System.out.println("平均薪资:" balance.getValue());
}
}
@Data
@ToString
class Source {
private int account_number;
private int balance;
private String firstname;
private String lastname;
private int age;
private String gender;
private String address;
private String employer;
private String email;
private String city;
private String state;
}
结果
代码语言:javascript复制source:Source(account_number=970, balance=19648, firstname=Forbes, lastname=Wallace, age=28, gender=M, address=990 Mill Road, employer=Pheast, email=forbeswallace@pheast.com, city=Lopezo, state=AK)
source:Source(account_number=136, balance=45801, firstname=Winnie, lastname=Holland, age=38, gender=M, address=198 Mill Lane, employer=Neteria, email=winnieholland@neteria.com, city=Urie, state=IL)
source:Source(account_number=345, balance=9812, firstname=Parker, lastname=Hines, age=38, gender=M, address=715 Mill Avenue, employer=Baluba, email=parkerhines@baluba.com, city=Blackgum, state=KY)
source:Source(account_number=472, balance=25571, firstname=Lee, lastname=Long, age=32, gender=F, address=288 Mill Street, employer=Comverges, email=leelong@comverges.com, city=Movico, state=MT)
年龄: 38,人数:2
年龄: 28,人数:1
年龄: 32,人数:1
平均薪资:25208.0
参考资料:松哥公众号
版权属于:乐心湖's Blog
本文链接:https://cloud.tencent.com/developer/article/1781409
声明:博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!