JavaREST客户端有两种模式: Java低级REST客户端和高级REST客户端。低级别的客户端通过http与Elasticearch集群通信,版本兼容性好。高级REST客户端是基于低级客户端API的封装,版本兼容性差。需要的Java1.8以上的版本。Elasticsearch需要6.0以上。
<!--elasticsearch-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.8.17</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.8.17</version>
</dependency>
ElasticSearch的配置信息如下,包括ElasticSearch服务器地址、端口号、索引名字、类型名字。我这里用的是application.yml
server:
port: 8080
spring:
application:
name: springboot-elasticsearch-example
elasticsearch:
schema: http
address: 120.48.54.67:9002
connectTimeout: 10000
socketTimeout: 10000
connectionRequestTimeout: 10000
maxConnectNum: 100
maxConnectPerRoute: 100
配置文件写好后,使用使用一个ElasticSearchConfig实例化创建一个RestHighLevelClient的Bean实例,使用注解将配置文件的值注入到类中,创建RestHighLevelClient对象时可以看到,内部其实是创建了一个低级的客户端RestClient来实现,传入ElasticSearch的服务器地址和端口号。
package club.mydlq.elasticsearch.config;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
* ElasticSearch 配置
*/
@Configuration
public class ElasticSearchConfig {
/** 协议 */
@Value("${elasticsearch.schema:http}")
private String schema;
/** 集群地址,如果有多个用“,”隔开 */
@Value("${elasticsearch.address}")
private String address;
/** 连接超时时间 */
@Value("${elasticsearch.connectTimeout:5000}")
private int connectTimeout;
/** Socket 连接超时时间 */
@Value("${elasticsearch.socketTimeout:10000}")
private int socketTimeout;
/** 获取连接的超时时间 */
@Value("${elasticsearch.connectionRequestTimeout:5000}")
private int connectionRequestTimeout;
/** 最大连接数 */
@Value("${elasticsearch.maxConnectNum:100}")
private int maxConnectNum;
/** 最大路由连接数 */
@Value("${elasticsearch.maxConnectPerRoute:100}")
private int maxConnectPerRoute;
@Bean
public RestHighLevelClient restHighLevelClient() {
// 拆分地址
List<HttpHost> hostLists = new ArrayList<>();
String[] hostList = address.split(",");
for (String addr : hostList) {
String host = addr.split(":")[0];
String port = addr.split(":")[1];
hostLists.add(new HttpHost(host, Integer.parseInt(port), schema));
}
// 转换成 HttpHost 数组
HttpHost[] httpHost = hostLists.toArray(new HttpHost[]{});
// 构建连接对象
RestClientBuilder builder = RestClient.builder(httpHost);
// 异步连接延时配置
builder.setRequestConfigCallback(requestConfigBuilder -> {
requestConfigBuilder.setConnectTimeout(connectTimeout);
requestConfigBuilder.setSocketTimeout(socketTimeout);
requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
return requestConfigBuilder;
});
// 异步连接数配置
builder.setHttpClientConfigCallback(httpClientBuilder -> {
httpClientBuilder.setMaxConnTotal(maxConnectNum);
httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
return httpClientBuilder;
});
return new RestHighLevelClient(builder);
}
}
package club.mydlq.elasticsearch.service.base;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
/**
* 索引操作
*/
@Slf4j
@Service
public class IndexService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* 验证索引是否存在
*/
public Object existsIndex() {
Object result = "";
try {
// 获取索引请求
GetIndexRequest request = new GetIndexRequest();
// 设置要查询的索引名称
request.indices("mydlq-user");
// 执行请求,验证索引是否存在
boolean isExist = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
log.info("是否存在:{}", isExist);
// 根据具体业务逻辑返回不同结果,这里为了方便直接将结果返回
result = isExist;
} catch (IOException e) {
log.error("", e);
}
return result;
}
/**
* 创建索引
*/
public Object createIndex() {
Object result = "";
try {
// 创建 Mapping
XContentBuilder mapping = XContentFactory.jsonBuilder()
.startObject()
.field("dynamic", true)
.startObject("properties")
.startObject("name")
.field("type","text")
.startObject("fields")
.startObject("keyword")
.field("type","keyword")
.endObject()
.endObject()
.endObject()
.startObject("address")
.field("type","text")
.startObject("fields")
.startObject("keyword")
.field("type","keyword")
.endObject()
.endObject()
.endObject()
.startObject("remark")
.field("type","text")
.startObject("fields")
.startObject("keyword")
.field("type","keyword")
.endObject()
.endObject()
.endObject()
.startObject("age")
.field("type","integer")
.endObject()
.startObject("salary")
.field("type","float")
.endObject()
.startObject("birthDate")
.field("type","date")
.field("format", "yyyy-MM-dd")
.endObject()
.startObject("createTime")
.field("type","date")
.endObject()
.endObject()
.endObject();
// 创建索引配置信息,配置
Settings settings = Settings.builder()
.put("index.number_of_shards", 1)
.put("index.number_of_replicas", 0)
.build();
// 新建创建索引请求对象,然后设置索引类型(ES 7.0 将不存在索引类型)和 mapping 与 index 配置
CreateIndexRequest request = new CreateIndexRequest("mydlq-user", settings);
request.mapping("doc", mapping);
// RestHighLevelClient 执行创建索引
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
// 判断是否创建成功
boolean isCreated = createIndexResponse.isAcknowledged();
log.info("是否创建成功:{}", isCreated);
// 根据具体业务逻辑返回不同结果,这里为了方便直接将结果返回
result = isCreated;
} catch (IOException e) {
log.error("", e);
}
return result;
}
/**
* 删除索引
*/
public Object deleteIndex() {
Object result = "";
try {
// 新建删除索引请求对象
DeleteIndexRequest request = new DeleteIndexRequest("mydlq-user");
// 执行删除索引
AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
// 判断是否删除成功
boolean siDeleted = acknowledgedResponse.isAcknowledged();
log.info("是否删除成功:{}", siDeleted);
// 根据具体业务逻辑返回不同结果,这里为了方便直接将结果返回
result = siDeleted;
} catch (IOException e) {
log.error("", e);
}
return result;
}
}
package club.mydlq.elasticsearch.service.base;
import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Date;
/**
* 文档操作
*/
@Slf4j
@Service
public class DocumentService {
@Autowired
private RestHighLevelClient restHighLevelClient;
public Object existsDocument() {
Object result = "";
try {
// 获取请求对象
GetRequest getRequest = new GetRequest("mydlq-user", "doc", "1");
// 是否获取源码内容
getRequest.fetchSourceContext(new FetchSourceContext(false));
// 执行请求,验证文档是否存在
boolean isExist = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
log.info("文档是否存在:{}", isExist);
// 根据具体业务逻辑返回不同结果,这里为了方便直接将结果返回
result = isExist;
} catch (IOException e) {
log.error("", e);
}
return result;
}
public Object getDocument() {
Object result = "";
try {
// 获取请求对象
GetRequest getRequest = new GetRequest("mydlq-user", "doc", "1");
// 获取文档信息
GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
// 将 JSON 转换成对象
if (getResponse.isExists()) {
UserInfo userInfo = JSON.parseObject(getResponse.getSourceAsBytes(), UserInfo.class);
log.info("用户信息:{}", userInfo);
}
// 根据具体业务逻辑返回不同结果,这里为了方便直接将结果返回
result = getResponse.getSourceAsString();
} catch (IOException e) {
log.error("", e);
}
return result;
}
public Object addDocument() {
Object result = "";
try {
// 创建索引请求对象
IndexRequest indexRequest = new IndexRequest("mydlq-user", "doc", "1");
// 创建用户信息
UserInfo userInfo = new UserInfo();
userInfo.setName("张三");
userInfo.setAge(29);
userInfo.setSalary(100.00f);
userInfo.setAddress("北京市");
userInfo.setRemark("来自北京市的张先生");
userInfo.setCreateTime(new Date());
userInfo.setBirthDate("1990-01-10");
// 将对象转换为 byte 数组
byte[] json = JSON.toJSONBytes(userInfo);
// 设置文档内容
indexRequest.source(json, XContentType.JSON);
// 执行增加文档
IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
log.info("创建状态:{}", response.status());
// 根据具体业务逻辑返回不同结果,这里为了方便直接将结果返回
result = response.getResult();
} catch (Exception e) {
log.error("", e);
}
return result;
}
public Object updateDocument() {
Object result = "";
try {
// 创建索引请求对象
UpdateRequest updateRequest = new UpdateRequest("mydlq-user", "doc", "1");
// 设置用户更新信息
UserInfo userInfo = new UserInfo();
userInfo.setSalary(200.00f);
userInfo.setAddress("北京市海淀区");
// 将对象转换为 byte 数组
byte[] json = JSON.toJSONBytes(userInfo);
// 设置更新文档内容
updateRequest.doc(json, XContentType.JSON);
// 执行更新文档
UpdateResponse response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
log.info("创建状态:{}", response.status());
// 根据具体业务逻辑返回不同结果,这里为了方便直接将结果返回
result = response.getResult();
} catch (Exception e) {
log.error("", e);
}
return result;
}
public Object deleteDocument() {
Object result = "";
try {
// 创建删除请求对象
DeleteRequest deleteRequest = new DeleteRequest("mydlq-user", "doc", "1");
// 执行删除文档
DeleteResponse response = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
log.info("删除状态:{}", response.status());
// 根据具体业务逻辑返回不同结果,这里为了方便直接将结果返回
result = response.getResult();
} catch (IOException e) {
log.error("", e);
}
return result;
}
}
package club.mydlq.elasticsearch.service.aggregation;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.tophits.ParsedTopHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.List;
/**
* 聚合 Bucket 与 Metric
*/
@Slf4j
@Service
public class AggrBucketMetricService {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* topHits 按照员工岁数分桶、然后统计每个岁数员工工资最高值
*/
public Object aggregationTopHits() {
String responseResult = "";
try {
AggregationBuilder testTop = AggregationBuilders.topHits("salary_max_user")
.size(1)
.sort("salary", SortOrder.DESC);
AggregationBuilder salaryBucket = AggregationBuilders.terms("salary_bucket")
.field("age")
.size(10);
salaryBucket.subAggregation(testTop);
// 查询源构建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(0);
searchSourceBuilder.aggregation(salaryBucket);
// 创建查询请求对象,将查询条件配置到其中
SearchRequest request = new SearchRequest("mydlq-user");
request.source(searchSourceBuilder);
// 执行请求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 获取响应中的聚合信息
Aggregations aggregations = response.getAggregations();
// 输出内容
if (RestStatus.OK.equals(response.status())) {
// 分桶
Terms byCompanyAggregation = aggregations.get("salary_bucket");
List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();
// 输出各个桶的内容
log.info("-------------------------------------------");
log.info("聚合信息:");
for (Terms.Bucket bucket : buckets) {
log.info("桶名:{}", bucket.getKeyAsString());
ParsedTopHits topHits = bucket.getAggregations().get("salary_max_user");
for (SearchHit hit:topHits.getHits()){
log.info(hit.getSourceAsString());
}
}
log.info("-------------------------------------------");
// 根据具体业务逻辑返回不同结果,这里为了方便直接将返回响应对象Json串
responseResult = response.toString();
}
} catch (IOException e) {
log.error("", e);
}
return responseResult;
}
}