本次操作是在 Windows上安装ElasticSearch7 进行操作
导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.es.demo</groupId>
<artifactId>elastic-search-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>elastic-search-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.3.2</elasticsearch.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Java High Level REST Client -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<!-- commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<!-- Swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8833
spring:
application:
name: elastic_search
#es http方式
elasticsearch:
address: localhost:9200
# username: admin
# password: admin
es配置加载
package com.es.demo.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.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.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
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.Objects;
/**
* es RestHighLevelClient 配置
* es 7.x之后 只支持http
* @author qjc
* @date 2019-07-19 10:33
*/
@Configuration
@Slf4j
public class ESConfig {
private static final int ADDRESS_LENGTH = 2;
private static final String HTTP_SCHEME = "http";
//权限验证
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
/**
* 使用冒号隔开ip和端口
*/
@Value("${elasticsearch.address}")
private String[] address;
// @Value("${elasticsearch.username}")
// private String username;
// @Value("${elasticsearch.password}")
// private String password;
@Bean
public RestClientBuilder restClientBuilder() {
HttpHost[] hosts = Arrays.stream(address)
.map(this::makeHttpHost)
.filter(Objects::nonNull)
.toArray(HttpHost[]::new);
log.debug("hosts:{}", Arrays.toString(hosts));
//配置权限验证
// credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
RestClientBuilder restClientBuilder = RestClient.builder(hosts).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
});
return restClientBuilder;
}
@Bean(name = "highLevelClient")
public RestHighLevelClient highLevelClient(@Autowired RestClientBuilder restClientBuilder) {
// restClientBuilder.setMaxRetryTimeoutMillis(60000);
return new RestHighLevelClient(restClientBuilder);
}
/**
* 处理请求地址
* @param s
* @return HttpHost
*/
private HttpHost makeHttpHost(String s) {
assert StringUtils.isNotEmpty(s);
String[] address = s.split(":");
if (address.length == ADDRESS_LENGTH) {
String ip = address[0];
int port = Integer.parseInt(address[1]);
return new HttpHost(ip, port, HTTP_SCHEME);
} else {
return null;
}
}
}
swagger
package com.es.demo.swagger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.async.DeferredResult;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration // 启动时就要加载
@EnableSwagger2
public class SwaggerConfig {
private String version;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.genericModelSubstitutes(DeferredResult.class)
.select()
.paths(PathSelectors.any())
.build().apiInfo(apiInfo());//.globalOperationParameters(pars);
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("Earth server")
.description("****")
.termsOfServiceUrl("http://www.baidu.com")
.version("1.0").build();
}
}
插入的实体:
package com.es.demo.vo;
import lombok.Data;
/**
* @Description:
* @Param:
* @Return:
* @Author: qjc
* @Date: 2019/10/18
*/
@Data //IDEA需要安装lombok:https://www.cnblogs.com/java-spring/p/9797560.html
public class User {
private String name;
private int age;
private Double money;
private String address;
private String birthday;
}
响应实体
package com.es.demo.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class ResponseBean {
//状态码
private Integer code;
//返回信息
private String message;
//返回的数据
private Object data;
}
es操作
创建索引时需要用到IK分词器,请参考: Windows上安装ElasticSearch7的IK分词器
package com.es.demo.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.es.demo.utils.ESUtil;
import com.es.demo.vo.ResponseBean;
import com.es.demo.vo.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.replication.ReplicationResponse;
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.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortMode;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @Author: qjc
* @Date: 2019/09/18
*/
@Api(value = "ES测试接口", tags = {"ES测试接口"})
@RestController
@RequestMapping("/es")
@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.PUT})
@Slf4j
public class ESTestController {
@Resource
private RestHighLevelClient restHighLevelClient;
@Resource
ESUtil esUtil;
@ApiOperation(value = "es测试创建索引接口", notes = "es测试创建索引接口")
@RequestMapping(value = "/create/index", method = RequestMethod.POST)
public ResponseBean createIndex(@RequestParam String indexName) {
try {
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.field("properties")
.startObject()
.field("name").startObject().field("index", "true").field("type", "keyword").endObject()
.field("age").startObject().field("index", "true").field("type", "integer").endObject()
.field("money").startObject().field("index", "true").field("type", "double").endObject()
.field("address").startObject().field("index", "true").field("type", "text").field("analyzer", "ik_max_word").endObject()
.field("birthday").startObject().field("index", "true").field("type", "date").field("format", "strict_date_optional_time||epoch_millis").endObject()
.endObject()
.endObject();
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
createIndexRequest.mapping(builder);
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
boolean acknowledged = createIndexResponse.isAcknowledged();
if (acknowledged) {
return new ResponseBean(200, "创建成功", null);
} else {
return new ResponseBean(1002, "创建失败", null);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@ApiOperation(value = "es测试是否存在索引接口", notes = "es测试是否存在索引接口")
@RequestMapping(value = "/index/exists", method = RequestMethod.POST)
public ResponseBean indexExists(@RequestParam String indexName) {
boolean isExists = esUtil.isIndexExists(indexName);
return new ResponseBean(200, "查询成功", isExists);
}
@ApiOperation(value = "es测试删除索引接口", notes = "es测试删除索引接口")
@RequestMapping(value = "/delete/index", method = RequestMethod.POST)
public ResponseBean deleteIndex(@RequestParam String indexName) {
boolean isDelete = esUtil.deleteIndex(indexName);
if (isDelete) {
return new ResponseBean(200, "删除成功", null);
} else {
return new ResponseBean(10002, "删除失败", null);
}
}
@ApiOperation(value = "es测试插入接口", notes = "es测试插入接口")
@RequestMapping(value = "/insert/data", method = RequestMethod.POST)
public ResponseBean findIndustryClassList(@RequestBody User user, @RequestParam String indexName) {
IndexRequest indexRequest = new IndexRequest(indexName);
String userJson = JSONObject.toJSONString(user);
indexRequest.source(userJson, XContentType.JSON);
try {
IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
if (indexResponse != null) {
String id = indexResponse.getId();
String index = indexResponse.getIndex();
long version = indexResponse.getVersion();
log.info("index:{},id:{}", index, id);
if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
System.out.println("新增文档成功!" + index + "-" + id + "-" + version);
return new ResponseBean(200, "插入成功", id);
} else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
System.out.println("修改文档成功!");
return new ResponseBean(10001, "插入失败", null);
}
// 分片处理信息
ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
System.out.println("分片处理信息.....");
}
// 如果有分片副本失败,可以获得失败原因信息
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
String reason = failure.reason();
System.out.println("副本失败原因:" + reason);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@ApiOperation(value = "es测试普通查询接口", notes = "es测试普通查询接口")
@RequestMapping(value = "/query/data", method = RequestMethod.GET)
public ResponseBean testESFind() {
SearchRequest searchRequest = new SearchRequest("test_es");
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 = restHighLevelClient.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 new ResponseBean(200, "查询成功", jsonArray);
} catch (IOException e) {
e.printStackTrace();
return new ResponseBean(10001, "查询失败", null);
}
}
@ApiOperation(value = "es测试聚合查询接口", notes = "es测试聚合查询接口")
@RequestMapping(value = "/query/agg", method = RequestMethod.GET)
public ResponseBean testESFindAgg() {
SearchRequest searchRequest = new SearchRequest("test_es");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("by_age").field("age");
sourceBuilder.aggregation(termsAggregationBuilder);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchRequest.source(sourceBuilder);
try {
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
Aggregations aggregations = searchResponse.getAggregations();
Map<String, Aggregation> stringAggregationMap = aggregations.asMap();
ParsedLongTerms parsedLongTerms = (ParsedLongTerms) stringAggregationMap.get("by_age");
List<? extends Terms.Bucket> buckets = parsedLongTerms.getBuckets();
Map<Integer, Long> map = new HashMap<>();
for (Terms.Bucket bucket : buckets) {
long docCount = bucket.getDocCount();//个数
Number keyAsNumber = bucket.getKeyAsNumber();//年龄
System.err.println(keyAsNumber + "岁的有" + docCount + "个");
map.put(keyAsNumber.intValue(), docCount);
}
return new ResponseBean(200, "查询成功", map);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@ApiOperation(value = "es测试更新接口", notes = "es测试更新接口")
@RequestMapping(value = "/update/data", method = RequestMethod.GET)
public ResponseBean testESUpdate(@RequestParam String id, @RequestParam Double money) {
UpdateRequest updateRequest = new UpdateRequest("test_es", id);
Map<String, Object> map = new HashMap<>();
map.put("money", money);
updateRequest.doc(map);
try {
UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
if (updateResponse.getResult() == DocWriteResponse.Result.UPDATED) {
return new ResponseBean(200, "更新成功", null);
} else {
return new ResponseBean(10002, "删除失败", null);
}
} catch (IOException e) {
e.printStackTrace();
return new ResponseBean(1003, "删除异常", null);
}
}
@ApiOperation(value = "es测试删除接口", notes = "es测试删除接口")
@RequestMapping(value = "/delete/data", method = RequestMethod.GET)
public ResponseBean testESDelete(@RequestParam String id, @RequestParam String indexName) {
DeleteRequest deleteRequest = new DeleteRequest(indexName);
deleteRequest.id(id);
try {
DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
return new ResponseBean(1001, "删除失败", null);
} else {
return new ResponseBean(200, "删除成功", null);
}
} catch (IOException e) {
e.printStackTrace();
return new ResponseBean(1003, "删除异常", null);
}
}
}
package com.es.demo.utils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
/**
* @Description:
* @Author: qjc
* @Date: 2019/10/30
*/
@Component
public class ESUtil {
@Resource
RestHighLevelClient restHighLevelClient;
/**
* 判断索引是否存在
*
* @param indexName
* @return
*/
public boolean isIndexExists(String indexName) {
boolean exists = false;
try {
GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
getIndexRequest.humanReadable(true);
exists = restHighLevelClient.indices().exists(getIndexRequest,RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
return exists;
}
/**
* 删除索引
*
* @param indexName
* @return
*/
public boolean deleteIndex(String indexName) {
boolean acknowledged = false;
try {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
deleteIndexRequest.indicesOptions(IndicesOptions.LENIENT_EXPAND_OPEN);
AcknowledgedResponse delete = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
acknowledged = delete.isAcknowledged();
} catch (IOException e) {
e.printStackTrace();
}
return acknowledged;
}
}
创建索引成功后,可以用以下方式查看
通过访问swagger http://localhost:8833/swagger-ui.html#/ 可以进行如下操作
源码地址:
https://gitee.com/xiaorenwu_dashije/es_search_demo.git
来源:oschina
链接:https://my.oschina.net/u/4303162/blog/3365233