ElasticSearch-ElasticSearch实战-仿京东商城搜索(高亮)
注:此为笔者学习狂神说ElasticSearch的实战笔记,其中包含个人的笔记和理解,仅做学习笔记之用,更多详细资讯请出门左拐B站:狂神说!!!
七、ElasticSearch实战
仿京东商城搜索(高亮)
1、工程创建(springboot)
目录结构
2、基本编码
①导入依赖
<properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.3.7.RELEASE</spring-boot.version></properties><dependencies><!-- jsoup解析页面 --><!-- 解析网页 爬视频可 研究tiko --><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.10.2</version></dependency><!-- fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.70</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<!-- <version>7.6.1</version>--></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
②导入前端素材
③编写 application.preperties
配置文件
# 更改端口,防止冲突
server.port=9999
# 关闭thymeleaf缓存
spring.thymeleaf.cache=false
④测试controller和view
@Controller
public class IndexController {@GetMapping({"/","index"})public String index(){return "index";}
}
到这里可以先去编写爬虫,编写之后,回到这里
⑤编写Config
@Configuration
public class ElasticSearchConfig {@Beanpublic RestHighLevelClient restHighLevelClient(){RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1",9200,"http")));return client;}
}
⑥编写service
因为是爬取的数据,那么就不走Dao,以下编写都不会编写接口,开发中必须严格要求编写
ContentService
@Service
public class ContentService {@Autowiredprivate RestHighLevelClient restHighLevelClient;// 1、解析数据放入 es 索引中public Boolean parseContent(String keyword) throws IOException {// 获取内容List<Content> contents = HtmlParseUtil.parseJD(keyword);// 内容放入 es 中BulkRequest bulkRequest = new BulkRequest();bulkRequest.timeout("2m"); // 可更具实际业务是指for (int i = 0; i < contents.size(); i++) {bulkRequest.add(new IndexRequest("jd_goods").id(""+(i+1)).source(JSON.toJSONString(contents.get(i)), XContentType.JSON));}BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);restHighLevelClient.close();return !bulk.hasFailures();}// 2、根据keyword分页查询结果public List<Map<String, Object>> search(String keyword, Integer pageIndex, Integer pageSize) throws IOException {if (pageIndex < 0){pageIndex = 0;}SearchRequest jd_goods = new SearchRequest("jd_goods");// 创建搜索源建造者对象SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();// 条件采用:精确查询 通过keyword查字段nameTermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", keyword);searchSourceBuilder.query(termQueryBuilder);searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));// 60s// 分页searchSourceBuilder.from(pageIndex);searchSourceBuilder.size(pageSize);// 高亮// ....// 搜索源放入搜索请求中jd_goods.source(searchSourceBuilder);// 执行查询,返回结果SearchResponse searchResponse = restHighLevelClient.search(jd_goods, RequestOptions.DEFAULT);restHighLevelClient.close();// 解析结果SearchHits hits = searchResponse.getHits();List<Map<String,Object>> results = new ArrayList<>();for (SearchHit documentFields : hits.getHits()) {Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();results.add(sourceAsMap);}// 返回查询的结果return results;}
}
⑦编写controller
⑧测试结果
1、解析数据放入 es 索引中
2、根据keyword分页查询结果
报错
java.lang.IllegalStateException: Request cannot be executed; I/O reactor status: STOPPED
一般是因为OTSClient被调用了shutDown,其内部的I/O reactor均已被关闭。如果此时再调用OTSClient进行读写,则会抛出这个错误。 此处是:restHighLevelClient
3、爬虫(jsoup)
数据获取:数据库、消息队列、爬虫、…
①搜索京东搜索页面,并分析页面
http://search.jd.com/search?keyword=java
页面如下
审查页面元素
页面列表id:J_goodsList
目标元素:img、price、name
②爬取数据(获取请求返回的页面信息,筛选出可用的)
创建HtmlParseUtil,并简单编写
public class HtmlParseUtil {public static void main(String[] args) throws IOException {/// 使用前需要联网// 请求urlString url = "http://search.jd.com/search?keyword=java";// 1.解析网页(jsoup 解析返回的对象是浏览器Document对象)Document document = Jsoup.parse(new URL(url), 30000);// 使用document可以使用在js对document的所有操作// 2.获取元素(通过id)Element j_goodsList = document.getElementById("J_goodsList");// 3.获取J_goodsList ul 每一个 liElements lis = j_goodsList.getElementsByTag("li");// 4.获取li下的 img、price、namefor (Element li : lis) {String img = li.getElementsByTag("img").eq(0).attr("src");// 获取li下 第一张图片String name = li.getElementsByClass("p-name").eq(0).text();String price = li.getElementsByClass("p-price").eq(0).text();System.out.println("=======================");System.out.println("img : " + img);System.out.println("name : " + name);System.out.println("price : " + price);}}
}
运行结果
原因是啥?
一般图片特别多的网站,所有的图片都是通过延迟加载的
发现img标签中并没有属性src的设置,只是data-lazy-img设置图片加载的地址
创建HtmlParseUtil、改写
- 更改图片获取属性为
data-lazy-img
- 与实体类结合,实体类如下
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Content implements Serializable {private static final long serialVersionUID = -8049497962627482693L;private String name;private String img;private String price;
}
- 封装为方法
public class HtmlParseUtil {public static void main(String[] args) throws IOException {System.out.println(parseJD("java"));}public static List<Content> parseJD(String keyword) throws IOException {/// 使用前需要联网// 请求urlString url = "http://search.jd.com/search?keyword=" + keyword;// 1.解析网页(jsoup 解析返回的对象是浏览器Document对象)Document document = Jsoup.parse(new URL(url), 30000);// 使用document可以使用在js对document的所有操作// 2.获取元素(通过id)Element j_goodsList = document.getElementById("J_goodsList");// 3.获取J_goodsList ul 每一个 liElements lis = j_goodsList.getElementsByTag("li");
// System.out.println(lis);// 4.获取li下的 img、price、name// list存储所有li下的内容List<Content> contents = new ArrayList<Content>();for (Element li : lis) {// 由于网站图片使用懒加载,将src属性替换为data-lazy-imgString img = li.getElementsByTag("img").eq(0).attr("data-lazy-img");// 获取li下 第一张图片String name = li.getElementsByClass("p-name").eq(0).text();String price = li.getElementsByClass("p-price").eq(0).text();// 封装为对象Content content = new Content(name,img,price);// 添加到list中contents.add(content);}
// System.out.println(contents);// 5.返回 listreturn contents;}
}
结果展示
4、搜索高亮
在3、的基础上添加内容
①ContentService
// 3、 在2的基础上进行高亮查询
public List<Map<String, Object>> highlightSearch(String keyword, Integer pageIndex, Integer pageSize) throws IOException {SearchRequest searchRequest = new SearchRequest("jd_goods");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();// 精确查询,添加查询条件TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", keyword);searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));searchSourceBuilder.query(termQueryBuilder);// 分页searchSourceBuilder.from(pageIndex);searchSourceBuilder.size(pageSize);// 高亮 =========HighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field("name");highlightBuilder.preTags("<span style='color:red'>");highlightBuilder.postTags("</span>");searchSourceBuilder.highlighter(highlightBuilder);// 执行查询searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);// 解析结果 ==========SearchHits hits = searchResponse.getHits();List<Map<String, Object>> results = new ArrayList<>();for (SearchHit documentFields : hits.getHits()) {// 使用新的字段值(高亮),覆盖旧的字段值Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();// 高亮字段Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();HighlightField name = highlightFields.get("name");// 替换if (name != null){Text[] fragments = name.fragments();StringBuilder new_name = new StringBuilder();for (Text text : fragments) {new_name.append(text);}sourceAsMap.put("name",new_name.toString());}results.add(sourceAsMap);}return results;
}
②ContentController
替换高亮的方法
@ResponseBody
@GetMapping("/h_search/{keyword}/{pageIndex}/{pageSize}")
public List<Map<String, Object>> highlightParse(@PathVariable("keyword") String keyword,@PathVariable("pageIndex") Integer pageIndex,@PathVariable("pageSize") Integer pageSize) throws IOException {return contentService.highlightSearch(keyword,pageIndex,pageSize);
}
③结果展示
最终页面
5、前后端分离(简单使用Vue)
①下载并引入Vue.min.js和axios.js
下载失败报错,试试初始化一下npm
npm install vue
npm install axios
导入vue.min.js和axios.min.js
②修改静态页面
引入js
<script th:src="@{/js/vue.min.js}"></script>
<script th:src="@{/js/axios.min.js}"></script>
实现数据的双向绑定
绑定点击事件,去掉事件冒泡
遍历数据
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="utf-8"/><title>狂神说Java-ES仿京东实战</title><link rel="stylesheet" th:href="@{/css/style.css}"/><script th:src="@{/js/jquery.min.js}"></script>
</head>
<body class="pg">
<div class="page"><div id="app" class=" mallist tmall- page-not-market "><!-- 头部搜索 --><div id="header" class=" header-list-app"><div class="headerLayout"><div class="headerCon "><!-- Logo--><h1 id="mallLogo"><img th:src="@{/images/jdlogo.png}" alt=""></h1><div class="header-extra"><!--搜索--><div id="mallSearch" class="mall-search"><form name="searchTop" class="mallSearch-form clearfix"><fieldset><legend>天猫搜索</legend><div class="mallSearch-input clearfix"><div class="s-combobox" id="s-combobox-685"><div class="s-combobox-input-wrap"><input v-model="keyword" type="text" autocomplete="off" id="mq"class="s-combobox-input" aria-haspopup="true"></div></div><button type="submit" @click.prevent="searchKey" id="searchbtn">搜索</button></div></fieldset></form><ul class="relKeyTop"><li><a>狂神说Java</a></li><li><a>狂神说前端</a></li><li><a>狂神说Linux</a></li><li><a>狂神说大数据</a></li><li><a>狂神聊理财</a></li></ul></div></div></div></div></div><!-- 商品详情页面 --><div id="content"><div class="main"><!-- 品牌分类 --><form class="navAttrsForm"><div class="attrs j_NavAttrs" style="display:block"><div class="brandAttr j_nav_brand"><div class="j_Brand attr"><div class="attrKey">品牌</div><div class="attrValues"><ul class="av-collapse row-2"><li><a href="#"> 狂神说 </a></li><li><a href="#"> Java </a></li></ul></div></div></div></div></form><!-- 排序规则 --><div class="filter clearfix"><a class="fSort fSort-cur">综合<i class="f-ico-arrow-d"></i></a><a class="fSort">人气<i class="f-ico-arrow-d"></i></a><a class="fSort">新品<i class="f-ico-arrow-d"></i></a><a class="fSort">销量<i class="f-ico-arrow-d"></i></a><a class="fSort">价格<i class="f-ico-triangle-mt"></i><i class="f-ico-triangle-mb"></i></a></div><!-- 商品详情 --><div class="view grid-nosku" ><div class="product" v-for="result in results"><div class="product-iWrap"><!--商品封面--><div class="productImg-wrap"><a class="productImg"><img :src="result.img"></a></div><!--价格--><p class="productPrice"><em v-text="result.price"></em></p><!--标题--><p class="productTitle"><a v-html="result.name"></a></p><!-- 店铺名 --><div class="productShop"><span>店铺: 狂神说Java </span></div><!-- 成交信息 --><p class="productStatus"><span>月成交<em>999笔</em></span><span>评价 <a>3</a></span></p></div></div></div></div></div></div>
</div>
<script th:src="@{/js/vue.min.js}"></script>
<script th:src="@{/js/axios.min.js}"></script>
<script>new Vue({el:"#app",data:{"keyword": '', // 搜索的关键字"results":[] // 后端返回的结果},methods:{searchKey(){var keyword = this.keyword;console.log(keyword);axios.get('h_search/'+keyword+'/0/20').then(response=>{console.log(response.data);this.results=response.data;})}}});
</script>
</body>
</html>
测试
ElasticSearch-ElasticSearch实战-仿京东商城搜索(高亮) 到此完结,笔者归纳、创作不易,大佬们给个3连再起飞吧
相关文章:

ElasticSearch-ElasticSearch实战-仿京东商城搜索(高亮)
注:此为笔者学习狂神说ElasticSearch的实战笔记,其中包含个人的笔记和理解,仅做学习笔记之用,更多详细资讯请出门左拐B站:狂神说!!! 七、ElasticSearch实战 仿京东商城搜索(高亮) 1、工程创建…...
解释 Python 中的描述符(Descriptor)是什么?如何在 Python 中实现一个简单的 ORM(对象关系映射)?
解释 Python 中的描述符(Descriptor)是什么?举例说明其用法。 在 Python 中,描述符(Descriptor)是一种对象属性的扩展机制,它允许你在访问或修改属性时执行自定义的操作。描述符是实现了特定协…...

IP数据云识别真实IP与虚假流量案例
随着互联网的普及,企业在数字领域面临着越来越复杂的网络威胁。为了保护网站免受虚假流量和恶意攻击的影响,许多企业正在采用IP数据云。本文将结合一个真实案例,深入探讨IP数据云如何成功准确地识别真实用户IP和虚假流量IP,提高网…...
signalR+websocket:实现消息实时通讯——技能提升
signalR 解决步骤1:npm install microsoft/signalr6.0.6 安装指定版本的microsoft/signalr,我这边安装的版本是6.0.6 解决步骤2:引入import * as signalR from microsoft/signalr; import * as signalR from microsoft/signalr; 下面第三…...

机器学习入门-----sklearn
机器学习基础了解 概念 机器学习是人工智能的一个实现途径 深度学习是机器学习的一个方法发展而来 定义:从数据中自动分析获得模型,并利用模型对特征数据【数据集:特征值+目标值构成】进行预测 算法 数据集的目标值是类别的话叫做分类问题;目标值是连续的数值的话叫做回…...

双非本科准备秋招(15.3)—— 力扣二叉树
今天学了二叉树结点表示法,建树代码如下。 public class TreeNode {public int val;public TreeNode left;public TreeNode right;public TreeNode(int val) {this.val val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val val;this.left …...

20240203在WIN10下使用GTX1080配置stable-diffusion-webui.git不支持float16精度出错的处理
20240203在WIN10下使用GTX1080配置stable-diffusion-webui.git不支持float16精度出错的处理 2024/2/3 21:23 缘起:最近学习stable-diffusion-webui.git,在Ubuntu20.04.6下配置SD成功。 不搞精简版本:Miniconda了。直接上Anacoda! …...

京东微前端框架MicroApp简介
一、MicroApp 1.1 MicroApp简介 MicroApp是由京东前端团队推出的一款微前端框架,它从组件化的思维,基于类WebComponent进行微前端的渲染,旨在降低上手难度、提升工作效率。MicroApp无关技术栈,也不和业务绑定,可以用于任何前端框架。 官网链接:https://micro-zoe.gith…...

SpringBoot 使用定时任务(SpringTask)
Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。 使用步骤: 1.导入坐标 在spring-boot-starter-web坐标中,就包含了SpringTask,所以一般的Web项目都包含了。 <depende…...

国标GB/T 28181详解:设备视音频文件检索消息流程
目 录 一、设备视音频文件检索 二、设备视音频文件检索的基本要求 三、命令流程 1、流程图 2、流程描述 四、协议接口 五、产品说明 六、设备视音频文件检索的作用 七、参考 在国标GBT28181中,定义了设备视音频文件检索消息的流程,主…...
openssl自签名CA根证书、服务端和客户端证书生成并模拟单向/双向证书验证
1. 生成根证书 1.1 生成CA证书私钥 openssl genrsa -aes256 -out ca.key 2048 1.2 取消密钥的密码保护 openssl rsa -in ca.key -out ca.key 1.3 生成根证书签发申请文件(csr文件) openssl req -new -sha256 -key ca.key -out ca.csr -subj "/CCN/STFJ/LXM/ONONE/OU…...

NIO Selector简介
1.Selector和Channel关系 Selector一般称为选择器,也叫多路复用器,NIO的核心组件,用于检查一个或多个Channel的状态是否处于可读、可写的状态。 2.可选择通道 (1)不是所有的channel都能被selector复用,…...
2023-12蓝桥杯STEMA考试 C++ 中高级试卷解析
蓝桥杯STEMA考试 C++ 中高级试卷(12月) 一、选择题 第一题 定义字符串 string a = "Hello C++",下列选项可以获取到字符 C 的是(B)。 A、a[7] B、a[6] C、a[5] D、a[4] 第二题 下列选项中数值与其它项不同的是( C)。 A、 B、 C、 D、 第三题 定义变量 int i =…...

设计模式——2_1 命令(Command)
文章目录 定义图纸一个例子:空调和他的遥控器只有控制面板的空调遥控器可以撤销的操作 碎碎念命令和Runnable命令和事务 定义 把请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持…...
HP数组面试题
PHP数组面试题 问题: 如何创建一个空数组和一个带有初始值的数组? 答案: 创建空数组:可以使用array()函数或空数组语法[]来创建一个空数组,例如$arr array();或$arr [];。创建带有初始值的数组:可以在创建…...
机器学习5-线性回归之损失函数
在线性回归中,我们通常使用最小二乘法(Ordinary Least Squares, OLS)来求解损失函数。线性回归的目标是找到一条直线,使得预测值与实际值的平方差最小化。 假设有数据集 其中 是输入特征, 是对应的输出。 线性回归的…...

vulhub中Adminer ElasticSearch 和 ClickHouse 错误页面SSRF漏洞复现(CVE-2021-21311)
Adminer是一个PHP编写的开源数据库管理工具,支持MySQL、MariaDB、PostgreSQL、SQLite、MS SQL、Oracle、Elasticsearch、MongoDB等数据库。 在其4.0.0到4.7.9版本之间,连接 ElasticSearch 和 ClickHouse 数据库时存在一处服务端请求伪造漏洞(…...

浅谈Zookeeper及windows下详细安装步骤
1. Zookeeper介绍 1.1 分布式系统面临的问题 分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。 面临的问题:系统每个节点之间信息同步及共享 以一个小团队为例,面临的问题 通过网络进行信息…...

vite, vue3, vue-router, vuex, ES6学习日记
学习使用vitevue3的所遇问题总结(2024年2月1日) 组件中使用<script>标签忘记加 setup 这会导致Navbar 没有暴露出来,导致使用不了,出现以下报错 这是因为,如果不用setup,就得使用 export default…...

25考研|660/880/1000/1800全年带刷计划
作为一个参加过两次研究生考试的老学姐,我觉得考研数学的难度完全取决于你自己 我自己就是一个很好的例子 21年数学题目是公认的简单,那一年考130的很多,但是我那一年只考了87分。但是22年又都说是有史以来最难的一年,和20年的难度…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...