BBS论坛项目相关-12:ES搜索相关
ElasticSearch
Elasticsearch:分布式的Restful风格的搜索引擎
搜索速度快,可提供实时的搜索服务,便于水平扩展,每秒可以处理PB级海量数据
相关术语:
索引,类型,文档,字段
集群,节点,分片,副本
Springboot中声明的ES版本为6.4.3,9200端口
可以在IKAnalyzer.cfg.xml配置自己的dic字典文件
curl -X PUT “localhost:9200/test” 添加索引—返回json格式
curl -X GET “localhost:9200/_cat/indeces?v” 查找
curl -X DELETE “localhost:9200/test” 删除
POSTMAN
Spring整合Elasticsearch
引入依赖:spring-boot-starter-data-elasticsearch
配置Elasticsearch: cluster-name。cluster-nodes
spring.data.elasticsearch.cluster-name=nowcoder
spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300
Elasticsearch有两个端口,9200是http访问端口,9300是tcp端口
Redis和Elasticsearch底层都基于netty,在启动netty时会产生冲突,nettyRuntime默认如果已经调用,就不能再调用,所以Redis启动netty后,Elasticsearch再调用会认为netty已经启动就不再启动进而产生报错。所以在初始化中要将netty4utils中set设为false,(让他不再执行依赖扫描?)让netty可以被重复依赖。
@SpringBootApplication
public class CommunityApplication {
@PostConstruct//初始化回调方法
public void init() {
// 解决netty启动冲突问题
// see Netty4Utils.setAvailableProcessors()
System.setProperty("es.set.netty.runtime.available.processors", "false");
}
public static void main(String[] args) {
SpringApplication.run(CommunityApplication.class, args);
}
}
Spring Data Elasticsearch:ElasticsearchTemplate ElasticsearchRepository
把数据库中存储的帖子存在ES中,通过ElasticsearchRepository,spring自动生成,生成之前需要做一些配置,告诉它表和索引之间的对应关系,用什么方法实现搜索等,用注解实现
analyzer = "ik_max_word"
尽可能分成多的单词;
searchAnalyzer = "ik_smart"
搜索时尽量符合搜索时的词,尽量少分词
@Document(indexName = "discusspost", type = "_doc", shards = 6, replicas = 3)
public class DiscussPost {
@Id
private 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;
@Field(type = FieldType.Integer)
private int status;
@Field(type = FieldType.Date)
private Date createTime;
@Field(type = FieldType.Integer)
private int commentCount;
@Field(type = FieldType.Double)
private double score;
}
@Repository
针对数据访问层的接口
定义一个接口实现ElasticsearchRepository并指定泛型,接口要处理的实体类和主键类型
在索引中保存数据可直接调用discussRepository.save(discussMapper.selectDiscussPostById(241));
@Repository
public interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost, Integer> {
}
利用repository进行搜索,ES能把关键字高亮,将返回的关键词前后加上标签。
可通过NativeSearchQueryBuilder
自定义搜索功能,设置搜索的关键词,以及搜索结果排序等,按分页条件查询,以及高亮显示等
@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)
//Repository底层查到的数据用SearchResultMapper进行处理,要把两份数据组装在一起需要用mapper进行处理。
// Repository底层获取得到了高亮显示的值, 但是没有返回.
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);
}
}
用template方法实现高亮,查询到结果后用mapper进行处理
@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>