本次操作是在 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