一、项目依赖
既然我们server安装7.3.2,那么我们客户端选择同样版本,高版本提供了更高层的api抽象封装。
<!--引入es -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.3.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.3.2</version>
</dependency>
二、项目配置
- application.properties配置
spring.elasticsearch.nodes=10.143.228.25:9200,10.143.228.26:9200,10.143.228.128:9200
spring.elasticsearch.username=elastic
spring.elasticsearch.password=elastic
- config bean 配置
import com.google.common.collect.Lists;
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.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
import java.util.List;
/**
* @description: elasticSearch配置
* @Date : 2020/5/14 上午11:37
* @Author : 石冬冬-Seig Heil
*/
@Configuration
public class ElasticSearchConfig{
/**
* 使用的协议
*/
final static String schema = "http";
/**
* 连接超时时间
*/
final static int connectTimeOut = 1000;
/**
* 连接超时时间
*/
final static int socketTimeOut = 30000;
/**
* 获取连接的超时时间
*/
final static int connectionRequestTimeOut = 500;
/**
* 最大连接数
*/
final static int maxConnectNum = 100;
/**
* 最大路由连接数
*/
final static int maxConnectPerRoute = 100;
@Value("${spring.elasticsearch.nodes}")
String[] nodes;
@Value("${spring.elasticsearch.username}")
String username;
@Value("${spring.elasticsearch.password}")
String password;
@Bean(name = "restHighLevelClient")
public RestHighLevelClient client() {
RestClientBuilder builder = RestClient.builder(hostList().toArray(new HttpHost[0]));
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(username, password));
builder.setHttpClientConfigCallback(httpClientBuilder -> {
httpClientBuilder.disableAuthCaching();
return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
});
// 异步httpclient连接延时配置
builder.setRequestConfigCallback(requestConfigBuilder -> {
requestConfigBuilder.setConnectTimeout(connectTimeOut);
requestConfigBuilder.setSocketTimeout(socketTimeOut);
requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeOut);
return requestConfigBuilder;
});
// 异步httpclient连接数配置
builder.setHttpClientConfigCallback(httpClientBuilder -> {
httpClientBuilder.setMaxConnTotal(maxConnectNum);
httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
return httpClientBuilder;
});
return new RestHighLevelClient(builder);
}
List<HttpHost> hostList(){
List<HttpHost> nodeList = Lists.newArrayList();
Arrays.asList(nodes).stream().forEach(each -> {
String[] array = each.split(":");
nodeList.add(new HttpHost(array[0],Integer.valueOf(array[1]),schema));
});
return nodeList;
}
}
三、示例介绍
3.1、创建索引
settings是修改分片和副本数的,mappings是修改字段和类型的。
@ApiOperation(value = "createIndex", notes = "createIndex")
@PostMapping("/createIndex/{indexName}")
public Result createIndex(@PathVariable String indexName, @RequestBody Map<String,Map<String,Object>> config) {
try {
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
createIndexRequest.settings(config.get("settings"));
createIndexRequest.mapping(config.get("mapping"));
CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
return Result.suc(JSONObject.toJSON(createIndexResponse));
} catch (IOException e) {
log.error("[createIndex]",e);
return Result.fail(e);
}
}
3.2、判断索引是否存在
public boolean exists(String index) {
boolean exists;
try {
GetIndexRequest getIndexRequest = new GetIndexRequest(index);
getIndexRequest.humanReadable(true);
exists = client.indices().exists(getIndexRequest, DEFAULT);
} catch (IOException e) {
log.error("[ElasticSearch]exists,index={}",index, e);
throw new RuntimeException("[ElasticSearch]exists异常");
}
return exists;
}
3.3、删除索引
public boolean deleteIndex(String... indices) {
boolean acknowledged;
try {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indices);
AcknowledgedResponse delete = client.indices().delete(deleteIndexRequest,DEFAULT);
acknowledged = delete.isAcknowledged();
} catch (IOException e) {
log.error("[ElasticSearch]deleteIndex,indices={}", JSON.toJSONString(indices), e);
throw new RuntimeException("[ElasticSearch]deleteIndex异常");
}
return acknowledged;
}
3.4、插入文档
@ApiOperation(value = "insertRecord", notes = "insertRecord")
@PostMapping("/insertRecord/{indexName}")
public Result insertRecord(@RequestBody Map<String,Object> param, @PathVariable String indexName) {
IndexRequest indexRequest = new IndexRequest(indexName);
String userJson = JSONObject.toJSONString(param);
indexRequest.source(userJson, XContentType.JSON);
try {
IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);
if (response != null) {
ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
log.info("shardInfo={}", JSONObject.toJSON(shardInfo));
}
// 如果有分片副本失败,可以获得失败原因信息
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
String reason = failure.reason();
log.info("副本失败原因,reason={}",reason);
}
}
}
return Result.suc(JSONObject.toJSON(response));
} catch (IOException e) {
log.info("[insertRecord]",e);
return Result.fail(e);
}
}
3.5、批量插入文档
@ApiOperation(value = "bulkInsertRecord", notes = "bulkInsertRecord")
@PostMapping("/bulkInsertRecord/{indexName}")
public Result bulkInsertRecord(@RequestBody List<Map<String,Object>> batch, @PathVariable String indexName) {
BulkRequest bulkRequest = new BulkRequest();
batch.forEach(each -> {
IndexRequest indexRequest = new IndexRequest(indexName).source(each, XContentType.JSON);
bulkRequest.add(indexRequest);
});
//同步
try {
BulkResponse response = client.bulk(bulkRequest,RequestOptions.DEFAULT);
return Result.suc(JSONObject.toJSON(response));
} catch (IOException e) {
log.info("[updateRecord]",e);
return Result.fail(e);
}
}
3.6、更新文档
@ApiOperation(value = "updateRecord", notes = "updateRecord")
@PostMapping("/updateRecord/{indexName}")
public Result updateRecord(@PathVariable String indexName, @RequestParam String id,@RequestBody Map<String,Object> param) {
UpdateRequest updateRequest = new UpdateRequest(indexName,id);
updateRequest.doc(param);
try {
UpdateResponse response = client.update(updateRequest, RequestOptions.DEFAULT);
return Result.suc(JSONObject.toJSON(response));
} catch (IOException e) {
log.info("[updateRecord]",e);
return Result.fail(e);
}
}
3.7、删除文档
@ApiOperation(value = "deleteRecord", notes = "deleteRecord")
@GetMapping("deleteRecord/{indexName}")
public Result deleteRecord(@RequestParam String id, @PathVariable String indexName) {
DeleteRequest deleteRequest = new DeleteRequest(indexName);
deleteRequest.id(id);
try {
DeleteResponse response = client.delete(deleteRequest, RequestOptions.DEFAULT);
return Result.suc(JSONObject.toJSON(response));
} catch (IOException e) {
log.info("[updateRecord]",e);
return Result.fail(e);
}
}
3.8、查询文档
ApiOperation(value = "queryRecord", notes = "queryRecord")
@GetMapping("/queryRecord/{indexName}")
public Result queryRecord(@PathVariable String indexName) {
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//如果用name直接查询,其实是匹配name分词过后的索引查到的记录(倒排索引);如果用name.keyword查询则是不分词的查询,正常查询到的记录
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("birthday").from("1991-01-01").to("2010-10-10").format("yyyy-MM-dd");//范围查询
// TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name.keyword", name);//精准查询
PrefixQueryBuilder prefixQueryBuilder = QueryBuilders.prefixQuery("name.keyword", "张");//前缀查询
// WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("name.keyword", "*三");//通配符查询
// FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("name", "三");//模糊查询
FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("age");//按照年龄排序
fieldSortBuilder.sortMode(SortMode.MIN);//从小到大排序
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(rangeQueryBuilder).should(prefixQueryBuilder);//and or 查询
sourceBuilder.query(boolQueryBuilder).sort(fieldSortBuilder);//多条件查询
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchRequest.source(sourceBuilder);
try {
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = response.getHits();
JSONArray jsonArray = new JSONArray();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
JSONObject jsonObject = JSON.parseObject(sourceAsString);
jsonArray.add(jsonObject);
}
return Result.suc();
} catch (IOException e) {
e.printStackTrace();
return Result.suc();
}
}
3.9、查询文档
通过封装QueryForm
对象实现查询
@ApiOperation(value = "queryCondition", notes = "queryCondition")
@PostMapping("/queryCondition/{indexName}")
public Result queryCondition(@PathVariable String indexName,@RequestBody QueryForm form) {
try {
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source(form.searchSourceBuilder());
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = response.getHits();
JSONArray jsonArray = new JSONArray();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
JSONObject jsonObject = JSON.parseObject(sourceAsString);
jsonArray.add(jsonObject);
}
return Result.suc(jsonArray);
} catch (IOException e) {
return Result.suc();
}
}
@Data
static class QueryForm {
private Integer id;
private String age;
private String name;
private String address;
private String birthday;
private String birthdayRange;
private String ageRange;
SearchSourceBuilder searchSourceBuilder(){
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
if(id != null){
sourceBuilder.query(QueryBuilders.termQuery("id", id));
}
if(name != null){
sourceBuilder.query(QueryBuilders.termQuery("name", id));
}
if(age != null){
sourceBuilder.query(QueryBuilders.termQuery("age", id));
}
if(address != null){
sourceBuilder.query(QueryBuilders.termQuery("address", id));
}
if(birthday != null){
sourceBuilder.query(QueryBuilders.termQuery("birthday", id));
}
if(birthdayRange != null){
String[] array = birthdayRange.split("-");
sourceBuilder.query(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("birthday").from(array[0]).to(array[1]).format("yyyy-MM-dd")));
}
if(ageRange != null){
String[] array = ageRange.split("-");
sourceBuilder.query(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("age").from(array[0]).to(array[1])));
}
return sourceBuilder;
}
}
3.10、源码
源码地址:
https://gitee.com/suze/springBoot/blob/master/src/main/java/org/suze/springboot/elasticsearch/controller/ElasticSearchController.java
源码下载:
git clone https://gitee.com/suze/springBoot
下面的是我的公众号二维码图片,欢迎关注。