2021-04-10 仿牛客网第六章
一、Elasticsearch入门
仿牛客网
内容部分引用至 https://blog.csdn.net/weixin_44406146
目录
- 一、Elasticsearch入门
- Elasticsearch配置
- 安装中文分词插件
- 安装Postman模拟网页访问
- 使用命令行操作Elasticsearch
- 使用Postman/RESTer访问ES
- 二、Spring整合Elasticsearch
- 导包
- 配置
- 写数据层
- 测试一波
- 三、开发社区搜索功能
- ElasticsearchService
- 处理DiscussPostController.addDiscussPost
- 处理CommentController.addComment
- EventConsumer写一个消费发帖事件的方法
- 新写一个SearchController
- 处理页面index处理搜索框
- 处理页面search
Elasticsearch简介
- 一个分布式的、Restful风格的搜索引擎。
- 支持对各种类型的数据的检索。
- 搜索速度快,可以提供实时的搜索服务。
- 便于水平扩展,每秒可以处理PB级海量数据。
Elasticsearch术语
- 索引、类型、文档、字段。
- 集群、节点、分片、副本。
术语的解释
- 索引:相当于数据库中的database 改版后作为table
- 类型:相当于数据库中的table 不再使用
- 文档:相当于数据库中的一行数据,数据结构为JSON
- 字段:相当于数据库中的一列
Elasticsearch6.0以后开始逐步废除类型的概念,索引的含义中也包括了类型。
- 集群:分布式部署,提高性能
- 节点:集群中的每一台服务器
- 分片:对一个索引的进一步划分存储,提高并发处理能力
- 副本:对分片的备份,提高可用性
Elasticsearch相关链接:官网
Elasticsearch选择下载6.4.3版本和SpringBoot兼容
Elasticsearch配置
文件位置config/elasticsearch.yml
配置环境变量
安装中文分词插件
github上找
解压到指定目录下
ik插件配置文件说明
IKAnalyzer.cfg 可以自己配置新词
安装Postman模拟网页访问
Postman相关链接:官网
使用命令行操作Elasticsearch
1.启动ES—./bin/elasticsearch.bat
2.常用命令介绍
- 查看节点健康状态
curl -X GET "localhost:9200/_cat/health?v"
这个命令需要下载curl相关包:参考链接
- 查看节点具体信息
curl -X GET "localhost:9200/_cat/nodes?v"
- 查看索引相关信息
curl -X GET "localhost:9200/_cat/indices?v"
新装的没有索引:
- 创建索引
curl -X PUT "localhost:9200/test" //test就是索引名字
查看状态显示yellow是因为没有分片(备份)。
- 删除索引
curl -X DELETE "localhost:9200/test" //test就是索引名字
使用Postman/RESTer访问ES
RESTer是火狐插件也很好用。
- 查索引
- 建索引
- 删除索引
- 提交数据
//test:索引 _doc:固定格式 1:id号 然后在请求body中写数据
PUT localhost:9200/test/_doc/1
- 查数据
GET localhost:9200/test/_doc/1
- 改数据
和添加数据一样,底层会先删除再添加
- 删除数据
DELETE localhost:9200/test/_doc/1
搜索功能的演示
- 先插入一些数据
- 先插入一些数据
开始搜索演示
搜索时会先分词然后搜索,并不一定完全匹配
二、Spring整合Elasticsearch
引入依赖
- spring-boot-starter-data-elasticsearch
配置Elasticsearch
- cluster-name、cluster-nodes
Spring Data Elasticsearch
- ElasticsearchTemplate
- ElasticsearchRepository
导包
<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-elasticsearch</artifactId>
</dependency>
配置
1.application.properties
spring:data:elasticsearch:cluster-name: nowcodercluster-nodes: 127.0.0.1:9300
2.解决Netty冲突问题
问题原因:Redis底层使用了Netty,Elasticsearch也用了Netty,当被注册两次就会报错
解决思路:Elasticsearch中注册Netty前会判断有无一个参数,如果有就不注册
这么解决:
3.给discussPost加注解
//indexName:索引名,type:固定_doc,shards:分片,replicas:备份
@Document(indexName = "discusspost",type = "_doc",shards =6 ,replicas = 2)
public class DiscussPost {@Idprivate int id;@Field(type = FieldType.Integer)private int userId;//analyzer:互联网校招--->建立最大的索引(就是各种拆分)//searchAnalyzer 拆分尽可能少的满足意图的分词器@Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_smart")private String title;@Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_smart")private String content;@Field(type = FieldType.Integer)//0-普通; 1-置顶;private int type;@Field(type = FieldType.Integer)//0-正常; 1-精华; 2-拉黑;private int status;@Field(type = FieldType.Date)private Date createTime;@Field(type = FieldType.Integer)private int commentCount;@Field(type = FieldType.Double)private double score;
写数据层
在dao下建立子包elasticsearch,并创建DiscussPostRepository接口
测试一波
Elasticsearch中配置再加一个这个:
elasticsearch包不要放在dao包下边,会导致bean注入失败。
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class ElasticsearchTest {@Autowiredprivate DiscussPostMapper discussMapper;@Autowiredprivate DiscussPostRepository discussRepository;//有些功能上边的解决不了,所以引入下边的@Autowiredprivate ElasticsearchTemplate elasticTemplate;@Testpublic void testInsert() {discussRepository.save(discussMapper.selectDiscussPostById(271));discussRepository.save(discussMapper.selectDiscussPostById(272));discussRepository.save(discussMapper.selectDiscussPostById(273));}@Testpublic void testInsertList() {discussRepository.saveAll(discussMapper.selectDiscussPosts(101, 0, 100));discussRepository.saveAll(discussMapper.selectDiscussPosts(102, 0, 100));discussRepository.saveAll(discussMapper.selectDiscussPosts(103, 0, 100));discussRepository.saveAll(discussMapper.selectDiscussPosts(111, 0, 100));discussRepository.saveAll(discussMapper.selectDiscussPosts(112, 0, 100));discussRepository.saveAll(discussMapper.selectDiscussPosts(131, 0, 100));discussRepository.saveAll(discussMapper.selectDiscussPosts(132, 0, 100));discussRepository.saveAll(discussMapper.selectDiscussPosts(133, 0, 100));discussRepository.saveAll(discussMapper.selectDiscussPosts(134, 0, 100));}//localhost:9200/discusspost/_doc/231@Testpublic void testUpdate() {DiscussPost post = discussMapper.selectDiscussPostById(231);post.setContent("我是新人,使劲灌水.");discussRepository.save(post);}@Testpublic void testDelete() {discussRepository.deleteById(231);//discussRepository.deleteAll();}@Testpublic void testSearchByRepository() {SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content")).withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC)) //按字段排序.withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC)).withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC)).withPageable(PageRequest.of(0, 10)) //分页.withHighlightFields(new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")).build();// 底层调用:elasticTemplate.queryForPage(searchQuery, class, SearchResultMapper)// 底层获取得到了高亮显示的值, 但是没有返回.所以为了得到高亮显示直接用elasticTemplate.queryForPage见下面Page<DiscussPost> page = discussRepository.search(searchQuery);System.out.println(page.getTotalElements());System.out.println(page.getTotalPages());System.out.println(page.getNumber());System.out.println(page.getSize());for (DiscussPost post : page) {System.out.println(post);}}@Testpublic void testSearchByTemplate() {SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content")).withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC)).withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC)).withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC)).withPageable(PageRequest.of(0, 10)).withHighlightFields(new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")).build();Page<DiscussPost> page = elasticTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {@Overridepublic <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {SearchHits hits = response.getHits();if (hits.getTotalHits() <= 0) {return null;}List<DiscussPost> list = new ArrayList<>();for (SearchHit hit : hits) {DiscussPost post = new DiscussPost();String id = hit.getSourceAsMap().get("id").toString();post.setId(Integer.valueOf(id));String userId = hit.getSourceAsMap().get("userId").toString();post.setUserId(Integer.valueOf(userId));String title = hit.getSourceAsMap().get("title").toString();post.setTitle(title);String content = hit.getSourceAsMap().get("content").toString();post.setContent(content);String status = hit.getSourceAsMap().get("status").toString();post.setStatus(Integer.valueOf(status));String createTime = hit.getSourceAsMap().get("createTime").toString(); //long类型的字符串post.setCreateTime(new Date(Long.valueOf(createTime)));String commentCount = hit.getSourceAsMap().get("commentCount").toString();post.setCommentCount(Integer.valueOf(commentCount));// 处理高亮显示的结果HighlightField titleField = hit.getHighlightFields().get("title");if (titleField != null) {post.setTitle(titleField.getFragments()[0].toString());}HighlightField contentField = hit.getHighlightFields().get("content");if (contentField != null) {post.setContent(contentField.getFragments()[0].toString());}list.add(post);}return new AggregatedPageImpl(list, pageable,hits.getTotalHits(), response.getAggregations(), response.getScrollId(), hits.getMaxScore());}@Overridepublic <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {return null;}});System.out.println(page.getTotalElements());System.out.println(page.getTotalPages());System.out.println(page.getNumber());System.out.println(page.getSize());for (DiscussPost post : page) {System.out.println(post);}}
}
三、开发社区搜索功能
搜索服务
- 将帖子保存至Elasticsearch服务器。
- 从Elasticsearch服务器删除帖子。
- 从Elasticsearch服务器搜索帖子。
发布事件
- 发布帖子时,将帖子异步的提交到Elasticsearch服务器。
- 增加评论时,将帖子异步的提交到Elasticsearch服务器。
- 在消费组件中增加一个方法,消费帖子发布事件。
显示结果
- 在控制器中处理搜索请求,在HTML上显示搜索结果。
一个小问题的解决
ElasticsearchService
@Service
public class ElasticsearchService {@Autowiredprivate DiscussPostRepository discussPostRepository;@Autowiredprivate ElasticsearchTemplate elasticTemplate;//高亮显示//添加、修改public void saveDiscussPost(DiscussPost discussPost){discussPostRepository.save(discussPost);}//删除public void deleteDiscussPost(int id){discussPostRepository.deleteById(id);}//查询public Page<DiscussPost> searchDiscussPost(String keyword,int current,int limit){SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "content")).withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC)).withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC)).withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC)).withPageable(PageRequest.of(current, limit)).withHighlightFields(new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")).build();return elasticTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {@Overridepublic <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {SearchHits hits = response.getHits();if (hits.getTotalHits() <= 0) {return null;}List<DiscussPost> list = new ArrayList<>();for (SearchHit hit : hits) {DiscussPost post = new DiscussPost();String id = hit.getSourceAsMap().get("id").toString();post.setId(Integer.valueOf(id));String userId = hit.getSourceAsMap().get("userId").toString();post.setUserId(Integer.valueOf(userId));String title = hit.getSourceAsMap().get("title").toString();post.setTitle(title);String content = hit.getSourceAsMap().get("content").toString();post.setContent(content);String status = hit.getSourceAsMap().get("status").toString();post.setStatus(Integer.valueOf(status));String createTime = hit.getSourceAsMap().get("createTime").toString(); //long类型的字符串post.setCreateTime(new Date(Long.valueOf(createTime)));String commentCount = hit.getSourceAsMap().get("commentCount").toString();post.setCommentCount(Integer.valueOf(commentCount));// 处理高亮显示的结果HighlightField titleField = hit.getHighlightFields().get("title");if (titleField != null) {post.setTitle(titleField.getFragments()[0].toString());}HighlightField contentField = hit.getHighlightFields().get("content");if (contentField != null) {post.setContent(contentField.getFragments()[0].toString());}list.add(post);}return new AggregatedPageImpl(list, pageable,hits.getTotalHits(), response.getAggregations(), response.getScrollId(), hits.getMaxScore());}@Overridepublic <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {return null;}}); }
}
处理DiscussPostController.addDiscussPost
处理CommentController.addComment
EventConsumer写一个消费发帖事件的方法
@KafkaListener(topics = {TOPIC_PUBLISH})public void handlePublishMessage(ConsumerRecord record){if(record==null||record.value()==null){logger.error("消息的内容为空");return;}Event event = JSONObject.parseObject(record.value().toString(),Event.class);if(event==null){logger.error("消息格式错误");return;}//查询出这个帖子DiscussPost post = discussPostService.findDiscussPostById(event.getEntityId());//往es中存数据elasticsearchService.saveDiscussPost(post);}
新写一个SearchController
@Controller
public class SearchController implements CommunityContant {@Autowiredprivate ElasticsearchService elasticsearchService;@Autowiredprivate UserService userService;@Autowiredprivate LikeService likeService;@RequestMapping(path="/search",method = RequestMethod.GET)//路径 search?keyword=xxxpublic String search(String keyword, Page page, Model model){//搜索帖子org.springframework.data.domain.Page<DiscussPost> searchResult = elasticsearchService.searchDiscussPost(keyword, page.getCurrent() - 1, page.getLimit());//聚合数据List<Map<String,Object>> discussPosts = new ArrayList<>();if(searchResult!=null){for(DiscussPost post:searchResult){Map<String,Object> map = new HashMap<>();//帖子map.put("post",post);//作者map.put("user",userService.findUserById(post.getUserId()));//点赞数量map.put("likeCount",likeService.findEntityLikeCount(ENTITY_TYPE_POST,post.getId()));discussPosts.add(map);}}model.addAttribute("discussPosts",discussPosts);model.addAttribute("keyword",keyword);//分页信息page.setPath("/search?keyword="+keyword);page.setRows(searchResult==null?0:(int)searchResult.getTotalElements());return "/site/search";}
}
处理页面index处理搜索框
处理页面search
2021-04-10 仿牛客网第六章相关推荐
- 仿牛客网项目第二章:开发社区登录模块(详细步骤和思路)
目录 1. 发送邮件 1.0 三步走 1.1 邮箱设置 1.2 Spring Email 1.3 模板引擎 1.4 发送邮件的过程 1.5 检验发送邮件的过程 2. 开发注册功能 2.0 注册功能的步 ...
- 从零开始—仿牛客网讨论社区项目(六)
主要技术架构: SpringBoot Spring SpringMVC MyBatis Redis Kakfa Elasticsearch Spring Security Spring Actator ...
- 从零开始—仿牛客网讨论社区项目(一)
主要技术架构: SpringBoot Spring SpringMVC MyBatis Redis Kakfa Elasticsearch Spring Security Spring Actator ...
- 仿牛客网讨论社区项目—优化网站性能
性能优化: 1.考虑加入缓存优化 优化热门帖子列表 GitHub中搜索caffeine 在Maven Repository搜索caffeine配置文件,在resources文件包内的pom.xml文件 ...
- 仿牛客网社区项目 全栈总结
学习仿牛客网社区项目 代码&资源 各章节总结 第一章 第二章 第三章 第四章 第五章 第六章 第七章 第八章 争取让每个知识点都有链接可点 项目总结 网站架构图 常见面试题 MySQL Red ...
- 云服务器上部署仿牛客网项目
云服务器上部署仿牛客网项目 安装JRE 安装Maven 安装MySQL 给mysql导入数据 安装Redis 安装kafka 安装ElasticSearch Wkhtmltopdf 安装tomcat ...
- 仿牛客网社区开发--核心功能模块
1.过滤敏感词 我们想在某个网站上发布一些内容的时候,网站会对我们所发布的内容进行过滤,如果发现我的内容里包含一些色情.暴力等非法词汇,会把这些词汇隐去,即不显示或者打码,那么这种行为就叫过滤敏感词. ...
- Java牛客项目课_仿牛客网讨论区_第八章
文章目录 第八章.项目发布与总结 8.1. 单元测试 8.2.项目监控 8.3.项目部署 宝塔面板.yum.rpm.压缩包 安装 unzip.Java1.8.Maven.MySQL.Redis.Kaf ...
- 仿牛客网项目第五,六章:异步消息系统和分布式搜索引擎(详细步骤和思路)
目录 1. Kafka:构建TB级异步消息系统 1.0 同步/异步消息的区别 1.1 项目的目的 1. 2 阻塞队列实现异步消息系统 1.4 Kafka入门 1.5 Spring整合Kafka 1.6 ...
最新文章
- linux无法运行病毒,{转}为什么linux系统不容易中病毒?
- NLTK与NLP原理及基础
- 复旦大学高等数学期末试题合集
- Python——蟒蛇绘制
- 被遗忘的图灵:计算机、神经网络、人工智能……他是这一切之父
- 题目1005:Graduate Admission(结构体排序)
- C# 线程池ThreadPool
- HTTP 协议中 Vary 的一些研究
- 【jvm】java jvm 报错 OutOfMemoryError: GC overhead limit exceeded
- ubuntu16.04装机7: 挂载机械硬盘
- Process Kill Technology Process Protection Against In Linux
- 基于H5的移动端APP开发框架
- mac安装yarn的方法
- 学Excel,一辈子这门课就够了
- PE文件偏移地址分析
- 信创干部人事档案管理系统单机版 - 人力资源档案管理系统软件
- 正六边形:判断点是否在正六边形内
- “百度杯”CTF比赛 十一月场Look
- win10开机蓝屏_终级解决win10蓝屏代码WHEA_UNCORRECTABLE_ERROR没有之一 心语家园
- 重磅!中国商业联合会专家委员会商贸物流与供应链智库成立在即
热门文章
- python中ipo模型有,python ipo模型是指什么?-Python教程
- AS Library 使用NDK 的一些坑 Unable to strip library (+深入了解部分gradle机制)
- Ubuntu下使用ROS moveit 连接ABB机器人
- 软考-信息安全工程师(汇总1000题)
- 用ECharts生成统计图
- windows10应用商店打不开
- 超详细的Storyboard的解析——Objective-C(IOS)
- 被曝欠薪又放长假,600亿科技巨头爆雷了
- js: 动画 筋斗云导航栏 仿淘宝关闭二维码
- 如何写cover letter 翻译自How to write a cover letter