一、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. 发送邮件 1.0 三步走 1.1 邮箱设置 1.2 Spring Email 1.3 模板引擎 1.4 发送邮件的过程 1.5 检验发送邮件的过程 2. 开发注册功能 2.0 注册功能的步 ...

  2. 从零开始—仿牛客网讨论社区项目(六)

    主要技术架构: SpringBoot Spring SpringMVC MyBatis Redis Kakfa Elasticsearch Spring Security Spring Actator ...

  3. 从零开始—仿牛客网讨论社区项目(一)

    主要技术架构: SpringBoot Spring SpringMVC MyBatis Redis Kakfa Elasticsearch Spring Security Spring Actator ...

  4. 仿牛客网讨论社区项目—优化网站性能

    性能优化: 1.考虑加入缓存优化 优化热门帖子列表 GitHub中搜索caffeine 在Maven Repository搜索caffeine配置文件,在resources文件包内的pom.xml文件 ...

  5. 仿牛客网社区项目 全栈总结

    学习仿牛客网社区项目 代码&资源 各章节总结 第一章 第二章 第三章 第四章 第五章 第六章 第七章 第八章 争取让每个知识点都有链接可点 项目总结 网站架构图 常见面试题 MySQL Red ...

  6. 云服务器上部署仿牛客网项目

    云服务器上部署仿牛客网项目 安装JRE 安装Maven 安装MySQL 给mysql导入数据 安装Redis 安装kafka 安装ElasticSearch Wkhtmltopdf 安装tomcat ...

  7. 仿牛客网社区开发--核心功能模块

    1.过滤敏感词 我们想在某个网站上发布一些内容的时候,网站会对我们所发布的内容进行过滤,如果发现我的内容里包含一些色情.暴力等非法词汇,会把这些词汇隐去,即不显示或者打码,那么这种行为就叫过滤敏感词. ...

  8. Java牛客项目课_仿牛客网讨论区_第八章

    文章目录 第八章.项目发布与总结 8.1. 单元测试 8.2.项目监控 8.3.项目部署 宝塔面板.yum.rpm.压缩包 安装 unzip.Java1.8.Maven.MySQL.Redis.Kaf ...

  9. 仿牛客网项目第五,六章:异步消息系统和分布式搜索引擎(详细步骤和思路)

    目录 1. Kafka:构建TB级异步消息系统 1.0 同步/异步消息的区别 1.1 项目的目的 1. 2 阻塞队列实现异步消息系统 1.4 Kafka入门 1.5 Spring整合Kafka 1.6 ...

最新文章

  1. linux无法运行病毒,{转}为什么linux系统不容易中病毒?
  2. NLTK与NLP原理及基础
  3. 复旦大学高等数学期末试题合集
  4. Python——蟒蛇绘制
  5. 被遗忘的图灵:计算机、神经网络、人工智能……他是这一切之父
  6. 题目1005:Graduate Admission(结构体排序)
  7. C# 线程池ThreadPool
  8. HTTP 协议中 Vary 的一些研究
  9. 【jvm】java jvm 报错 OutOfMemoryError: GC overhead limit exceeded
  10. ubuntu16.04装机7: 挂载机械硬盘
  11. Process Kill Technology Process Protection Against In Linux
  12. 基于H5的移动端APP开发框架
  13. mac安装yarn的方法
  14. 学Excel,一辈子这门课就够了
  15. PE文件偏移地址分析
  16. 信创干部人事档案管理系统单机版 - 人力资源档案管理系统软件
  17. 正六边形:判断点是否在正六边形内
  18. “百度杯”CTF比赛 十一月场Look
  19. win10开机蓝屏_终级解决win10蓝屏代码WHEA_UNCORRECTABLE_ERROR没有之一 心语家园
  20. 重磅!中国商业联合会专家委员会商贸物流与供应链智库成立在即

热门文章

  1. python中ipo模型有,python ipo模型是指什么?-Python教程
  2. AS Library 使用NDK 的一些坑 Unable to strip library (+深入了解部分gradle机制)
  3. Ubuntu下使用ROS moveit 连接ABB机器人
  4. 软考-信息安全工程师(汇总1000题)
  5. 用ECharts生成统计图
  6. windows10应用商店打不开
  7. 超详细的Storyboard的解析——Objective-C(IOS)
  8. 被曝欠薪又放长假,600亿科技巨头爆雷了
  9. js: 动画 筋斗云导航栏 仿淘宝关闭二维码
  10. 如何写cover letter 翻译自How to write a cover letter