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
* <p>
* 错误码和错误信息定义类
* 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();
}
}