1、Elasticsearch简介
- 一个分布式的、Restful风格的搜索引擎。
- 支持对各种类型的数据的检索。
- 搜索速度快,可以提供实时的搜索服务。
- 便于水平扩展,每秒可以处理PB级海量数据。
• Elasticsearch术语
- 索引、类型、文档、字段。
-
2、下载安装、配置与简单应用
下载链接:https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-4-3
1、下载完后直接解压
2、修改配置
cluster.name:nowcoder
path.data: d:/AAcommunity\data\elasticsearch6.4.3\data
path.logs: d:/AAcommunity\data\elasticsearch6.4.3\logs
3、配置bin目录的环境变量
4、下载中文分词插件
(1)github搜索elasticsearch ik
(2)将中文分词插件解压到elasticsearch安装目录下的plugins的新建目录ik下
5、下载postman
6、启动elasticsearch-》双击elasticseaarch.bat文件或执行命令elasticsearch.bat
7、查看健康状态命令:curl -X GET “localhost:9200/_cat/health?v
8、查看有什么节点:curl -X GET “localhost:9200/_cat/nodes?v”
9、查看有什么索引:curl -X GET “localhost:9200/_cat/indices?v”
10、创建索引:curl -X PUT “localhost:9200/test”
11、删除索引:curl -X DELETE “localhost:9200/test”
案例:
PUT
localhost:9200/test/_doc/1 “title”:”互联网求职” “content”:”寻求一份运营的岗位”
localhost:9200/test/_doc/2 “title”:”互联网招聘” “content”:”招聘一名资深程序员”
localhost:9200/test/_doc/3 “title”:”实习生推荐” “content”:”本人在一家互联网公司任职,可推荐实习开发岗位”
GET
localhost:9200/test/_search?q=title:互联网
localhost:9200/test/_search?q=content:运营实习
两者都检索的情况:localhost:9200/test/_search
{
“query”:{
“multi_match”:{
“query”:”互联网”
“fields”:[“title”,”content”]
}
}
}3、elasticsearch整合springboot
1、导入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency>
2、配置
#配置ElasticsearchPropertiesspring.data.elasticsearch.cluster-name=nowcoderspring.data.elasticsearch.cluster-nodes=localhost:9300
3、解决netty启动冲突问题
CommunityApplication.java@PostConstructpublic void init(){//解决netty启动冲突问题System.setProperty("es.set.netty.runtime.available.processors","false");}
4、配置对应实体类
DiscussPost.java@Data@AllArgsConstructor@NoArgsConstructor@ToString//版本:_doc 分片:6 副本:3@Document(indexName = "dicusspost",type="_doc",shards=6,replicas = 3)public class DiscussPost {@Idprivate int id;@Field(type = FieldType.Integer)private int userId;@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)private int type;//0普通1置顶@Field(type = FieldType.Integer)private int status;//0正常1精华2拉黑@Field(type = FieldType.Date)private Date createTime;@Field(type = FieldType.Integer)private int commentCount;@Field(type = FieldType.Double)private double score;}
5、创建DiscussPostRepository接口
@Repositorypublic interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost,Integer> {}
6、测试 ```java @Autowired private DiscussPostMapper discussMapper;
@Autowired private DiscussPostRepository discussRepository;
@Autowired private ElasticsearchTemplate elasticTemplate;
@Test public void testInsert() {
discussRepository.save(discussMapper.selectDiscussPostById(241));discussRepository.save(discussMapper.selectDiscussPostById(242));discussRepository.save(discussMapper.selectDiscussPostById(243));
}
@Test public 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));
}
@Test public void testUpdate() {
DiscussPost post = discussMapper.selectDiscussPostById(231);post.setContent("我是新人,使劲灌水.");discussRepository.save(post);
}
@Test public void testDelete() {
// discussRepository.deleteById(231);discussRepository.deleteAll();
}
@Test public 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)// 底层获取得到了高亮显示的值, 但是没有返回.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);}
}
@Test public 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();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());}});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);}
}
<a name="Uvbhn"></a># 4、开发搜索功能1、ElasticsearchService.java```java@Servicepublic class ElasticsearchService {@Autowiredprivate DiscussPostRepository discussPostRepository;@Autowiredprivate ElasticsearchTemplate elasticTemplate;/*** 存储帖子* @param post*/public void savePost(DiscussPost post){discussPostRepository.save(post);}/*** 删除帖子* @param id*/public void deletePost(int id){discussPostRepository.deleteById(id);}/*** 搜索帖子* @param keyword* @param current* @param limit* @return*/public Page<DiscussPost> search(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();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());}});}}
2、CommunityConstant
/*** 发帖*/String TOPIC_PUBLISH="publish";
3、DiscussPostController.java
在发布帖子接口中添加
// 触发发帖事件Event event = new Event().setTopic(TOPIC_PUBLISH).setUserId(user.getId()).setEntityType(ENTITY_TYPE_POST).setEntityId(post.getId());eventProducer.fireEvent(event);
4、CommentController
if(comment.getEntityType()==ENTITY_TYPE_POST){// 触发发帖事件event = new Event().setTopic(TOPIC_PUBLISH).setUserId(comment.getId()).setEntityType(ENTITY_TYPE_POST).setEntityId(discussPostId);eventProducer.fireEvent(event);}
5、EventConsumer.java
// 消费发帖事件@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());elasticsearchService.saveDiscussPost(post);}
6、SearchController
@Controllerpublic class SearchController implements CommunityConstant {@Autowiredprivate ElasticsearchService elasticsearchService;@Autowiredprivate UserService userService;@Autowiredprivate LikeService likeService;// search?keyword=xxx@RequestMapping(path = "/search", method = RequestMethod.GET)public 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.selectUserById(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";}}
7、页面(略)
index.html===>处理搜索框
search.html
