1. 导入商品数据
1.1. 搭建搜索工程
pom.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.atguigu</groupId>
<artifactId>gmall</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.atguigu</groupId>
<artifactId>gmall-search</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gmall-search</name>
<description>谷粒商城搜索系统</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>gmall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
bootstrap.yml:
spring:
application:
name: search-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
application.yml:
server:
port: 18086
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
zipkin:
base-url: http://localhost:9411
discovery-client-enabled: false
sender:
type: web
sleuth:
sampler:
probability: 1
elasticsearch:
rest:
uris: http://172.16.116.100:9200
feign:
sentinel:
enabled: true
logging:
level:
com.atguigu.gmall: debug
GmallSearchApplication.java引导类:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class GmallSearchApplication {
public static void main(String[] args) {
SpringApplication.run(GmallSearchApplication.class, args);
}
}
网关路由:
- id: search-route
uri: lb://search-service
predicates:
- Host=search.gmall.com
1.2. 构建es数据模型
接下来,我们需要商品数据导入索引库,便于用户搜索。
那么问题来了,我们有SPU和SKU,到底如何保存到索引库?
先看京东搜索,输入“小米”搜索:
可以看到每条记录就是一个sku,再来看看每条记录需要哪些字段:
直观能看到:sku的默认图片、sku的价格、标题、skuId
排序及筛选字段:综合、新品、销量、价格、库存(是否有货)等
聚合字段:品牌、分类、搜索规格参数(多个)
最终可以构建一个Goods对象:(注意属性名需要提前和前端约定好,不能随便改)
@Document(indexName = "goods", type = "info", shards = 3, replicas = 2)
@Data
public class Goods {
@Id
private Long skuId;
@Field(type = FieldType.Keyword, index = false)
private String pic;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title;
@Field(type = FieldType.Double)
private Double price;
@Field(type = FieldType.Long)
private Long sales; // 销量
@Field(type = FieldType.Boolean)
private Boolean store; // 是否有货
@Field(type = FieldType.Date)
private Date createTime; // 新品
@Field(type = FieldType.Long)
private Long brandId;
@Field(type = FieldType.Keyword)
private String brandName;
@Field(type = FieldType.Long)
private Long categoryId;
@Field(type = FieldType.Keyword)
private String categoryName;
@Field(type = FieldType.Nested)
private List<SearchAttrValue> attrs;
}
搜索规格参数:SearchAttrValue
@Data
public class SearchAttrValue {
@Field(type = FieldType.Long)
private Long attrId;
@Field(type = FieldType.Keyword)
private String attrName;
@Field(type = FieldType.Keyword)
private String attrValue;
}
“type”: “nested”
嵌套结构,防止数据扁平化问题。
参照官方文档:https://www.elastic.co/guide/cn/elasticsearch/guide/current/nested-objects.html
1.3. 批量导入
1.3.1. 数据接口
索引库中的数据来自于数据库,我们不能直接去查询商品的数据库,因为真实开发中,每个微服务都是相互独立的,包括数据库也是一样。所以我们只能调用商品微服务提供的接口服务。
先思考我们需要的数据:
- 分页查询已上架的SPU信息
- 根据SpuId查询对应的SKU信息(接口已写好)
- 根据分类id查询商品分类(逆向工程已自动生成)
- 根据品牌id查询品牌(逆向工程已自动生成)
- 根据skuid查询库存(gmall-wms中接口已写好)
- 根据spuId查询检索规格参数及值
- 根据skuId查询检索规格参数及值
大部分接口之前已经编写完成,接下来开发接口:
1.3.1.1. 分页查询已上架SPU
在gmall-pms的SpuController中添加方法:
@PostMapping("page")
public ResponseVo<List<SpuEntity>> querySpusByPage(@RequestBody PageParamVo pageParamVo){
PageResultVo page = spuService.queryPage(pageParamVo);
List<SpuEntity> list = (List<SpuEntity>)page.getList();
return ResponseVo.ok(list);
}
1.3.1.2. 根据spuId查询检索属性及值
在gmall-pms的SpuAttrValueController中添加方法:
@ApiOperation("根据spuId查询检索属性及值")
@GetMapping("spu/{spuId}")
public ResponseVo<List<SpuAttrValueEntity>> querySearchAttrValueBySpuId(@PathVariable("spuId")Long spuId){
List<SpuAttrValueEntity> attrValueEntities = spuAttrValueService.querySearchAttrValueBySpuId(spuId);
return ResponseVo.ok(attrValueEntities);
}
在SpuAttrValueService中添加接口方法:
List<SpuAttrValueEntity> querySearchAttrValueBySpuId(Long spuId);
在实现类SpuAttrValueServiceImpl中添加实现方法:
@Autowired
private SpuAttrValueMapper spuAttrValueMapper;
@Override
public List<SpuAttrValueEntity> querySearchAttrValueBySpuId(Long spuId) {
return this.spuAttrValueMapper.querySearchAttrValueBySpuId(spuId);
}
在SpuAttrValueMapper接口中添加接口方法:
@Mapper
public interface SpuAttrValueMapper extends BaseMapper<SpuAttrValueEntity> {
List<SpuAttrValueEntity> querySearchAttrValueBySpuId(Long spuId);
}
在SpuAttrValueMapper对应的映射文件中添加配置:
<select id="querySearchAttrValueBySpuId" resultType="SpuAttrValueEntity">
select a.id,a.attr_id,a.attr_name,a.attr_value,a.spu_id
from pms_spu_attr_value a INNER JOIN pms_attr b on a.attr_id=b.id
where a.spu_id=#{spuId} and b.search_type=1
</select>
1.3.1.3. 根据skuId查询检索属性及值
在gmall-pms的SkuAttrValueController中添加方法:
@ApiOperation("根据spuId查询检索属性及值")
@GetMapping("sku/{skuId}")
public ResponseVo<List<SkuAttrValueEntity>> querySearchAttrValueBySkuId(@PathVariable("skuId")Long skuId){
List<SkuAttrValueEntity> attrValueEntities = skuAttrValueService.querySearchAttrValueBySkuId(skuId);
return ResponseVo.ok(attrValueEntities);
}
在SkuAttrValueService中添加接口方法:
List<SkuAttrValueEntity> querySearchAttrValueBySkuId(Long skuId);
在实现类SkuAttrValueServiceImpl中添加实现方法: