使用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、重复调用?接口幂等性:重试机制
}
}