当前位置:   article > 正文

整合Elasticsearch实现商品搜索_es 分词器 商品搜索

es 分词器 商品搜索

Elasticsearch

Elasticsearch 是一个分布式、可扩展、实时的搜索与数据分析引擎。 它能从项目一开始就赋予你的数据以搜索、分析和探索的能力,可用于实现全文搜索和实时数据统计。

 Elasticsearch的安装和使用

下载Elasticsearch

Elasticsearch6.2.2的zip包,并解压到指定目录,下载地址:Elasticsearch 6.2.2 | Elastic

安装中文分词插件

在elasticsearch-6.2.2\bin目录下执行以下命令:elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.2/elasticsearch-analysis-ik-6.2.2.zip

 运行bin目录下的elasticsearch.bat启动Elasticsearch

 下载Kibana

下载Kibana,作为访问Elasticsearch的客户端,请下载6.2.2版本的zip包,并解压到指定目录,下载地址:https://artifacts.elastic.co/downloads/kibana/kibana-6.2.2-windows-x86_64.zip

运行bin目录下的kibana.bat,启动Kibana的用户界面

访问Kibana

访问http://localhost:5601open in new window 即可打开Kibana的用户界面

Spring Data Elasticsearch

Spring Data Elasticsearch是Spring提供的一种以Spring Data风格来操作数据存储的方式,它可以避免编写大量的样板代码。

常用注解

@Document

  1. //标示映射到Elasticsearch文档上的领域对象
  2. public @interface Document {
  3. //索引库名次,mysql中数据库的概念
  4. String indexName();
  5. //文档类型,mysql中表的概念
  6. String type() default "";
  7. //默认分片数
  8. short shards() default 5;
  9. //默认副本数量
  10. short replicas() default 1;
  11. }

@Id

  1. //表示是文档的id,文档可以认为是mysql中表行的概念
  2. public @interface Id {
  3. }

@Field

  1. public @interface Field {
  2. //文档中字段的类型
  3. FieldType type() default FieldType.Auto;
  4. //是否建立倒排索引
  5. boolean index() default true;
  6. //是否进行存储
  7. boolean store() default false;
  8. //分词器名次
  9. String analyzer() default "";
  10. }

  1. //为文档自动指定元数据类型
  2. public enum FieldType {
  3. Text,//会进行分词并建了索引的字符类型
  4. Integer,
  5. Long,
  6. Date,
  7. Float,
  8. Double,
  9. Boolean,
  10. Object,
  11. Auto,//自动判断字段类型
  12. Nested,//嵌套对象类型
  13. Ip,
  14. Attachment,
  15. Keyword//不会进行分词建立索引的类型
  16. }


Sping Data方式的数据操作


继承ElasticsearchRepository接口可以获得常用的数据操作方法


可以使用衍生查询

在接口中直接指定查询方法名称便可查询,无需进行实现,如商品表中有商品名称、标题和关键字,直接定义以下查询,就可以对这三个字段进行全文搜索。

  1. /**
  2. * 搜索查询
  3. *
  4. * @param name 商品名称
  5. * @param subTitle 商品标题
  6. * @param keywords 商品关键字
  7. * @param page 分页信息
  8. * @return
  9. */
  10. Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);

在idea中直接会提示对应字段 


使用@Query注解可以用Elasticsearch的DSL语句进行查询

  1. @Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}")
  2. Page<EsProduct> findByName(String name,Pageable pageable);

使用表说明

  • pms_product:商品信息表
  • pms_product_attribute:商品属性参数表
  • pms_product_attribute_value:存储产品参数值的表

整合Elasticsearch实现商品搜索 

在pom.xml中添加相关依赖

  1. <!--Elasticsearch相关依赖-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-data-elasticsearch<artifactId>
  5. </dependency>

修改SpringBoot配置文件

修改application.yml文件,在spring节点下添加Elasticsearch相关配置。

  1. data:
  2. elasticsearch:
  3. repositories:
  4. enabled: true
  5. cluster-nodes: 127.0.0.1:9300 # es的连接地址及端口号
  6. cluster-name: elasticsearch # es集群的名称

添加商品文档对象EsProduct

