使用ElasticSearch的准备工作
一、在Linux上安装ElasticSearch
1、docker下载elasticSearch和kibana的镜像
docker pull elasticsearch:7.4.2 存储和检索数据 docker pull kibana:7.4.2 可视化检索数据
2、创建目录
mkdir -p /mydata/elasticsearch/config mkdir -p /mydata/elasticsearch/data echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
3、启动并挂载Elasticsearch
chmod -R 777 /mydata/elasticsearch/ 保证权限 docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \ -e "discovery.type=single-node" \ -e ES_JAVA_OPTS="-Xms64m -Xmx1024m" \ -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \ -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \ -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \ -d elasticsearch:7.4.2 特别注意: -e ES_JAVA_OPTS="-Xms64m -Xmx256m" \ 测试环境下,设置 ES 的初始内存和最大内存,否则导 致过大启动不了 ES
4、启动kibana
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://虚拟机Linux的ip地址:9200 -p 5601:5601 \ -d kibana:7.4.2 http://192.168.56.10:9200 一定改为自己虚拟机的地址
二、整合SpringBoot
1、导入Elasticsearch客户端的依赖
注意这里的<elasticsearch.version>7.4.2</elasticsearch.version>要写成和自己Linux的elasticsearch版本,如果不写这句那就用的是SpringBoot默认的版本,然后上面的linux中的elasticSearch和kibana版本最好保持一致性
<properties> <java.version>1.8</java.version> <elasticsearch.version>7.4.2</elasticsearch.version> <spring-cloud.version>2021.0.0</spring-cloud.version> </properties> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.4.2</version> </dependency>
2、ElasticSearch的配置类
package com.saodai.saodaimall.search.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * ElasticSearch的配置类 **/ @Configuration public class SaodaimallElasticSearchConfig { 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; builder = RestClient.builder(new HttpHost("192.168.241.128", 9200, "http")); RestHighLevelClient client = new RestHighLevelClient(builder); return client; } }
本商城项目哪里用到了ElasticSearch
商品服务
商品服务的商品上架功能就是把上架的商品的所有信息存到ElasticSearch
1、在Vscode中发送上架请求
2、商品服务的SpuInfoController来处理请求/{spuId}/up
/** * 商品维护的spu管理的上架功能 */ @PostMapping("/{spuId}/up") public R spuUp(@PathVariable("spuId") Long spuId){ spuInfoService.up(spuId); return R.ok(); }
分流程:
(1)查找出spuId对应的所有sku对象
(2)查出当前sku的所有可以被用来检索的规格属性
//商品维护的spu管理的上架功能 @Override public void up(Long spuId) { //查找出spuId对应的所有sku对象 List<SkuInfoEntity> skuInfoEntities = skuInfoService.getSkusBySpuId(spuId); //查出当前sku的所有可以被用来检索的规格属性 List<ProductAttrValueEntity> productAttrValueEntities = attrValueService.baseAttrlistforspu(spuId); List<Long> attrIds = productAttrValueEntities.stream().map(attr -> { return attr.getAttrId(); }).collect(Collectors.toList()); /* //在批量规格参数attrids找到具有检索属性的规格参数的id集 List<Long> sarchAttrIds = attrService.selectSearchAttrsIds(attrIds);*/ Set<Long> idSet = new HashSet<>(attrIds); //找到符合要求的数据 List<SkuEsModel.Attrs> attrsList = productAttrValueEntities.stream().filter(item -> { //下面返回的是List<ProductAttrValueEntity> return idSet.contains(item.getAttrId()); }).map(item -> { //把上面过滤的List<ProductAttrValueEntity>对象转为List<SkuEsModel.Attrs> SkuEsModel.Attrs attrs = new SkuEsModel.Attrs(); BeanUtils.copyProperties(item, attrs); return attrs; }).collect(Collectors.toList()); //发送远程调用,库存服务查询是否有库存 //获取skuIds集合 List<Long> skuIdList = skuInfoEntities.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList()); Map<Long, Boolean> stockMap =null; //进行异常处理(因为远程调用可能因为网络问题导致失败,进行异常处理就不会影响下面的代码运行) try{ //远程调用仓库接口 R r = wareFeignService.getSkusHasStock(skuIdList); TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {}; //获取返回R中的数据并封装成map<skuId,HasStock> stockMap = r.getData(typeReference).stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock())); } catch (Exception e) { log.error("库存服务查询异常:原因{}",e); } Map<Long, Boolean> finalStockMap =stockMap; List<SkuEsModel> collect = skuInfoEntities.stream().map(skuInfoEntity -> { //组装需要的数据 SkuEsModel skuEsModel = new SkuEsModel(); BeanUtils.copyProperties(skuInfoEntity,skuEsModel); skuEsModel.setSkuPrice(skuInfoEntity.getPrice()); skuEsModel.setSkuImg(skuInfoEntity.getSkuDefaultImg()); //hasStock,hotScore //设置库存信息 if (finalStockMap == null) { skuEsModel.setHasStock(true); } else { skuEsModel.setHasStock(finalStockMap.get(skuInfoEntity.getSkuId())); } //热度评分 //查询品牌和分类的名称信息 BrandEntity brandEntity = brandService.getById(skuInfoEntity.getBrandId()); skuEsModel.setBrandName(brandEntity.getName()); skuEsModel.setBrandId(brandEntity.getBrandId()); skuEsModel.setBrandImg(brandEntity.getLogo()); CategoryEntity categoryEntity = categoryService.getById(skuInfoEntity.getCatalogId()); skuEsModel.setCatalogId(categoryEntity.getCatId()); skuEsModel.setCatalogName(categoryEntity.getName()); //设置可以检索的规格参数 skuEsModel.setAttrs(attrsList); return skuEsModel; }).collect(Collectors.toList()); //TODO 5、远程调用将数据发给es进行保存:saodaimall-search R r = searchFeginService.productStatusUp(collect); if (r.getCode() == 0) { //远程调用成功 //TODO 6、修改当前spu的状态 System.out.println("远程调成功!"); this.baseMapper.updaSpuStatus(spuId, ProductConstant.ProductStatusEnum.SPU_UP.getCode()); } else { //远程调用失败 //TODO 7、重复调用?接口幂等性:重试机制 } }