检索是一个十分普遍的作用,大伙儿毫无疑问都应用过,比如:网页搜索、Google 检索、电子商务商品查询、美团商家/食品类检索这些。
照片来源于 Pexels
伴随着互联网信息可燃性地飞快提高,网友必须更合理的人性化站内搜索。因此互联网技术运用基本上沒有不开发设计检索作用的,即然这一作用那么关键,作为一名达标的程序猿务必弄清楚其身后的完成基本原理。分配!
文中将根据 Spring Boot Elasticsearch Vue 完成一个简易版的电子商务检索系统软件,便捷大伙儿了解身后的基本原理。
经典案例
依据图中能够获知,检索的领域模型实际上蛮简易的,客户键入要检索的产品关键字递交之后,将关键词搜索、页数信息内容等传往后面台,后台管理查看后将結果集开展解决并回到。
必须关心的只不过以下几个方面:
MySQL
关键表(goods)以下:
MySQL 产品表的字段名是十分多的,而商城系统检索网页页面所必须的数据信息只不过便是产品ID、产品名称、产品价格、产品评价数和产品初始图等(依据自身具体开发设计状况而定,这儿依据文中实例前面款式开展剖析)。
一般产品表还会继续选择商品关键字字段名专业便捷百度搜索引擎应用,因此一条单表 SQL 查看坚信应当打不倒诸位。
大家先不考虑到数据库查询特性层面的难题,就单纯性为了更好地完成这一作用讨论一下都必须干什么:
WTF,收到那样的要求如果让你用关联型数据库查询去完成,确实有点儿自讨没趣。该怎么办?往下看。
Elasticsearch
伴随着互联网信息可燃性地飞快提高,传统式的如何查询已没法为网友出示合理的站内搜索。
如果我们做的仅仅用户数量非常少的内部网新项目,而且检索的字段名全是一些內容很简洁明了的字段名,例如名字,序号这类的,那彻底可以用数据库查询 like 句子。
可是,数据库查询 like 查看特性极低,假如检索的要求太多,或是必须检索的是大文字种类的內容(全文检索),那麼这类检索的计划方案也是不可取的。
互联网技术的迅猛发展急切地要求一种迅速、全方位、精确且平稳靠谱的信息内容如何查询。
即然我们要做特性高的全文检索,这一要求又不可以依靠数据库查询,只有由我们自己来完成了。
可是令大家很受严厉打击的是全文检索是难以完成的,大家不但期待能全文检索,还期待它充足平稳充足快,且百度搜索有关键词高亮度,还能按各种各样配对成绩来排列,期待它能转换不一样的匹配算法来达到各种各样词性标注要求。
总的来说,如果我们想要做一个功能齐全,特性强劲的全文检索实际上并非易事,而全文检索也是一个普遍的要求,在这类自然环境下,目前市面上发生了一些开源系统的解决方法。
这种解决方法开源系统出去后,得到了很多的小区开发人员适用,持续为其开发设计软件,使其持续提升和健全,这就变成大家所讲的百度搜索引擎了。而他们中最有名的便是 Elasticsearch 和 Solr。
①词性标注
刚刚大家提及的难题中,假定检索标准是华为荣耀手机平板,规定是只需达到了在其中随意一个词句组成的数据信息都需要查看出去。
依靠 Elasticseach 的文本分析作用能够轻轻松松将检索标准开展词性标注解决,再融合全文索引完成迅速查找。
Elasticseach 出示了三种词性标注方式:
一个字词性标注:
二分法词性标注:
词典词性标注:按某类优化算法结构词,随后去配对已建好的词库结合,假如配对到就分割出去变成词句。
一般词典词性标注被觉得是最理想化的汉语匹配算法。而词典词性标注最常见的便是 IK 词性标注。
IK 分词器出示二种分词模式:
②全文索引
针对百度搜索引擎而言:
全文索引的查看步骤是:最先依据关键词搜索到相匹配的文本文档 ID,随后依据正排数据库索引查看文本文档 ID 的详细內容,最终回到给客户要想的結果。
③构成部分
全文索引是百度搜索引擎的关键,关键包括2个一部分:
全文索引项(Posting)关键包括以下的信息内容:
④实例
全文索引论文参考文献:《这就是搜索引擎:核心技术详解》张俊林著。
假定文本文档结合包括五个文本文档,每一个文本文档內容如下图所显示。在图上最左方一栏是每一个文本文档相匹配的文本文档序号。大家的每日任务便是对这一文本文档结合创建全文索引。
最先用分词算法将文本文档全自动切分为英语单词编码序列。为了更好地系统软件事后解决便捷,必须对每一个不一样的英语单词授予唯一的英语单词序号,另外纪录什么文本文档中包括这一英语单词,在这般解决完毕后,我们可以获得非常简单的全文索引,如下图所显示。
在图上,“英语单词 ID”一栏纪录了每一个英语单词的英语单词序号,第二栏是相匹配的英语单词,第三栏即每一个英语单词相匹配的倒排序表。例如英语单词 Google,其英语单词序号为 1,倒排序表为 1,2,3,4,5,表明文本文档结合中每一个文本文档都包括了这一英语单词。
为了更好地便捷大伙儿了解,图中仅仅一个简易的全文索引,只纪录了什么文本文档包括什么英语单词。而实际上,数据库索引系统软件还能够纪录此外的其他信息。
下面的图则是一个相对性繁杂的全文索引,在英语单词相匹配的倒排序表格中不但纪录了文本文档序号,还纪录了英语单词頻率信息内容(TF),即这一英语单词在某一文本文档中发生的频次。
往往要纪录这一信息内容,是由于高频词信息内容在百度搜索排列时,测算查看和文本文档相似性是很重要的一个测算因素,因此将其纪录在倒排序表格中,以便捷事后排列时开展得分测算。
图上英语单词 创办人 的英语单词序号为 7,相匹配的倒排序表內容为 (3;1),在其中 3 意味着文本文档序号为 3 的文本文档包括这一英语单词,数据 1 意味着高频词信息内容,即这一英语单词在 3 号文本文档中只发生过 1 次。
好用的全文索引还能够纪录大量的信息内容,如下图所显示数据库索引系统软件除开纪录文本文档序号和英语单词頻率信息内容外,附加记述了两大类信息内容,即每一个英语单词相匹配的“文本文档頻率信息内容”及其在倒排序表格中纪录英语单词在某一文本文档发生的位置信息(POS)。
拥有这一数据库索引系统软件,百度搜索引擎能够很便捷地回应客户的查看,例如客户键入查看词“Facebook”,检索系统软件搜索全文索引,从这当中载入包括这一英语单词的文本文档,这种文本文档便是出示给客户的百度搜索。
运用英语单词頻率信息内容、文本文档頻率信息内容能够对这种备选百度搜索开展排列,测算文本文档和查看的相似度,依照相似度的评分由高到低排列輸出。
总的来说,你懂得的,废话不多说,下边进到实战演练阶段。
自然环境:
Elasticsearch
安裝步骤这儿但是多过多阐释,文中应用 Elasticsearch 群集自然环境,已安裝好 IK 汉语分词器。
下面的图为 elasticsearch-head 软件(电脑浏览器能够立即安裝该软件开展联接)表明的群集信息内容。
Spring Boot
①建立新项目
应用 Spring Initializr 复位 Spring Boot 新项目,加上 Spring Web,Spring Data Elasticsearch,MySQL,MyBatis,Lombok。
②环境变量
application.yml 配备 MySQL、Elasticsearch、MyBatis 基本信息。
- spring:
- # 数据库
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost:3306/example?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false
- username: root
- password: 123456
- # elasticsearch
- elasticsearch:
- rest:
- uris: 192.168.10.10:9200,192.168.10.11:9200,192.168.10.12:9200
- mybatis:
- configuration:
- map-underscore-to-camel-case: true # 打开骆驼峰投射
③运行类
运行类加上 Mapper 插口扫描仪。
- package com.example;
- import org.mybatis.spring.annotation.MapperScan;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- @MapperScan("com.example.mapper") // Mapper 插口扫描仪
- @SpringBootApplication
- public class SearchDemoApplication {
- public static void main(String[] args) {
- SpringApplication.run(SearchDemoApplication.class, args);
- }
- }
前面
将我替大伙儿准备好的前端资源文档加上至新项目 resources 文件目录下的 static 文件目录中。
在 list.html 中应用 CDN 加上 Vue 和 Axios 免除下载文件的全过程。
- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js"></script>
- <script src="https://cdn.jsdelivr.net/npm/axios@0.21.1/dist/axios.min.js"></script>
运行
浏览:http://localhost:8080/list.html,实际效果以下:
作用开发设计
创建索引
①要求表明
该作用关键用以将 MySQL 产品信息导进 Elasticseach。
假如贵公司构建了 ELK 系统软件,能够应用 Logstash 将 MySQL 产品信息导进 Elasticseach。这些內容中后期因为我会升级,敬请关注,今日我们不聊这些。
即然沒有 Logstash 那大家就根据编码将 MySQL 数据信息导进 Elasticseach。
MySQL 产品表的字段名是十分多的,而商城系统检索网页页面所必须的数据信息只不过便是产品ID、产品名称、产品价格、产品评价数和产品初始图等(依据自身具体开发设计状况而定,这儿依据文中实例前面款式开展剖析)。
一般产品表还会继续选择商品关键字字段名专业便捷百度搜索引擎应用,因此一条单表 SQL 查看坚信应当打不倒诸位。
②dao层
建立dao层 Goods.java,加上 @Document 注释用以投射 Elasticsearch 数据库索引库:
设定数据库索引标准:
- package com.example.pojo;
- import lombok.Data;
- 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;
- @Data
- @NoArgsConstructor
- /**
- * @Document 投射 Elasticsearch 数据库索引库所必须的注释
- * indexName:数据库索引库名字
- * shards:分块数
- * replicas:团本数
- * createIndex:是不是创建索引库
- */
- @Document(indexName = "goods", shards = 5, replicas = 1, createIndex = true)
- public class Goods implements Serializable {
- private static final long serialVersionUID = -1989082640160920658L;
- @Id
- private Integer goodsId; // 产品ID
- @Field(type = FieldType.Text, analyzer = "ik_max_word") // 词性标注
- private String goodsName; // 产品名称
- @Field(type = FieldType.Text, analyzer = "ik_max_word") // 词性标注
- private String keywords; // 产品关键字
- @Field(type = FieldType.Double)
- private BigDecimal marketPrice; // 市价
- @Field(type = FieldType.Short)
- private Short commentCount; // 产品评价数
- @Field(type = FieldType.Keyword)
- private String originalImg; // 产品初始图详细地址
- private String goodsRemark; // 产品简易叙述
- private String goodsContent; // 产品详细说明,储存商品详情图详细地址
- private Integer catId; // 归类ID
- private Integer extendCatId; // 拓展归类ID
- private String goodsNo; // 商品编号
- private Integer clickCount; // 点击量
- private Short brandId; // 知名品牌ID
- private Short storeCount; // 库存量总数
- private Integer weight; // 产品净重,企业:克
- private BigDecimal shopPrice; // 店铺价
- private BigDecimal costPrice; // 产品出厂价
- private Byte isReal; // 是不是为商品
- private Byte isOnSale; // 是不是发布
- private Byte isFreeShipping; // 是不是免邮 0 否, 1 是
- private Integer onTime; // 产品发布時间
- private Short sort; // 产品排列
- private Byte isRecommend; // 是不是强烈推荐
- private Byte isNew; // 是不是新产品
- private Byte isHot; // 是不是畅销
- private Integer lastUpdate; // 最终更新
- private Short goodsType; // 产品隶属种类ID
- private Short specType; // 商品规格种类
- private Integer giveIntegral; // 购买商品赠予積分
- private Integer exchangeIntegral; // 积分换购:0 不参加积分换购
- private Short suppliersId; // 供应商ID
- private Integer salesSum; // 产品销售量
- private Byte promType; // 0 一般订单信息,1 限时秒杀, 2 团购价, 3 营销特惠
- private Integer promId; // 优惠促销ID
- private BigDecimal commission; // 提成用以分销商分为
- private String spu; // SPU
- private String sku; // SKU
- }
③GoodsMapper.java
从 MySQL 查看 goods 产品表:产品ID、产品名称、产品关键字、市价、产品评价数、产品初始图详细地址。这种字段名用以百度搜索引擎应用。
- package com.example.mapper;
- import com.example.pojo.Goods;
- import org.apache.ibatis.annotations.Select;
- import java.util.List;
- /**
- * @author hello沃德老先生
- * @微信公众平台 hello沃德老先生
- * @website https://mrhelloworld.com
- * @wechat 124059770
- */
- public interface GoodsMapper {
- /**
- * 查看产品ID、产品名称、产品关键字、市价、产品评价数、产品初始图详细地址
- *
- * @return 产品列表
- */
- @Select("select goods_id, goods_name, keywords, market_price, comment_count, original_img from goods")
- List<Goods> selectGoodsList();
- }
④GoodsRepository.java
application.yml 环境变量加上一个自定配备,用以操纵创建索引和设定投射的电源开关。
- # 自定配备
- search:
- index:
- enabled: true # 是不是必须创建索引和设定投射。默认设置为 false
GoodsRepository.java 引入 ElasticsearchRestTemplate,撰写创建索引和设定投射有关编码。
- package com.example.repository;
- import com.example.pojo.Goods;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
- import org.springframework.data.elasticsearch.core.IndexOperations;
- import org.springframework.data.elasticsearch.core.document.Document;
- import org.springframework.stereotype.Repository;
- import javax.annotation.Resource;
- import java.util.Arrays;
- import java.util.List;
- /**
- * @author hello沃德老先生
- * @微信公众平台 hello沃德老先生
- * @website https://mrhelloworld.com
- * @wechat 124059770
- */
- @Repository
- public class GoodsRepository {
- @Resource
- private ElasticsearchRestTemplate elasticsearchRestTemplate;
- // 是不是必须创建索引和设定投射。默认设置为 false
- @Value("${search.index.enabled}")
- private boolean indexEnabled;
- /**
- * 大批量增加产品信息至 Elasticsearch
- *
- * @param goodsList
- */
- public void save(List<Goods> goodsList) {
- // 是不是必须创建索引和设定投射
- if (indexEnabled) {
- createIndexAndPutMapping();
- }
- // 大批量增加
- elasticsearchRestTemplate.save(goodsList);
- }
- /**
- * 增加单独产品信息至 Elasticsearch
- *
- * @param goods
- */
- public void save(Goods goods) {
- save(Arrays.asList(goods));
- }
- /**
- * 创建索引和设定投射
- */
- private void createIndexAndPutMapping() {
- // 设定数据库索引信息内容(dao层)
- IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Goods.class);
- // 创建索引
- indexOperations.create();
- // 建立投射
- Document mapping = indexOperations.createMapping();
- // 将投射载入数据库索引
- indexOperations.putMapping(mapping);
- }
- }
⑤SearchService.java
SearchService.java 引入 GoodsMapper 和 GoodsRepository,完成将 MySQL 产品信息导进 Elasticsearch。
- package com.example.service;
- import com.example.mapper.GoodsMapper;
- import com.example.repository.GoodsRepository;
- import org.springframework.stereotype.Service;
- import javax.annotation.Resource;
- /**
- * @author hello沃德老先生
- * @微信公众平台 hello沃德老先生
- * @website https://mrhelloworld.com
- * @wechat 124059770
- */
- @Service
- public class SearchService {
- @Resource
- private GoodsMapper goodsMapper;
- @Resource
- private GoodsRepository goodsRepository;
- /**
- * 将 MySQL 产品信息导进 Elasticsearch
- */
- public void importGoods() {
- goodsRepository.save(goodsMapper.selectGoodsList());
- }
- }
⑥单元测试卷
针对当今实例来讲,这些作用没必要曝露一个插口去启用,立即內部撰写单元测试卷进行就可以。
- package com.example.service;
- import com.example.SearchDemoApplication;
- import org.junit.jupiter.api.Test;
- import org.springframework.boot.test.context.SpringBootTest;
- import javax.annotation.Resource;
- @SpringBootTest(classes = SearchDemoApplication.class)
- public class SearchServiceTest {
- @Resource
- private SearchService searchService;
- @Test
- public void testImportGoods() {
- searchService.importGoods();
- }
- }
实行单元测试卷之后,更新 elasticsearch-head 软件网页页面,結果以下:
查询一下 goods 数据库索引库的投射信息内容。
MySQL 的 goods 表:
Elasticsearch 的 goods 数据库索引库:
见到之上結果,表明 MySQL 产品信息已所有导进 Elasticsearch。
检索
下面就需要进到今日的主题风格了,检索作用的完成。要做就做全套,大家应用仿京东模版 Vue 完成一个真实的电子商务检索作用。
检索的领域模型实际上蛮简易的,客户键入要检索的产品关键字递交之后,将关键词搜索、页数信息内容等传往后面台,再相互配合 Spring Data Elasticseach 就可以轻轻松松拿下。
①GoodsRepository.java
依照惯例,DAO 层只承担数据处理方法,一行编码拿下。
- /**
- * 分页查询、高亮度查看
- *
- * @param query
- * @return
- */
- public SearchHits<Goods> selectGoodsListForPage(NativeSearchQuery query) {
- return elasticsearchRestTemplate.search(query, Goods.class);
- }
②PageInfo.java
这类作用毫无疑问全是必须配搭分页查询解决的,封裝一个分页查询目标方便快捷。
- package com.example.result;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import java.io.Serializable;
- import java.util.List;
- /**
- * @author hello沃德老先生
- * @微信公众平台 hello沃德老先生
- * @website https://mrhelloworld.com
- * @wechat 124059770
- */
- @Data
- @NoArgsConstructor
- public class PageInfo<T> implements Serializable {
- private static final long serialVersionUID = 6260163970867016563L;
- private int currentPage; // 当页
- private int pageSize; // 每张表明总数
- private int total; // 总纪录数
- private int totalPage; // 总页码
- private int prePage; // 上一页
- private int nextPage; // 下一页
- private boolean hasPre; // 是不是有上一页
- private boolean hasNext; // 是不是有下一页
- private List<T> result; // 回到結果集
- public PageInfo(int currentPage, int pageSize) {
- // 当页
- this.currentPage = currentPage < 1 ? 1 : currentPage;
- // 每张表明总数
- this.pageSize = pageSize;
- // 是不是有上一页
- this.hasPre = currentPage == 1 ? false : true;
- // 是不是有下一页
- this.hasNext = currentPage == totalPage ? false : true;
- // 上一页
- if (hasPre) {
- this.prePage = currentPage - 1;
- }
- // 下一页
- if (hasNext) {
- this.nextPage = currentPage 1;
- }
- }
- public PageInfo(int currentPage, int pageSize, int total) {
- // 当页
- this.currentPage = currentPage < 1 ? 1 : currentPage;
- // 每张表明总数
- this.pageSize = pageSize;
- // 总纪录数
- this.total = total;
- // 测算总页码
- if (total == 0) {
- this.totalPage = 0;
- } else {
- this.totalPage = (total - 1) / pageSize 1;
- }
- // 是不是有上一页
- this.hasPre = currentPage == 1 ? false : true;
- // 是不是有下一页
- this.hasNext = currentPage == totalPage ? false : true;
- // 上一页
- if (hasPre) {
- this.prePage = currentPage - 1;
- }
- // 下一页
- if (hasNext) {
- this.nextPage = currentPage 1;
- }
- }
- }
③SearchService.java
Service 领域模型层关键关心下列关键点:
- /**
- * 检索
- *
- * @param searchStr 检索标准
- * @param pageNum 哪页
- * @param pageSize 每张表明总数
- * @return
- */
- public PageInfo<GoodsVo> doSearch(String searchStr, Integer pageNum, Integer pageSize) {
- // 设定高亮度文件格式 <span style='color:red;'></span>
- HighlightBuilder.Field field = new HighlightBuilder.Field("goodsName");
- field.preTags("<span style='color:red;'>");
- field.postTags("</span>");
- // 搭建检索标准目标
- BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
- // 设定检索标准 goodsName 和 keywords
- boolQueryBuilder.must(QueryBuilders.multiMatchQuery(searchStr, "goodsName", "keywords"));
- // 搭建检索目标
- NativeSearchQuery query = new NativeSearchQueryBuilder()
- .withQuery(boolQueryBuilder) // 检索标准
- .withHighlightFields(field) // 高亮度
- .withPageable(PageRequest.of(pageNum - 1, pageSize)) // 分页查询,当页从 0 逐渐
- .build();
- // 检索
- SearchHits<Goods> searchHits = goodsRepository.selectGoodsListForPage(query);
- // 总总数
- Long total = searchHits.getTotalHits();
- if (0 > total) {
- return new PageInfo<>(pageNum, pageSize, 0);
- }
- // 复位回到結果集
- List<GoodsVo> goodsVoList = new ArrayList<>();
- // 解决百度搜索集
- for (SearchHit<Goods> searchHit : searchHits) {
- // 复位回到結果目标
- GoodsVo goodsVo = new GoodsVo();
- // 获得結果目标
- Goods goods = searchHit.getContent();
- // 复制特性
- BeanUtils.copyProperties(goods, goodsVo);
- // 解决高亮度信息内容
- Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
- // 是不是有高亮度信息内容
- if (highlightFields.containsKey("goodsName")) {
- String goodsNameHl = highlightFields.get("goodsName").get(0);
- goodsVo.setGoodsNameHl(goodsNameHl);
- } else {
- goodsVo.setGoodsNameHl(goods.getGoodsName());
- }
- goodsVoList.add(goodsVo);
- }
- // 复位分页查询目标
- PageInfo<GoodsVo> pageInfo = new PageInfo<GoodsVo>(pageNum, pageSize, total.intValue());
- pageInfo.setResult(goodsVoList);
- return pageInfo;
- }
④SearchController.java
操纵层出示一个 /search 的 GET 插口。
- package com.example.controller;
- import com.example.result.PageInfo;
- import com.example.service.SearchService;
- import com.example.vo.GoodsVo;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- import javax.annotation.Resource;
- /**
- * @author hello沃德老先生
- * @微信公众平台 hello沃德老先生
- * @website https://mrhelloworld.com
- * @wechat 124059770
- */
- @RestController
- @RequestMapping("search")
- public class SearchController {
- @Resource
- private SearchService searchService;
- /**
- * 检索
- *
- * @param searchStr 检索标准
- * @param pageNum 哪页
- * @param pageSize 每张表明总数
- * @return
- */
- @GetMapping
- public PageInfo<GoodsVo> doSearch(String searchStr, Integer pageNum, Integer pageSize) {
- return searchService.doSearch(searchStr, pageNum, pageSize);
- }
- }
⑤list.html
在 list.html 中应用 CDN 加上 Vue 和 Axios 免除下载文件的全过程。
- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js"></script>
- <script src="https://cdn.jsdelivr.net/npm/axios@0.21.1/dist/axios.min.js"></script>
⑥网页页面解决
改动头顶部检索(擅于运用 Ctrl F)的表格一部分:
- <form action="" name="search" method="get" class="fl" onsubmit="return false;">
- <input id="searchStr" type="text" class="txt" value="输入您产品关键词"/>
- <input type="submit" class="btn" value="检索"/>
- <input id="pageNum" type="hidden" value="1"/>
- <input id="pageSize" type="hidden" value="12"/>
- </form>
改动产品列表(擅于运用 Ctrl F),只留有一个 <li></li>:
- <!-- 产品列表 start-->
- <div id="goodsList" class="goodslist mt10">
- <ul>
- <li>
- <dl>
- <dt><a href=""><img src="images/goods1.jpg" alt=""/></a></dt>
- <dd><a href=""><p class="beyondHidden">清华同方精英X2 电脑台式机(2核E3500 2G 500G DVD 键盘鼠标)带20英寸显示屏</p></a></dd>
- <dd><strong>¥2399.00</strong></dd>
- <dd><a href=""><em>现有10人点评</em></a></dd>
- </dl>
- </li>
- </ul>
- </div>
- <!-- 产品列表 end-->
改动分页查询信息内容(擅于运用 Ctrl F):
- <!-- 分页查询信息内容 start -->
- <div id="page" class="page mt20">
- <a href="">主页</a>
- <a href="">上一页</a>
- <a href="" class="cur">3</a>
- <a href="">下一页</a>
- <a href="">尾页</a>
- <span>
- <em>共8页 到第<input type="text" id="num" class="page_num"/>页</em>
- <a href="" class="skipsearch">明确</a>
- </span>
- </div>
- <!-- 分页查询信息内容 end -->
⑦Vue and Axios
最先全局性加上一个 div,设定 id="app"。
随后复位 Vue 目标,关联原素,界定部件数据信息和部件方式。
- <script>
- var app = new Vue({
- // element 的缩写,初始化原素,关联 id 为 app 的 html 编码精彩片段
- el: '#app',
- // 界定部件数据信息
- data: {
- goodsList: [],
- page: []
- },
- // 界定部件方式
- methods: {
- // 检索
- doSearch() {
- axios({
- url: "http://localhost:8080/search",
- method: "GET",
- params: {
- searchStr: $("#searchStr").val(),
- pageNum: $("#pageNum").val(),
- pageSize: $("#pageSize").val()
- }
- }).then(response => { // 回到結果
- $("#pageNum").val(1);// 重置当前页
- if (response.data.total <= 0) {
- $('#goodsList').append('<strong>抱歉,沒有寻找与“' $("#searchStr").val() '”有关的产品,请确定关键词搜索是不是恰当。</strong>');
- }
- this.goodsList = response.data.result;
- this.page = response.data;
- }).catch(error => {// 出现异常捕捉
- alert('系统软件正在升级中,请稍后再试!');
- });
- },
- // 上一页
- prePage() {
- // 获得当页的值并减一,随后再次取值给当页
- let page = parseInt($("#pageNum").val()) - 1;
- $("#pageNum").val(page);
- // 启用检索涵数
- this.doSearch();
- },
- // 下一页
- nextPage() {
- // 获得当页的值并加一,随后再次取值给当页
- let page = parseInt($("#pageNum").val()) 1;
- $("#pageNum").val(page);
- // 启用检索涵数
- this.doSearch();
- },
- // 哪页
- whichPage(num) {
- // 获得点一下的按键(主页、1、2...尾页)值,随后再次取值给当页
- $("#pageNum").val(num);
- // 启用检索函数
- this.doSearch();
- },
- // 到哪页
- goToPage() {
- // 获得键入的页数值,随后再次取值给当页
- $("#pageNum").val($("#num").val());
- // 启用检索涵数
- this.doSearch();
- }
- }
- });
- </script>
⑧关联原素
改动头顶部检索(擅于运用 Ctrl F)的表格一部分:加上 v-on:click="doSearch"(缩写方法 @click="doSearch")到检索按键上。
- <form action="" name="search" method="get" class="fl" onsubmit="return false;">
- <input id="searchStr" type="text" class="txt" value="输入您产品关键词"/>
- <input v-on:click="doSearch" type="submit" class="btn" value="检索"/>
- <input id="pageNum" type="hidden" value="1"/>
- <input id="pageSize" type="hidden" value="12"/>
- </form>
改动产品列表(擅于运用 Ctrl F):
- <!-- 产品列表 start-->
- <div id="goodsList" class="goodslist mt10">
- <ul>
- <li v-for="(goods, index) in goodsList">
- <dl>
- <dt><a href=""><img v-bind:src="goods.originalImg" alt=""/></a></dt>
- <dd><a href=""><p class="beyondHidden" v-html="goods.goodsNameHl"></p></a></dd>
- <dd><strong>¥{{ goods.marketPrice }}</strong></dd>
- <dd><a href=""><em>现有{{ goods.commentCount }}人点评</em></a></dd>
- </dl>
- </li>
- </ul>
- </div>
- <!-- 产品列表 end-->
改动分页查询信息内容(擅于运用 Ctrl F):
- <!-- 分页查询信息内容 start -->
- <div id="page" class="page mt20">
- <a v-on:click="whichPage(1)" href="javascript:void(0);">主页</a>
- <a v-if="page.hasPre" v-on:click="prePage" href="javascript:void(0);">上一页</a>
- <a v-for="i in page.totalPage"
- v-on:click="whichPage(i)"
- v-bind:class="{ cur:i == page.currentPage }"
- href="javascript:void(0);">{{ i }}</a>
- <a v-if="page.hasNext" v-on:click="nextPage" href="javascript:void(0);">下一页</a>
- <a v-on:click="whichPage(page.totalPage)" href="javascript:void(0);">尾页</a>
- <span>
- <em>共{{ page.totalPage }}页 到第<input type="text" id="num" class="page_num"/>页</em>
- <a v-on:click="goToPage" href="javascript:void(0);" class="skipsearch">明确</a>
- </span>
- </div>
- <!-- 分页查询信息内容 end -->
检测
浏览:http://localhost:8080/list.html 随意键入哪些测试一下吧。
总结
到此 Elasticsearch 的实战演练好项目《电商搜索系统》就进行啦,文中解读了 Spring Boot 融合 Elasticsearch 的应用,顺带融合前面 Vue 完成了网页页面实际效果。
做为一款十分受欢迎的百度搜索引擎,大伙儿十分必须开展更深层次的学习培训,最终祝大家涨薪!涨薪!涨薪!
要想一步到位立即获得编码的同学们:
- 连接:https://pan.baidu.com/s/1VfRjcHCtTFo1-y-nwhmLvQ
- 提取码:abcd
参考文献:
创作者:hello沃德老先生
编写:陶家龙
出處:转载微信公众号hello沃德老先生(ID:imrhelloworld)