不需要中文分词的字段设置成@Field(type = FieldType.Keyword)类型,需要中文分词的设置成@Field(analyzer = "ik_max_word",type = FieldType.Text)类型。

  1. package org.yxin.elasticsearch.document;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Builder;
  4. import lombok.NoArgsConstructor;
  5. import org.springframework.data.annotation.Id;
  6. import org.springframework.data.elasticsearch.annotations.Document;
  7. import org.springframework.data.elasticsearch.annotations.Field;
  8. import org.springframework.data.elasticsearch.annotations.FieldType;
  9. import java.io.Serializable;
  10. import java.math.BigDecimal;
  11. import java.util.List;
  12. /**
  13. * 搜索中的商品信息
  14. */
  15. @Document(indexName = "pms", type = "product",shards = 1,replicas = 0)
  16. @Builder
  17. @AllArgsConstructor
  18. @NoArgsConstructor
  19. public class EsProduct implements Serializable {
  20. private static final long serialVersionUID = -1L;
  21. @Id
  22. private Long id;
  23. @Field(type = FieldType.Keyword)
  24. private String productSn;
  25. private Long brandId;
  26. @Field(type = FieldType.Keyword)
  27. private String brandName;
  28. private Long productCategoryId;
  29. @Field(type = FieldType.Keyword)
  30. private String productCategoryName;
  31. private String pic;
  32. @Field(analyzer = "ik_max_word",type = FieldType.Text)
  33. private String name;
  34. @Field(analyzer = "ik_max_word",type = FieldType.Text)
  35. private String subTitle;
  36. @Field(analyzer = "ik_max_word",type = FieldType.Text)
  37. private String keywords;
  38. private BigDecimal price;
  39. private Integer sale;
  40. private Integer newStatus;
  41. private Integer recommandStatus;
  42. private Integer stock;
  43. private Integer promotionType;
  44. private Integer sort;
  45. @Field(type =FieldType.Nested)
  46. private List<EsProductAttributeValue> attrValueList;
  47. public Long getId() {
  48. return id;
  49. }
  50. public void setId(Long id) {
  51. this.id = id;
  52. }
  53. public String getProductSn() {
  54. return productSn;
  55. }
  56. public void setProductSn(String productSn) {
  57. this.productSn = productSn;
  58. }
  59. public Long getBrandId() {
  60. return brandId;
  61. }
  62. public void setBrandId(Long brandId) {
  63. this.brandId = brandId;
  64. }
  65. public String getBrandName() {
  66. return brandName;
  67. }
  68. public void setBrandName(String brandName) {
  69. this.brandName = brandName;
  70. }
  71. public Long getProductCategoryId() {
  72. return productCategoryId;
  73. }
  74. public void setProductCategoryId(Long productCategoryId) {
  75. this.productCategoryId = productCategoryId;
  76. }
  77. public String getProductCategoryName() {
  78. return productCategoryName;
  79. }
  80. public void setProductCategoryName(String productCategoryName) {
  81. this.productCategoryName = productCategoryName;
  82. }
  83. public String getPic() {
  84. return pic;
  85. }
  86. public void setPic(String pic) {
  87. this.pic = pic;
  88. }
  89. public String getName() {
  90. return name;
  91. }
  92. public void setName(String name) {
  93. this.name = name;
  94. }
  95. public String getSubTitle() {
  96. return subTitle;
  97. }
  98. public void setSubTitle(String subTitle) {
  99. this.subTitle = subTitle;
  100. }
  101. public BigDecimal getPrice() {
  102. return price;
  103. }
  104. public void setPrice(BigDecimal price) {
  105. this.price = price;
  106. }
  107. public Integer getSale() {
  108. return sale;
  109. }
  110. public void setSale(Integer sale) {
  111. this.sale = sale;
  112. }
  113. public Integer getNewStatus() {
  114. return newStatus;
  115. }
  116. public void setNewStatus(Integer newStatus) {
  117. this.newStatus = newStatus;
  118. }
  119. public Integer getRecommandStatus() {
  120. return recommandStatus;
  121. }
  122. public void setRecommandStatus(Integer recommandStatus) {
  123. this.recommandStatus = recommandStatus;
  124. }
  125. public Integer getStock() {
  126. return stock;
  127. }
  128. public void setStock(Integer stock) {
  129. this.stock = stock;
  130. }
  131. public Integer getPromotionType() {
  132. return promotionType;
  133. }
  134. public void setPromotionType(Integer promotionType) {
  135. this.promotionType = promotionType;
  136. }
  137. public Integer getSort() {
  138. return sort;
  139. }
  140. public void setSort(Integer sort) {
  141. this.sort = sort;
  142. }
  143. public List<EsProductAttributeValue> getAttrValueList() {
  144. return attrValueList;
  145. }
  146. public void setAttrValueList(List<EsProductAttributeValue> attrValueList) {
  147. this.attrValueList = attrValueList;
  148. }
  149. public String getKeywords() {
  150. return keywords;
  151. }
  152. public void setKeywords(String keywords) {
  153. this.keywords = keywords;
  154. }
  155. }

添加EsProductRepository接口用于操作Elasticsearch

