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相關包:參考鏈接
- 查看節點具體信息
- 查看索引相關信息
新裝的沒有索引:
- 創建索引
查看狀態顯示yellow是因為沒有分片(備份)。
- 刪除索引
使用Postman/RESTer訪問ES
RESTer是火狐插件也很好用。
- 查索引
- 建索引
- 刪除索引
- 提交數據
- 查數據
- 改數據
和添加數據一樣,底層會先刪除再添加
- 刪除數據
-
搜索功能的演示
-
- 先插入一些數據
- 先插入一些數據
-
開始搜索演示
搜索時會先分詞然后搜索,并不一定完全匹配
二、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:93002.解決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 仿牛客网第六章的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: e最著名的形容美女的词语
- 下一篇: 计算机网络多项式的定义,多项式的定义与概