赞
踩
目录
1.-问题:Elasticsearch 与Spring Data与Lucene 等存在版本冲突
2.-解决方法:添加指定版本的lucene依赖而不使用默认的Elasticsearch自带的lucene
(具有指导价值,但版本对应存在很高容错率)
1.Elasticsearch 7.6.2 SpringBoot2.5.6 (实现)
2.Elasticsearch 7.17.3 SpringBoot2.7.5 (实现)
参考网址:https://blog.csdn.net/weixin_42633131/article/details/82902812
pom.xml
- <!--ES核心依赖-->
-
- <dependency>
-
- <groupId>org.springframework.boot</groupId>
-
- <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
-
- </dependency>
-
-
-
- <!--配置客户端需要的依赖,不存在添加,存在不添加-->
-
- <dependency>
-
- <groupId>org.springframework.boot</groupId>
-
- <artifactId>spring-boot-starter-web</artifactId>
-
- </dependency>
-
- <!--若不需要Tomcat,则只需要依赖spring-web-->
-
- <!--<dependency>
-
- <groupId>org.springframework</groupId>
-
- <artifactId>spring-web</artifactId>
-
- </dependency>-->
application.yml
- # yml配置elasticsearch客户端地址(可配置项有限)
-
- spring:
-
- elasticsearch:
-
- uris: http://127.0.0.1:9200 # elasticsearch 连接地址
-
- #username: elastic # 用户名
-
- #password: 123456 # 密码
-
- connection-timeout: 10s # 连接超时时间(默认1s)
-
- socket-timeout: 30s # 数据读取超时时间(默认30s)
- package com.nengyy.rest_server.elasticsearch.entity;
-
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import lombok.experimental.Accessors;
- 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.Objects;
- @Data
- @Accessors(chain = true) // 支持链式set赋值功能
- @AllArgsConstructor // 自动生成包含全部参数的构造方法
- @NoArgsConstructor // 自动生成无参构造方法
- // @Document是SpringDataES标记实体类的注解
- // indexName指定关联的索引名称,运行时如果items索引不存在,SpringData会自动将它创建出来
- @Document(indexName = "items")
- public class ItemEfm implements Serializable {
- // SpringData标记当前属性为ES的主键
- @Id //ES本条数据ID(只能为long类型等转化为的String类型,不能出现数字之外的字母或汉字)(暂未研究解决方法)
- private Long id; //想用ES自带增删改查方法,此id需要为Long类型
- // SpringData标记title属性是text类型支持分词的,以及分词器
- @Field(type = FieldType.Keyword)
- private String GoodsId;
- @Field(type = FieldType.Text, //生成索引时使用 ik_max_word,在搜索时用ik_smart
- analyzer = "ik_max_word", //最细粒度拆分-->(字会重复被使用)(生成索引时,进行分词使用)
- searchAnalyzer = "ik_smart") //最粗粒度拆分-->智能拆分(字不会被重复使用)(搜索时,对搜索词进行分词)
- private String title; // 商品描述
- // Keyword类型是不需要分词的字符串类型
- @Field(type = FieldType.Keyword)
- private String category; // 商品分类
- @Field(type = FieldType.Keyword)
- private String brand; // 品牌(商品描述备用字段)(此字段用来做全称查询,用来补充分词查询的不足)
- @Field(type = FieldType.Keyword)
- private String price; // 价格
- @Field(type = FieldType.Keyword)
- private String origPrice; // 原价
- // 图片地址不会成为搜索条件,所以设置index = false
- // 这样ES就不会为它创建索引库了,能够节省空间
- @Field(type = FieldType.Keyword,index = false)
- private String imgPath; // 图片地址
-
- // images/1a123s-as4td-asdsa-jasbdjff.png
- @Field(type = FieldType.Keyword)
- private String intertestNum;//关注人数
-
-
- //重写equals,用于contains判断,非必要不会用到
- @Override
- public boolean equals(Object obj) {
- if (this == obj) return true;
- if (obj == null || getClass() != obj.getClass()) return false;
- ItemEfm other = (ItemEfm) obj;
- return Objects.equals(GoodsId, other.GoodsId) &&
- Objects.equals(title, other.title) &&
- Objects.equals(price, other.price) &&
- Objects.equals(origPrice, other.origPrice) &&
- Objects.equals(imgPath, other.imgPath) &&
- Objects.equals(intertestNum, other.intertestNum);
- }
- @Override
- public int hashCode() {
- return Objects.hash(GoodsId, title, price, origPrice, imgPath, intertestNum);
- }
- }
解析:持久层ItemRepository 接口继承extends ElasticsearchRepository 后,可以实现和MybatisPlus等同的作用
- package com.nengyy.rest_server.elasticsearch.repository;
-
- import com.nengyy.rest_server.elasticsearch.entity.ItemEfm;
- import org.springframework.data.domain.Page;
- import org.springframework.data.domain.Pageable;
- import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
- import org.springframework.stereotype.Repository;
- import java.util.List;
- // Spring 家族持久层命名规范为repository
- @Repository
- public interface ItemRepository extends ElasticsearchRepository<ItemEfm,Long>{
- // 当前ItemRepository接口可以继承SpringDataElasticsearch框架提供的父接口ElasticsearchRepository
- // 一旦继承,效果是会为指定的实体类自动生成基本的增删改查方法
- // ElasticsearchRepository<[关联的实体类名],[实体类主键类型]>
-
- // SpringData自定义查询
- // 遵循SpringData框架给定的格式,编写方法名称,就可以自动生成查询语句
- // query(查询): 表示当前方法是一个查询方法,类似sql中的select
- // Item\Items: 表示要查询的实体类,不带s返回单个对象,带s返回集合类型
- // By(通过): 标识开始设置条件的关键词,类似sql中的where
- // Title: 要查询的字段名称
- // Matches: 执行的查询操作,Matches表示执行查询支持分词的字符串 类似sql中的like
-
- Iterable<ItemEfm> queryItemsByTitleMatches(String title);
-
- // 四.es详细分词查询(多条件查询and)
- // 多条件查询
- // 多个条件之间需要使用逻辑运算符And或Or来分割
- // 方法参数赋值的依据是根据方法名称中参数的顺序来决定的(参数不能乱取名字,title,brand)
- Iterable<ItemEfm> queryItemsByTitleMatchesAndBrandMatches(String title, String brand);
-
- // 四.es详细分词查询(多条件排序查询or)
- // query、By、Matches、Or、OrderBy、Desc(倒序):均为关键字
- // Items :实体映射名字(也是此实体对应es其中一个索引库的名字)
- // Title、Brand :需要根据什么字段进行查询
- // Price :配合OrderBy、Desc意思是根据价格倒序
- Iterable<ItemEfm> queryItemsByTitleMatchesOrBrandMatchesOrderByPriceDesc(String title,String brand);
-
- // 一.全称查询(多写一个字段,对其设置FieldType.Keyword, 如此此字段就是不分词的全称索引)
- ItemEfm findByBrand(String brand);
-
- // 二.es精确分词查询(全称+分词+模糊三种查询合一)(精确查询,前端传参的分词与后端索引,必须全部匹配到才能查询到)
- org.springframework.data.domain.Page<ItemEfm> findByTitleOrderByIntertestNumDesc(String title,Pageable pageable);
-
- // 三.分页查询+分词查询--->分词查询(传参和索引都会进行分词,然后进行一一匹配,并通过自带算法做好排序)(自己也可以设置排序) (前端传参的分词与后端索引,只要能匹配到一个就能查询出来)
- // 实现分页查询:最后一个参数的位置添加声明类型Pageable的变量
- // 返回值修改为Page类型,这个类型的对象不但能够保存查询出的数据,而且还能自动计算出分页信息
- // 分页信息中包括:当前页,总页数,总条数,是否有上一页或下一页等
- Page<ItemEfm> queryItemsByTitleMatchesOrBrandMatchesOrderByIntertestNumDesc(
- String title,String brand,Pageable pageable);
-
- List<ItemEfm> queryItemsByTitleMatchesOrBrandMatchesOrderByOrigPriceDesc(String title,String brand);
- }
- package com.nengyy.rest_server.service.impl.mall;
-
- import com.baomidou.mybatisplus.core.metadata.IPage;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.nengyy.dao_mysql.common.utils.PageUtil;
- import com.nengyy.dao_mysql.mapper.primary.mall.CommodityListMapper;
- import com.nengyy.dem_common.utils.ListUtils;
- import com.nengyy.dem_common.utils.StringUtils;
- import com.nengyy.dto.mall.*;
- import com.nengyy.rest_server.elasticsearch.entity.ItemEfm;
- import com.nengyy.rest_server.elasticsearch.repository.ItemRepository;
- import com.nengyy.rest_server.service.impl.consignment.DatacenterIdGenerator;
- import com.nengyy.rest_server.service.mall.ItemRepositoryService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.domain.PageRequest;
- import org.springframework.stereotype.Service;
- import java.util.*;
- /**
- * @Author: cyz
- * @Date: 2023/04/24
- * @Description:
- */
- @Service
- public class ItemRepositoryServiceImpl implements ItemRepositoryService {
- private final ItemRepository itemRepository;
- private final CommodityListMapper commodityListMapper;
- @Autowired
- public ItemRepositoryServiceImpl(ItemRepository itemRepository, CommodityListMapper commodityListMapper) {
- this.itemRepository = itemRepository;
- this.commodityListMapper = commodityListMapper;
- }
- /**从数据库查出所有符合条件的商品 , 每天定时进行es索引的刷新*/
- @Override
- public String goodsList() {
- List<ESCommodityListDto> data = commodityListMapper.getGoodsList();
- List<ItemEfm> list = new ArrayList<>();
- DatacenterIdGenerator snowId1 = new DatacenterIdGenerator(17,18);//获取雪花算法ID
- ItemEfm item;
- if(data != null){
- for (ESCommodityListDto listDto:data) {
- if("2".equals(listDto.getGoodsSource())){
- item = new ItemEfm();
- item.setId(snowId1.nextId());
- item.setGoodsId(listDto.getGoodsId());
- item.setTitle(listDto.getGoodsDesc());
- item.setCategory(listDto.getGoodsType());
- item.setBrand(listDto.getGoodsDesc()); //此字段用来做全称查询,用来补充分词查询的不足
- item.setPrice(listDto.getGoodsFee());
- item.setOrigPrice(listDto.getReservFee1());
- item.setImgPath(listDto.getFilePath());
- item.setIntertestNum(listDto.getIntertestNum());
- list.add(item);
- }else{
- item = new ItemEfm();
- item.setId(snowId1.nextId());
- item.setGoodsId(listDto.getGoodsId());
- item.setTitle(listDto.getGoodsName());
- item.setCategory(listDto.getGoodsType());
- item.setBrand(listDto.getGoodsName()); //此字段用来做全称查询,用来补充分词查询的不足
- item.setPrice(listDto.getGoodsFee());
- item.setOrigPrice(listDto.getReservFee1());
- item.setImgPath(listDto.getFilePath());
- item.setIntertestNum(listDto.getIntertestNum());
- list.add(item);
- }
- }
- //先删除之前存的索引(批量删)
- itemRepository.deleteAll();
- //添加新的索引 (批量加)
- itemRepository.saveAll(list);
- }
- return "成功";
- }
-
- /**
- * Es搜索出的商品(分页获取商品列表)
- * @param in
- * @return
- */
- @Override
- public Page<CommodityListDto> searchCommodityList(SiftEsCommodityListDto in) {
- //一.全称查询(不分词查询)
- ItemEfm oneGoods = itemRepository.findByBrand(in.getGoodsDesc());
- //二.es精确分词查询(全称+分词+模糊三种查询合一)(精确查询,前端传参的分词与后端索引,必须全部匹配到才能查询到)
- org.springframework.data.domain.Page<ItemEfm> pageGoodsList = itemRepository.findByTitleOrderByIntertestNumDesc(in.getGoodsDesc(),PageRequest.of(0, 49));
- //三.分页查(非精确分词查询)(前端传参的分词与后端索引,只要能匹配到一个就能查询出来)
- int size = in.getPageSize() - pageSizeExtra;
- int size1 = size >=0 ? size :1;
- org.springframework.data.domain.Page<ItemEfm> page = itemRepository
- .queryItemsByTitleMatchesOrBrandMatchesOrderByIntertestNumDesc( //通过商品描述和商品品牌(暂定传值为空)进行查询并通过关注人数进行排序
- in.getGoodsDesc(),"",PageRequest.of(in.getPageNo() - 1, size1));
- }
Spring Data根据方法名称自动实现功能:
查询方式两种:query(详细查询)与find(精确查询)
// 四.es详细分词查询(多条件排序查询or)
// query、By、Matches、Or、OrderBy、Desc(倒序):均为关键字
// Items :实体映射名字(也是此实体对应es其中一个索引库的名字)
// Title、Brand :需要根据什么字段进行查询
// Price :配合OrderBy、Desc意思是根据价格倒序
//黑色和蓝色均为关键字 实体映射名 根据哪个字段查询 根据哪个字段倒序
Iterable<ItemEfm> queryItemsByTitleMatchesOrBrandMatchesOrderByPriceDesc(String title,String brand);
// 二.es精确分词查询(全称+分词+模糊三种查询合一)(精确查询,前端传参的分词与后端索引,必须全部匹配到才能查询到)
org.springframework.data.domain.Page<ItemEfm> findByTitleOrderByIntertestNumDesc(String title,Pageable pageable);
// 三.分页查询+分词查询--->分词查询(传参和索引都会进行分词,然后进行一一匹配,并通过自带算法做好排序)(自己也可以设置排序) (前端传参的分词与后端索引,只要能匹配到一个就能查询出来)
// 实现分页查询:最后一个参数的位置添加声明类型Pageable的变量
// 返回值修改为Page类型,这个类型的对象不但能够保存查询出的数据,而且还能自动计算出分页信息
// 分页信息中包括:当前页,总页数,总条数,是否有上一页或下一页等
Page<ItemEfm> queryItemsByTitleMatchesOrBrandMatchesOrderByIntertestNumDesc(
String title,String brand,Pageable pageable);
可以通过chatGpt自行问Elasticsearch不同版本对应的lucene版本
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>8.11.1</version>
</dependency>
@Document(indexName = "itemsapp1")
//其中itemsapp1是自定义的索引库的库名,es中有很多的索引库,是项目通过不同实体创建的索引库
解释:(删除索引后,重启项目,调用刷新索引项目可以重建索引库)
解决方法:1.想删除Elasticsearch索引库,可以使用es的可视化工具
2.Elasticvue -(es的可视化工具)用于浏览器的免费开源 Elasticsearch GUI
Elasticvue安装步骤网址:https://blog.csdn.net/UbuntuTouch/article/details/125777834
3.利用Elasticvue连接上Elasticsearch
--Ik下载网址: https://github.com/medcl/elasticsearch-analysis-ik/releases
--参考ik详解网址:【精选】ElasticSearch——IK分词器的下载及使用_ik分词器下载-CSDN博客
--将解压的ik分词器改名为ik,放到plugins目录下即可(下之前百度查自己es对应版本的ik,容错率挺高的)
1.案例代码
GET http://localhost:9200
### 三个#既是分隔符也是注释,两个请求之间必须使用它来分割,否则无法运行
POST http://localhost:9200/_analyze
Content-Type: application/json
{
"text": "绿色冰种手镯",
"analyzer": "ik_smart"
}
2.创建一个demo案例
3.Es启动后,直接点击启动就可以测试
1.直接用记事本打开main.dic,在里面添加不想进行分词的词语
2.ik_smart和ik_max_word两种分词不同
ik_smart //智能分词: 粗粒度分词 (字不会被重复使用)
ik_max_word //细粒度分词 (字会重复被使用)
项目实体建议:@Field(type = FieldType.Text, //生成索引时使用 ik_max_word,在搜索时(对前端传递来的参数分词)用ik_smart
analyzer = "ik_max_word", //最细粒度拆分-->(字会重复被使用)(生成索引时,进行分词使用)
searchAnalyzer = "ik_smart") //最粗粒度拆分-->智能拆分(字不会被重复使用)(搜索时,对搜索词进行分词)
private String title; // 商品描述
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。