1.名次介绍
- index 索引:相当于mysql的database
- type 类型: 相当于mysql的table
- document 文档: 在某个index中的type里面的一条数据,是json格式的
2.初步检索
1._cat
- postman测试 http://ip:9200/_cat/**
2.ES数据扁平化处理
- ES添加一个数据 user是一个数组 但添加后es会做一个扁平化处理 处理后的数据是这个样子的
-
这个时候去检索就会有问题
-
将user type设置嵌入式属性即可
3.boot整合es 7.12.1
1.导入pom
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticsearch-rest-high-level.version}</version>
</dependency>
-
但发现es client的版本并不是7.12.1而是boot设置的6.4
-
解决 将pom版本改成7.12.1
4.完成商品上架功能
-
功能实现:点击上传后需要将sku数据导入到es中
-
安装es、ik、kibana
docker run -d --name elasticsearch \ -v /mydata/es/data:/usr/share/elasticsearch/data \ --restart=always -p 9200:9200 -p 9300:9300 \ -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \ -e "discovery.type=single-node" d9c406333741 # 上传ik docker cp /mydata/es/plugins/ik elasticsearch:/usr/share/elasticsearch/plugins docker run -d \ --name kibana \ -e ELASTICSEARCH_HOSTS=http://10.211.55.3:9200 \ -p 5601:5601 bae9450c8714
-
1.引入es依赖
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.13.1</version> </dependency> # 因为我的springboot版本是2.1.8 所以es版本默认6.8 这里需要改成7.13.1 <elasticsearch.version>7.13.1</elasticsearch.version>
-
2.配置es连接信息
@Configuration public class EsClientConfig { @Bean public RestHighLevelClient RestHighLevelClient() { RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("10.211.55.3", 9200, "http") )); return client; } }
-
controller层
@PostMapping(value = "/{spuId}/up") public R spuUp(@PathVariable("spuId") Long spuId) { spuInfoService.up(spuId); return R.ok(); }
-
sevice层
@Override public void up(Long spuId) { //1、查出当前spuId对应的所有sku信息,品牌的名字 List<SkuInfo> skuInfoEntities = skuInfoService.list(Wrappers.<SkuInfo>lambdaQuery().eq(SkuInfo::getSpuId,spuId)); // 4、查出当前sku的所有可以被用来检索的规格属性 List<ProductAttrValue> baseAttrs = productAttrValueService.baseAttrListForSpu(spuId); List<SkuEsModel.Attrs> attrsList = baseAttrs.stream().map(item->{ SkuEsModel.Attrs attrs = new SkuEsModel.Attrs(); BeanUtil.copyProperties(item,attrs); return attrs; }).collect(Collectors.toList()); // 获取skuId List<Long> skuIdList = skuInfoEntities.stream().map(SkuInfo::getSkuId).collect(Collectors.toList()); // 1、发送远程调用,库存系统查询是否有库存 Map<Long, Boolean> stockMap = new HashMap<>(); try { R skuHasStock = wareFeignService.hasStock(skuIdList); TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {}; stockMap = skuHasStock.getData(typeReference).stream() .collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock())); } catch (Exception e) { log.error("库存服务查询异常:原因{}",e); } //2、封装每个sku的信息 Map<Long, Boolean> finalStockMap = stockMap; List<SkuEsModel> collect = skuInfoEntities.stream().map(sku -> { //组装需要的数据 SkuEsModel esModel = new SkuEsModel(); esModel.setSkuPrice(sku.getPrice()); esModel.setSkuImg(sku.getSkuDefaultImg()); //设置库存信息 if (finalStockMap == null) { esModel.setHasStock(true); } else { esModel.setHasStock(finalStockMap.get(sku.getSkuId())); } // 2、热度评分。0 esModel.setHotScore(0L); //3、查询品牌和分类的名字信息 Brand brandEntity = brandService.getById(sku.getBrandId()); esModel.setBrandName(brandEntity.getName()); esModel.setBrandId(brandEntity.getBrandId()); esModel.setBrandImg(brandEntity.getLogo()); Category categoryEntity = categoryService.getById(sku.getCatalogId()); esModel.setCatalogId(categoryEntity.getCatId()); esModel.setCatalogName(categoryEntity.getName()); //设置检索属性 esModel.setAttrs(attrsList); BeanUtils.copyProperties(sku,esModel); return esModel; }).collect(Collectors.toList()); // 5、将数据发给es进行保存:gulimall-search R r = searchFeignService.productStatusUp(collect); if (r.getCode() == 0) { //远程调用成功 // 6、修改当前spu的状态 this.update(Wrappers.<SpuInfo>lambdaUpdate().eq(SpuInfo::getId,spuId) .set(SpuInfo::getPublishStatus,ProductConstant.ProductStatusEnum.SPU_UP.getCode())); } else { //远程调用失败 //TODO 7、重复调用?接口幂等性:重试机制 } }
-
es实体类
@Data public class SkuEsModel { private Long skuId; private Long spuId; private String skuTitle; private BigDecimal skuPrice; private String skuImg; private Long saleCount; private Boolean hasStock; private Long hotScore; private Long brandId; private Long catalogId; private String brandName; private String brandImg; private String catalogName; private List<Attrs> attrs; @Data public static class Attrs { private Long attrId; private String attrName; private String attrValue; } }
# es mapping 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" } } } } } }
-
es导入代码实现
@Override public boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException { BulkRequest bulkRequest = new BulkRequest(); for (SkuEsModel skuEsModel : skuEsModels) { bulkRequest.add(new IndexRequest(EsConstant.PRODUCT_INDEX).id(String.valueOf(skuEsModel.getSkuId())) .source(JSONObject.toJSONString(skuEsModel), XContentType.JSON)); } BulkResponse responses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); // 是否有添加失败的 true=有 boolean hasFailures = responses.hasFailures(); List<String> ids = Arrays.stream(responses.getItems()).map(BulkItemResponse::getId).collect(Collectors.toList()); log.info("商品上架完成:{}",ids); return hasFailures; }
-
此处为什么要用这种方式来获取返回值?
-
因为R继承了Map,如果使用泛型的话不会有返回值
-
所以在查到结果后,调用R的setdata方法把值放到map中,取值的时候调用getdata传对应泛型就能拿到数据
-