1.给es中建立索引。product,建立好映射关系PUT product { "mappings": { "properties": { "skuId": { "type": "long" }, "spuId": { "type": "long" }, "skuTitle": { "type": "text", "analyzer": "ik_smart" }, "skuPrice": { "type": "keyword" }, "skuImg": { "type": "keyword", "index": false, "doc_values": false }, "saleCount": { "type": "long" }, "hosStock": { "type": "boolean" }, "hotScore": { "type": "long" }, "brandId": { "type": "long" }, "catelogId": { "type": "long" }, "brandName": { "type": "keyword", "index": false, "doc_values": false }, "brandImg": { "type": "keyword", "index": false, "doc_values": false }, "catelogName": { "type": "keyword", "index": false, "doc_values": false }, "attrs": { "type": "nested", "properties": { "attrId": { "type": "long" }, "attrName": { "type": "keyword", "index": false, "doc_values": false }, "attrValue": { "type": "keyword" } } } } } }2.Service类package com.atguigu.gulimall.lsearch.service; import com.atguigu.common.to.es.SkuEsModel; import java.io.IOException; import java.util.List; public interface ProductSaveService { boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException; }3.ServiceImpl类package com.atguigu.gulimall.lsearch.service.iml; import com.alibaba.fastjson.JSON; import com.atguigu.common.to.es.SkuEsModel; import com.atguigu.gulimall.lsearch.config.GulimallElasticSearchConfig; import com.atguigu.gulimall.lsearch.constant.EsConstant; import com.atguigu.gulimall.lsearch.service.ProductSaveService; import lombok.extern.slf4j.Slf4j; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @Slf4j @Service("productSaveService") public class ProductSaveServiceImpl implements ProductSaveService { @Autowired RestHighLevelClient restHighLevelClient; @Override public boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException { //保存到es //1.给es中建立索引。product,建立好映射关系 //2.给es中保存数据 BulkRequest bulkRequest, RequestOptions options BulkRequest bulkRequest = new BulkRequest(); for (SkuEsModel model : skuEsModels) { //构造保存请求 IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX); indexRequest.id(model.getSkuId().toString()); String s = JSON.toJSONString(model); indexRequest.source(s, XContentType.JSON); bulkRequest.add(indexRequest); } BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, GulimallElasticSearchConfig.COMMON_OPTIONS); //TODO 如果批量保存错误则需要处理 boolean b = bulk.hasFailures(); List<String> collect = Arrays.stream(bulk.getItems()).map(item -> { return item.getId(); }).collect(Collectors.toList()); log.info("商品上架成功:{}，返回数据:{}", collect,bulk.toString()); return b; } }4.Controller类package com.atguigu.gulimall.lsearch.controller; import com.atguigu.common.exception.BizCodeEnume; import com.atguigu.common.to.es.SkuEsModel; import com.atguigu.common.utils.R; import com.atguigu.gulimall.lsearch.service.ProductSaveService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @Slf4j @RequestMapping("/search/save") @RestController public class ElasticSaveController { @Autowired ProductSaveService productSaveService; @PostMapping("/product") public R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels) { boolean b = false; try { b = productSaveService.productStatusUp(skuEsModels); } catch (Exception e) { log.error("ElasticSaveController商品商家错误:{}", e); return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnume.PRODUCT_UP_EXCEPTION.getMessage()); } if (!b) { return R.ok(); } else { return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnume.PRODUCT_UP_EXCEPTION.getMessage()); } } }5.BizCodeEnume枚举package com.atguigu.common.exception; /** * @Description: 错误状态码枚举 * @Created: with IntelliJ IDEA. * @author: 夏沫止水 * @createTime: 2020-05-27 17:29 * * 错误码和错误信息定义类 * 1. 错误码定义规则为5为数字 * 2. 前两位表示业务场景，最后三位表示错误码。例如：100001。10:通用 001:系统未知异常 * 3. 维护错误码后需要维护错误描述，将他们定义为枚举形式 * 错误码列表： * 10: 通用 * 001：参数格式校验 * 002：短信验证码频率太高 * 11: 商品 * 12: 订单 * 13: 购物车 * 14: 物流 * 15：用户 **/ public enum BizCodeEnume { UNKNOW_EXCEPTION(10000, "系统未知异常"), VAILD_EXCEPTION(10001, "参数格式校验失败"), TO_MANY_REQUEST(10002, "请求流量过大，请稍后再试"), SMS_CODE_EXCEPTION(10002, "验证码获取频率太高，请稍后再试"), PRODUCT_UP_EXCEPTION(11000, "商品上架异常"), USER_EXIST_EXCEPTION(15001, "存在相同的用户"), PHONE_EXIST_EXCEPTION(15002, "存在相同的手机号"), NO_STOCK_EXCEPTION(21000, "商品库存不足"), LOGINACCT_PASSWORD_EXCEPTION(15003, "账号或密码错误"), ; private Integer code; private String message; BizCodeEnume(Integer code, String message) { this.code = code; this.message = message; } public Integer getCode() { return code; } public String getMessage() { return message; } }6.其他测试功能package com.atguigu.gulimall.lsearch; import com.alibaba.fastjson.JSON; import com.atguigu.gulimall.lsearch.config.GulimallElasticSearchConfig; import lombok.Data; import lombok.ToString; 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.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilders; 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.Terms; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.Avg; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; import java.util.Map; @SpringBootTest public class GulimallSearchApplicationTests { @Autowired private RestHighLevelClient client; /** * 测试复杂查询功能 */ @Test public void searchDate() throws IOException { //1.创建检索请求 SearchRequest searchRequest = new SearchRequest(); //指定索引 searchRequest.indices("bank"); //指定DSL，检索条件 //SearchSourceBuilder sourceBuilder 封装的条件 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //1.1构造检索条件 searchSourceBuilder.query(); searchSourceBuilder.from(); searchSourceBuilder.size(); searchSourceBuilder.aggregation(); searchSourceBuilder.query(QueryBuilders.matchQuery("address", "mill")); //1.2按照年龄的值分布进行聚合 TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10); searchSourceBuilder.aggregation(ageAgg); //1.3计算平均薪资 TermsAggregationBuilder balanceAvg = AggregationBuilders.terms("balanceAvg").field("balance"); searchSourceBuilder.aggregation(balanceAvg); System.out.println("检索条件" + searchSourceBuilder.toString()); searchRequest.source(searchSourceBuilder); //2.执行检索 SearchResponse searchResponce = client.search(searchRequest, GulimallElasticSearchConfig.COMMON_OPTIONS); //3.分析结果 System.out.println(searchResponce.toString()); //Map map = JSON.parseObject(searchResponce.toString(), Map.class); 这种方式太麻烦 //3.1获取所有查询到的数据 SearchHits hits = searchResponce.getHits(); SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String sourceAsString = hit.getSourceAsString(); Account account = JSON.parseObject(sourceAsString, Account.class); System.out.println("account" + account); } //3.2获取这次检索到的分析信息 Aggregations aggregations = searchResponce.getAggregations(); Terms ageAgg1 = aggregations.get("ageAgg"); for (Terms.Bucket bucket : ageAgg1.getBuckets()) { String keyAsString = bucket.getKeyAsString(); System.out.println("年龄" + keyAsString + "===>" + bucket.getDocCount()); } Avg balanceAvg1 = aggregations.get("balanceAvg"); System.out.println("平均工资" + balanceAvg1.getValue()); } @ToString @Data static class Account { private int account_number; private int balance; private String firstname; private String lastname; private int age; private String gender; private String address; private String employer; private String email; private String city; private String state; } /** * 测试存储数据到es,保存更新二合一 */ @Test public void indexDate() throws IOException { IndexRequest indexRequest = new IndexRequest("users"); //数据的id indexRequest.id("1"); // indexRequest.source("userName", "youzi", "age", 18); User user = new User(); user.setUserName("Youzi"); user.setAge(28); user.setGender("男"); String jsonString = JSON.toJSONString(user); //要保存的内容 indexRequest.source(jsonString, XContentType.JSON); //执行index操作 IndexResponse index = client.index(indexRequest, GulimallElasticSearchConfig.COMMON_OPTIONS); //提取有用的响应数据 System.out.println(index); } @Data class User { private String userName; private String gender; private int age; } }7.工具类package com.atguigu.gulimall.lsearch.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 1.导入配置 * 2.编写配置,给容器内注入一个RestHighLevelClient */ @Configuration public class GulimallElasticSearchConfig { @Bean public RestHighLevelClient esRestClient() { RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( //第一个参数是ElasticSearch安装机地址，第二个参数是端口，第三个参数是协议"http"或"https" new HttpHost("192.168.56.10", 9200, "http") ) ); return client; } public static final RequestOptions COMMON_OPTIONS; static { RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder(); // builder.addHeader("Authorization", "Bearer " + TOKEN); // builder.setHttpAsyncResponseConsumerFactory( // new HttpAsyncResponseConsumerFactory // .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024)); COMMON_OPTIONS = builder.build(); } }
1.导入依赖这里的版本要和所按照的ELK版本匹配。 org.elasticsearch.client elasticsearch-rest-high-level-client 7.6.2 在spring-boot-dependencies中所依赖的ELK版本位6.8.7<elasticsearch.version>6.8.7</elasticsearch.version>需要在项目中将它改为7.6.2 ... <elasticsearch.version>7.6.2</elasticsearch.version> 2.编写配置package com.youzi.gulimall.search.config; import org.apache.http.HttpHost; import org.elasticsearch.client.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Author youzi * @ClassName GulimallElasticSearchConfig * @Date 2022/5/6 9:42 * @Description //TODO */ /** * 1.导入依赖 * 2.编写配置，给容器中注入一个RestHighLevelClient * 3.参照API https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html */ @Configuration public class GulimallElasticSearchConfig { public static final RequestOptions COMMON_OPTIONS; static { RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder(); // builder.addHeader("Authorization", "Bearer " + TOKEN); // builder.setHttpAsyncResponseConsumerFactory( // new HttpAsyncResponseConsumerFactory // .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024)); COMMON_OPTIONS = builder.build(); } @Bean public RestHighLevelClient esRestClient() { RestClientBuilder builder = null; //final String hostname, final int port, final String scheme builder = RestClient.builder(new HttpHost("106.13.234.61", 9200, "http")); RestHighLevelClient client = new RestHighLevelClient(builder); // RestHighLevelClient client = new RestHighLevelClient( // RestClient.builder( // new HttpHost("106.13.234.61", 9200, "http"))); return client; } }3.编写测试类package com.youzi.gulimall.search; import com.alibaba.fastjson.JSON; import com.youzi.gulimall.search.config.GulimallElasticSearchConfig; import lombok.Data; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; @SpringBootTest public class GulimallSearchApplicationTests { @Autowired private RestHighLevelClient client; /** * 测试存储数据到es * 更新也可以 */ @Test public void indexData() throws IOException { IndexRequest indexRequest = new IndexRequest("users"); //数据的ID indexRequest.id("1"); // indexRequest.source("userName","zhangsan","age",18,"gender","男"); Users users = new Users(); users.setUserName("张三"); users.setAge(18); users.setGender("男"); String jsonString = JSON.toJSONString(users); //要保存的内容 indexRequest.source(jsonString, XContentType.JSON); //执行保存操作 IndexResponse index = client.index(indexRequest, GulimallElasticSearchConfig.COMMON_OPTIONS); //提取有用的相应数据 System.out.println(index); } @Data class Users { private String userName; private String gender; private Integer age; } @Test public void contextLoads() { System.out.println(client); } } 输出：IndexResponse[index=users,type=_doc,id=1,version=2,result=updated,seqNo=1,primaryTerm=1,shards={"total":2,"successful":1,"failed":0}]结果如图显示：4.测试复杂检索package com.youzi.gulimall.search; import com.alibaba.fastjson.JSON; import com.youzi.gulimall.search.config.GulimallElasticSearchConfig; import lombok.Data; import lombok.ToString; 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.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilders; 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.Terms; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.Avg; import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; @SpringBootTest public class GulimallSearchApplicationTests { @Autowired private RestHighLevelClient client; @Test public void searchData() throws IOException { //1.创建检索请求 SearchRequest searchRequest = new SearchRequest(); //指定索引 searchRequest.indices("bank"); //指定DSL，检索条件 //SearchSourceBuilder sourceBuilder SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //1.1构造检索条件 // sourceBuilder.query(); // sourceBuilder.from(); // sourceBuilder.size(); // sourceBuilder.aggregation(); sourceBuilder.query(QueryBuilders.matchQuery("address", "mill")); //聚合函数 //1.2按照年龄的值分布，进行聚合 TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10); sourceBuilder.aggregation(ageAgg); //1.3计算平均薪资 AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance"); sourceBuilder.aggregation(balanceAvg); System.out.println("检索条件" + sourceBuilder.toString()); searchRequest.source(sourceBuilder); //2.执行检索; SearchResponse searchResponse = client.search(searchRequest, GulimallElasticSearchConfig.COMMON_OPTIONS); //3.分析结果 searchResponse System.out.println(searchResponse.toString()); //3.1获取所有查到的数据 SearchHits hits = searchResponse.getHits(); SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String string = hit.getSourceAsString(); Account account = JSON.parseObject(string, Account.class); System.out.println("account:" + account); } //3.2获取这次检索到的分析信息 Aggregations aggregations = searchResponse.getAggregations(); //年龄 Terms ageAgg1 = aggregations.get("ageAgg"); for (Terms.Bucket bucket : ageAgg1.getBuckets()) { String keyAsString = bucket.getKeyAsString(); System.out.println("年龄:" + keyAsString + "==>" + bucket.getDocCount()); } //平均工资 Avg balanceAvg1 = aggregations.get("balanceAvg"); System.out.println("平均工资：" + balanceAvg1.getValue()); } /** * 测试存储数据到es * 更新也可以 */ @Test public void indexData() throws IOException { IndexRequest indexRequest = new IndexRequest("users"); //数据的ID indexRequest.id("1"); // indexRequest.source("userName","zhangsan","age",18,"gender","男"); Users users = new Users(); users.setUserName("张三"); users.setAge(18); users.setGender("男"); String jsonString = JSON.toJSONString(users); //要保存的内容 indexRequest.source(jsonString, XContentType.JSON); //执行保存操作 IndexResponse index = client.index(indexRequest, GulimallElasticSearchConfig.COMMON_OPTIONS); //提取有用的相应数据 System.out.println(index); } @Data class Users { private String userName; private String gender; private Integer age; } @ToString @Data static class Account { private int account_number; private int balance; private String firstname; private String lastname; private int age; private String gender; private String address; private String employer; private String email; private String city; private String state; } @Test public void contextLoads() { System.out.println(client); } }输出：年龄:38==>2 年龄:28==>1 年龄:32==>1 平均工资：25208.0