Elasticsearch是开源可扩展的全文检索和分析引擎,用于实时存储、搜索、分析海量信息。Java REST client是其官方提供的客户端,提供特定方法API并对请求和响应封装。本文聚焦如何使用High-Level REST Client。
springboot 默认依赖的版本为6.8,这里在gradle.properties中指定版本7.3.0 。
elasticsearch.version=7.3.0
引用elasticsearch依赖。
implementation 'org.elasticsearch.client:elasticsearch-rest-high-level-client'
implementation 'org.elasticsearch.client:elasticsearch-rest-client'
implementation 'org.elasticsearch:elasticsearch'
@Configuration
@Slf4j
public class EsConfig {
public static final String INDEX_NAME = "my_index";
@Value("192.168.0.1")
private String elasticsearchHost;
@Value("9200")
private int port;
@Bean(name = "highClient", destroyMethod = "close")
public RestHighLevelClient client() {
return new RestHighLevelClient(RestClient.builder(new HttpHost(elasticsearchHost,port)));;
}
@Bean
public IndexRequest buildIndexRequest(){
return new IndexRequest(INDEX_NAME);
}
}
Spring boot也初始化了RestHighLevelClient,这里指定name为highClient。9200是发送http请求端口。
Java High-Level REST Client支持不同API,其中Index, Update, Search, Get, Delete, Bulk应用较多。
ElasticQuery类中引入client和indexRequest。同时定义SearchRequest infoSearch.
@Service
@Slf4j
public class ElasticQuery {
@Qualifier("highClient")
@Autowired
private RestHighLevelClient client;
private final IndexRequest indexRequest;
private SearchRequest infoSearch = new SearchRequest(INDEX_NAME);
public ElasticQuery(IndexRequest indexRequest) {
this.indexRequest = indexRequest;
}
}
IndexRequest提供重载方法source,支持不同类型的数据格式,下面示例使用Map。
public void insertDoc() throws IOException {
Map extInfo = Maps.newHashMap();
extInfo.put("name","李某");
extInfo.put("id_type","1");
extInfo.put("id_code","34561001");
extInfo.put("f_code","C04");
extInfo.put("s_code","01");
extInfo.put("res_property","02");
extInfo.put("person_id","100001");
extInfo.put("resource_key","210C04010001");
extInfo.put("flag","1");
indexRequest.id("80001").source(extInfo);
client.index(indexRequest, RequestOptions.DEFAULT);
}
public void queryDoc() throws IOException {
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.termQuery("name", "李某"));
sourceBuilder.from(0);
sourceBuilder.size(5);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
infoSearch.source(sourceBuilder);
SearchResponse response = client.search(infoSearch, RequestOptions.DEFAULT);
long cnt = response.getHits().getTotalHits().value;
log.info("result.hit={}", cnt);
for (SearchHit hit : response.getHits()) {
Map map = hit.getSourceAsMap();
log.info("map={}", map.toString());
log.info("docId={}", hit.getId());
}
}
SearchSourceBuilder定义查询条件,from和size指定分页,timeout设置超时时间。SearchHit是查询结果,hit.getSourceAsMap()方法把查询结果转为Map。
假如要实现下面查询:
GET /nat_info_index/_search?size=0
{
"query": {
"bool": {
"filter": {"term":{"flag":"1"}}
}
},
"aggs": {
"f-cnt": {
"terms": {
"field": "f_code"
},
"aggs": {
"s-cnt": {
"terms": {
"field": "s_code"
}
}
}
}
}
}
查询所有flag为1的记录,然后根据f_code字段进行分组,在增加一个根据s_code自己进行子分组。
public void aggDoc() throws IOException {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(0);
// 增加bool过滤条件
BoolQueryBuilder booleanQuery = QueryBuilders.boolQuery().filter(QueryBuilders.termQuery("flag","1"));
searchSourceBuilder.query(booleanQuery);
// 增加聚集条件
AggregationBuilder aggregationBuilder = AggregationBuilders.terms("f-cnt").field("f_code").subAggregation(
AggregationBuilders.terms("s-cnt").field("s_code")
);
searchSourceBuilder.aggregation(aggregationBuilder);
// 查询并解析查询结果
infoSearch.source(searchSourceBuilder);
SearchResponse response = client.search(infoSearch.source(searchSourceBuilder), RequestOptions.DEFAULT);
Terms ta1 = response.getAggregations().get("f-cnt");
List extends Terms.Bucket> hit1 = ta1.getBuckets();
for (Terms.Bucket bucket: hit1 ) {
log.info("key={},cnt={}",bucket.getKey(), bucket.getDocCount());
Terms ta2 = bucket.getAggregations().get("s-cnt");
List extends Terms.Bucket> hit2 = ta2.getBuckets();
for (Terms.Bucket bucket2: hit2 ) {
log.info("key2={}, cnt2={}", bucket2.getKey(), bucket2.getDocCount());
}
}
}
输出结果如下:
2019-10-24 18:07:08.712 INFO 5476 --- [ main] com.dataz.textsearch.query.ElasticQuery : key=C02,cnt=1
2019-10-24 18:07:08.713 INFO 5476 --- [ main] com.dataz.textsearch.query.ElasticQuery : key2=03, cnt2=1
2019-10-24 18:07:08.713 INFO 5476 --- [ main] com.dataz.textsearch.query.ElasticQuery : key=C04,cnt=1
2019-10-24 18:07:08.714 INFO 5476 --- [ main] com.dataz.textsearch.query.ElasticQuery : key2=01, cnt2=1
系统中仅有两条记录,且f_code和s_code都不一样,输出结果正确。
本文简单介绍了Elasticsearch Java High-Level REST Client应用,通过示例展示了如何插入、查询和分析文档,更多内容可以参考官方文档。