继承ElasticsearchRepository接口,这样就拥有了一些基本的Elasticsearch数据操作方法,同时定义了一个衍生查询方法。

  1. package org.yxin.elasticsearch.repository;
  2. import com.github.pagehelper.Page;
  3. import org.springframework.data.domain.Pageable;
  4. import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
  5. import org.yxin.elasticsearch.document.EsProduct;
  6. /**
  7. * 商品ES操作类
  8. */
  9. public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> {
  10. /**
  11. * 搜索查询
  12. *
  13. * @param name 商品名称
  14. * @param subTitle 商品标题
  15. * @param keywords 商品关键字
  16. * @param page 分页信息
  17. * @return
  18. */
  19. Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);
  20. Page<EsProduct> findByNameOrSubTitle(String name, String subTitle, Pageable page);
  21. Page<EsProduct> findById(Long id, Pageable page);
  22. @Override
  23. boolean existsById(Long aLong);
  24. Page<EsProduct> findByName(String name, Pageable page);
  25. }

 添加EsProductService类

  1. package org.yxin.service;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
  4. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  5. import com.github.pagehelper.Page;
  6. import lombok.RequiredArgsConstructor;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9. import org.springframework.beans.BeanUtils;
  10. import org.springframework.data.domain.PageRequest;
  11. import org.springframework.data.domain.Pageable;
  12. import org.yxin.elasticsearch.document.EsProduct;
  13. import org.yxin.elasticsearch.repository.EsProductRepository;
  14. import org.yxin.entity.PmsProduct;
  15. import org.yxin.mapper.PmsProductMapper;
  16. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  17. import org.springframework.stereotype.Service;
  18. import java.util.ArrayList;
  19. import java.util.Iterator;
  20. import java.util.List;
  21. import java.util.stream.Collectors;
  22. /**
  23. * <p>
  24. * 商品信息 服务实现类
  25. * </p>
  26. *
  27. * @author yxin
  28. * @since 2024-01-28
  29. */
  30. @Service
  31. @RequiredArgsConstructor
  32. public class PmsProductService extends ServiceImpl<PmsProductMapper, PmsProduct> {
  33. private static final Logger LOGGER = LoggerFactory.getLogger(PmsProductService.class);
  34. private final PmsProductMapper productDao;
  35. private final EsProductRepository productRepository;
  36. public int importAll() {
  37. LambdaQueryWrapper<PmsProduct> wrappers = Wrappers.lambdaQuery();
  38. List<EsProduct> esProductList = productDao.selectList(wrappers).stream().map(this::toEsProduct)
  39. .collect(Collectors.toList());
  40. Iterable<EsProduct> esProductIterable = productRepository.saveAll(esProductList);
  41. Iterator<EsProduct> iterator = esProductIterable.iterator();
  42. int result = 0;
  43. while (iterator.hasNext()) {
  44. result++;
  45. iterator.next();
  46. }
  47. return result;
  48. }
  49. public void delete(Long id) {
  50. productRepository.deleteById(id);
  51. }
  52. public EsProduct create(Long id) {
  53. EsProduct result = null;
  54. LambdaQueryWrapper<EsProduct> wrappers = Wrappers.lambdaQuery();
  55. wrappers.eq(EsProduct::getId,id);
  56. PmsProduct pmsProduct = productDao.selectById(wrappers);
  57. EsProduct esProduct = new EsProduct();
  58. BeanUtils.copyProperties(pmsProduct,esProduct);
  59. result = productRepository.save(esProduct);
  60. return result;
  61. }
  62. public void delete(List<Long> ids) {
  63. if (!CollectionUtils.isEmpty(ids)) {
  64. List<EsProduct> esProductList = new ArrayList<>();
  65. for (Long id : ids) {
  66. EsProduct esProduct = new EsProduct();
  67. esProduct.setId(id);
  68. esProductList.add(esProduct);
  69. }
  70. productRepository.deleteAll(esProductList);
  71. }
  72. }
  73. public Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize) {
  74. Pageable pageable = PageRequest.of(pageNum, pageSize);
  75. return productRepository.findByNameOrSubTitleOrKeywords(keyword, keyword, keyword, pageable);
  76. }
  77. public EsProduct toEsProduct(PmsProduct duct){
  78. return EsProduct.builder().productSn(duct.getProductSn())
  79. .brandId(duct.getBrandId())
  80. .brandName(duct.getBrandName())
  81. .id(duct.getId())
  82. .keywords(duct.getKeywords())
  83. .name(duct.getName())
  84. .pic(duct.getPic())
  85. .productCategoryId(duct.getProductCategoryId())
  86. .productCategoryName(duct.getProductCategoryName())
  87. .newStatus(duct.getNewStatus())
  88. .price(duct.getPrice())
  89. .promotionType(duct.getPromotionType())
  90. .recommandStatus(duct.getRecommandStatus())
  91. .sale(duct.getSale())
  92. .sort(duct.getSort())
  93. .stock(duct.getStock())
  94. .subTitle(duct.getSubTitle())
  95. .productSn(duct.getProductSn())
  96. .build();
  97. }
  98. }

 进行接口测试

将数据库中数据导入到Elasticsearch

 

 

 进行商品搜索

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/973020
推荐阅读
相关标签
  

闽ICP备14008679号