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
//标示映射到Elasticsearch文档上的领域对象
public @interface Document {
//索引库名次,mysql中数据库的概念
String indexName();
//文档类型,mysql中表的概念
String type() default "";
//默认分片数
short shards() default 5;
//默认副本数量
short replicas() default 1;
}
@Id
//表示是文档的id,文档可以认为是mysql中表行的概念
public @interface Id {
}
@Field
public @interface Field {
//文档中字段的类型
FieldType type() default FieldType.Auto;
//是否建立倒排索引
boolean index() default true;
//是否进行存储
boolean store() default false;
//分词器名次
String analyzer() default "";
}
//为文档自动指定元数据类型
public enum FieldType {
Text,//会进行分词并建了索引的字符类型
Integer,
Long,
Date,
Float,
Double,
Boolean,
Object,
Auto,//自动判断字段类型
Nested,//嵌套对象类型
Ip,
Attachment,
Keyword//不会进行分词建立索引的类型
}
Sping Data方式的数据操作
继承ElasticsearchRepository接口可以获得常用的数据操作方法
可以使用衍生查询
在接口中直接指定查询方法名称便可查询,无需进行实现,如商品表中有商品名称、标题和关键字,直接定义以下查询,就可以对这三个字段进行全文搜索。
/**
* 搜索查询
*
* @param name 商品名称
* @param subTitle 商品标题
* @param keywords 商品关键字
* @param page 分页信息
* @return
*/
Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);
在idea中直接会提示对应字段
使用@Query注解可以用Elasticsearch的DSL语句进行查询
@Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}")
Page<EsProduct> findByName(String name,Pageable pageable);
使用表说明
-
pms_product
:商品信息表 -
pms_product_attribute
:商品属性参数表 -
pms_product_attribute_value
:存储产品参数值的表
整合Elasticsearch实现商品搜索
在pom.xml中添加相关依赖
<!--Elasticsearch相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch<artifactId>
</dependency>
修改SpringBoot配置文件
修改application.yml文件,在spring节点下添加Elasticsearch相关配置。
data:
elasticsearch:
repositories:
enabled: true
cluster-nodes: 127.0.0.1:9300 # es的连接地址及端口号
cluster-name: elasticsearch # es集群的名称
添加商品文档对象EsProduct
不需要中文分词的字段设置成@Field(type = FieldType.Keyword)类型,需要中文分词的设置成@Field(analyzer = "ik_max_word",type = FieldType.Text)类型。
package org.yxin.elasticsearch.document;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
/**
* 搜索中的商品信息
*/
@Document(indexName = "pms", type = "product",shards = 1,replicas = 0)
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EsProduct implements Serializable {
private static final long serialVersionUID = -1L;
@Id
private Long id;
@Field(type = FieldType.Keyword)
private String productSn;
private Long brandId;
@Field(type = FieldType.Keyword)
private String brandName;
private Long productCategoryId;
@Field(type = FieldType.Keyword)
private String productCategoryName;
private String pic;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String name;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String subTitle;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String keywords;
private BigDecimal price;
private Integer sale;
private Integer newStatus;
private Integer recommandStatus;
private Integer stock;
private Integer promotionType;
private Integer sort;
@Field(type =FieldType.Nested)
private List<EsProductAttributeValue> attrValueList;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProductSn() {
return productSn;
}
public void setProductSn(String productSn) {
this.productSn = productSn;
}
public Long getBrandId() {
return brandId;
}
public void setBrandId(Long brandId) {
this.brandId = brandId;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public Long getProductCategoryId() {
return productCategoryId;
}
public void setProductCategoryId(Long productCategoryId) {
this.productCategoryId = productCategoryId;
}
public String getProductCategoryName() {
return productCategoryName;
}
public void setProductCategoryName(String productCategoryName) {
this.productCategoryName = productCategoryName;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSubTitle() {
return subTitle;
}
public void setSubTitle(String subTitle) {
this.subTitle = subTitle;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public Integer getSale() {
return sale;
}
public void setSale(Integer sale) {
this.sale = sale;
}
public Integer getNewStatus() {
return newStatus;
}
public void setNewStatus(Integer newStatus) {
this.newStatus = newStatus;
}
public Integer getRecommandStatus() {
return recommandStatus;
}
public void setRecommandStatus(Integer recommandStatus) {
this.recommandStatus = recommandStatus;
}
public Integer getStock() {
return stock;
}
public void setStock(Integer stock) {
this.stock = stock;
}
public Integer getPromotionType() {
return promotionType;
}
public void setPromotionType(Integer promotionType) {
this.promotionType = promotionType;
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
public List<EsProductAttributeValue> getAttrValueList() {
return attrValueList;
}
public void setAttrValueList(List<EsProductAttributeValue> attrValueList) {
this.attrValueList = attrValueList;
}
public String getKeywords() {
return keywords;
}
public void setKeywords(String keywords) {
this.keywords = keywords;
}
}
添加EsProductRepository接口用于操作Elasticsearch
继承ElasticsearchRepository接口,这样就拥有了一些基本的Elasticsearch数据操作方法,同时定义了一个衍生查询方法。
package org.yxin.elasticsearch.repository;
import com.github.pagehelper.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.yxin.elasticsearch.document.EsProduct;
/**
* 商品ES操作类
*/
public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> {
/**
* 搜索查询
*
* @param name 商品名称
* @param subTitle 商品标题
* @param keywords 商品关键字
* @param page 分页信息
* @return
*/
Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);
Page<EsProduct> findByNameOrSubTitle(String name, String subTitle, Pageable page);
Page<EsProduct> findById(Long id, Pageable page);
@Override
boolean existsById(Long aLong);
Page<EsProduct> findByName(String name, Pageable page);
}
添加EsProductService类
package org.yxin.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.yxin.elasticsearch.document.EsProduct;
import org.yxin.elasticsearch.repository.EsProductRepository;
import org.yxin.entity.PmsProduct;
import org.yxin.mapper.PmsProductMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 商品信息 服务实现类
* </p>
*
* @author yxin
* @since 2024-01-28
*/
@Service
@RequiredArgsConstructor
public class PmsProductService extends ServiceImpl<PmsProductMapper, PmsProduct> {
private static final Logger LOGGER = LoggerFactory.getLogger(PmsProductService.class);
private final PmsProductMapper productDao;
private final EsProductRepository productRepository;
public int importAll() {
LambdaQueryWrapper<PmsProduct> wrappers = Wrappers.lambdaQuery();
List<EsProduct> esProductList = productDao.selectList(wrappers).stream().map(this::toEsProduct)
.collect(Collectors.toList());
Iterable<EsProduct> esProductIterable = productRepository.saveAll(esProductList);
Iterator<EsProduct> iterator = esProductIterable.iterator();
int result = 0;
while (iterator.hasNext()) {
result++;
iterator.next();
}
return result;
}
public void delete(Long id) {
productRepository.deleteById(id);
}
public EsProduct create(Long id) {
EsProduct result = null;
LambdaQueryWrapper<EsProduct> wrappers = Wrappers.lambdaQuery();
wrappers.eq(EsProduct::getId,id);
PmsProduct pmsProduct = productDao.selectById(wrappers);
EsProduct esProduct = new EsProduct();
BeanUtils.copyProperties(pmsProduct,esProduct);
result = productRepository.save(esProduct);
return result;
}
public void delete(List<Long> ids) {
if (!CollectionUtils.isEmpty(ids)) {
List<EsProduct> esProductList = new ArrayList<>();
for (Long id : ids) {
EsProduct esProduct = new EsProduct();
esProduct.setId(id);
esProductList.add(esProduct);
}
productRepository.deleteAll(esProductList);
}
}
public Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize) {
Pageable pageable = PageRequest.of(pageNum, pageSize);
return productRepository.findByNameOrSubTitleOrKeywords(keyword, keyword, keyword, pageable);
}
public EsProduct toEsProduct(PmsProduct duct){
return EsProduct.builder().productSn(duct.getProductSn())
.brandId(duct.getBrandId())
.brandName(duct.getBrandName())
.id(duct.getId())
.keywords(duct.getKeywords())
.name(duct.getName())
.pic(duct.getPic())
.productCategoryId(duct.getProductCategoryId())
.productCategoryName(duct.getProductCategoryName())
.newStatus(duct.getNewStatus())
.price(duct.getPrice())
.promotionType(duct.getPromotionType())
.recommandStatus(duct.getRecommandStatus())
.sale(duct.getSale())
.sort(duct.getSort())
.stock(duct.getStock())
.subTitle(duct.getSubTitle())
.productSn(duct.getProductSn())
.build();
}
}
进行接口测试
将数据库中数据导入到Elasticsearch
进行商品搜索
文章来源:https://www.toymoban.com/news/detail-835659.html
文章来源地址https://www.toymoban.com/news/detail-835659.html
到了这里,关于整合Elasticsearch实现商品搜索的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!