Elasticsearch
一个分布式的搜索引擎 支持各种类型的数据检索 搜索速度快,可以提供实时的搜索服务 便于水平扩展,每秒可以处理BP级海量数据。
Elasticsearch术语 | 意思 |
---|
索引 | 相当于数据库 | 类型 | 数据库中的表(最新版本已弃用) | 文档 | 一行数据(相当于一个对象全部数据) | 字段 | 就是一列一个字段 |
版本问题
- 这里要注意一下哈,7.0后的版本开始逐步遗弃掉类型的概念,用索引来代替拉,
- 但是俺还是用6.4.3的版本试试吧。
- 文件下载下来,就是一个压缩包哈,解压即可!
- 解压后以后呢,我们要对config配置文件进行配置一下哈。
- 进去后,打开 elasticsearch.yml 文件哈,然后进行如下配置即可
分词软件
那么啥是分词呢? 举个例子: 互联网招聘 我要所搜互联网招聘,那么我们就要将其分成 互联、联网、网招、招聘、互联网等等。 这样匹配多的那就放在最前面,方便我们的搜索!!
- 但是哈,下载的elasticsearch只有对英文的分词,没有中文的,所以我们还要进行下载一个对中文分词的插件
- 这个插件可以去 github 上下载哈,直接搜索 elasticsearch ik 即可,一般第一个就是。
- 然后我们要找到和自己下载的elastic版本相同的分词版本哈!!
- 这个也是个压缩包,你解压到 原来elasticsearch文件里面的 插件文件plugins 下面的 ik文件夹下即可。(ik文件夹自己创建哈)
- 到这里,我们就可以使用命令行,进行操作了,(记得将里面bin路径存放到环境变量里面去哈!)
bin路径下的 elasticsearch.bat 文件可以启动服务器,不用的时候直接关掉就行
- 完成后,我们就可以在cmd里面进行简单的测试了
- 我们可以试试以下命令
# 查看该es服务器的健康状态
curl -X GET "localhost:9200/_cat/health?v"
# 查看节点
curl -X GET "localhost:9200/_cat/nodes?v"
# 查看索引
curl -X GET "localhost:9200/_cat/indeces?v"
# 创建索引
curl -X PUT "localhost:9200/test"
# 删除索引
curl -X DELETE "localhost:9200/test"
postMan
- 先利用命令向里面存放点东西 localhost:9200/test/_doc/3
- 这里,我们 test索引 里面就会有数据了,记得看清哈,我们使用的是Body里面的raw里面,数据采用JSON进行传输即可。
- 然后采用 localhost:9200/test/_search 命令进行数据的分词搜索
- 这不比cmd舒服?啊哈哈哈哈哈
- 搞定这些,我们就可以进行数据的整合啦!
spring 整合 Elasticsearch
三步走: 一、 引入依赖 二、 对Elasticsearch进行配置 三、 使用Spring Data Elasticsearch
一、引入依赖
- 因为是spring boot项目,所以他的上面会有他自己调试好的版本,所以我们不需要写版本号
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
二、 配置Elasticsearch
- 在 application.properties 里面配置
# ElasticsearchProperties
spring.data.elasticsearch.cluster-name=nowcoder
spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300
- 这里的cluster-name 就是前面配置的时候配置的。
- Elasticsearch将绑定到HTTP和节点/传输API的单个端口。
- 它会先尝试最低的可用端口,如果已经被使用,请尝试下一个端口。如果在机器上运行单个节点,则只能绑定到9200和9300。
端口的区别
9200用于外部通讯,基于http协议,程序与es的通信使用9200端口。 9300jar之间就是通过tcp协议通信,遵循tcp协议,es集群中的节点之间也通过9300端口进行通信。
三、 使用 Spring Data Elastisearch (6.4.3版本)
这里它有两个类可以使用哈!
- ElasticsearchTemplate
- ElasticsearchRepository
后者使用起来方便一点,所以我们使用后者哈!(高版本前者已经被取消了)
ElasticSearchRepository
- 先对我们的实体进行加注解,这样就能达到一个 映射 的目的
- 这里我们主要是对帖子进行查询,所以我们对帖子实体类进行加注解
@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;
- 最上面的四个,分别表示: 索引 、 文档 、 节点数 、 副本数
- id是设置主键哈,其余的跟着套用就行。
- 要查询的字段是 title 和content 所以我们还要设置他的查询方式。
- Elasticsearch 其实就是一个特殊的数据库,所以我们也要搞一个数据访问层
- 可以看出哈,这个不需要我们做什么,只需要加个注解,然后继承个ElasticsearchRepository类,然后设置下泛型即可。
- Mapper注解式 mybatis 专属的哈, Repository 才是 spring提供的数据访问层的注解哈!
冲突问题
available processors value [%d] did not match current value [%d]
- 这个我们要看看 Netty4Utils 类里面啦
- 原因就是原来的 Redis 服务将这个给占用了,然后我们的es也依赖这个,所以就冲突了,但是还好,人家给了解决方法,将那个类设置为false即可跳过这个检查!!!
- 但是在初始化的时候完成,所以这个时候,我们就可以用上 @PostPostConstruct 注解来完成初始化。我们写在CommunityApplication里面的哈
@SpringBootApplication
public class CommunityApplication {
@PostConstruct
public void init(){
System.setProperty("es.set.netty.runtime.available.processors","false");
}
public static void main(String[] args) {
SpringApplication.run(CommunityApplication.class, args);
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class ElasticsearchTests {
@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));
}
- 这样通过id就可将这个帖子存放进去。而他的 索引 就是 discusspost,在上面的实体类上的注解已经定义过啦!!
先来存多条数据
@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));
}
我们也可以利用Repository的save进行数据的修改
@Test
public void testUpdate(){
DiscussPost post = discussMapper.selectDiscussPostById(231);
post.setContent("我是大帅哥,请使劲灌水!!!");
discussRepository.save(post);
}
数据的删除
@Test
public void testDelete(){
discussRepository.deleteById(231);
discussRepository.deleteAll();
}
数据的查询(代码)
- 这个要重要说明哈!
- 我们对 “互联网招聘” 进行搜索, 在 title 和 content 字段里面查询
- 然后先按 类型 排降序,再按 成绩 排降序, 再按 创建时间 排降序
- 然后继续分页,从第0页,每页搞10 条
@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();
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);
}
}
数据的高亮显示
- 原理就是再关键字左右加上一个 < em> 标签,然后到页面的时候,利用css进行样式的调节即可。
- 有点长,这个
@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() {
@Override
public <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.parseInt(id));
String userId = hit.getSourceAsMap().get("userId").toString();
post.setUserId(Integer.parseInt(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.parseInt(status));
String createTime = hit.getSourceAsMap().get("createTime").toString();
post.setCreateTime(new Date(Long.parseLong(createTime)));
String commentCount = hit.getSourceAsMap().get("commentCount").toString();
post.setCommentCount(Integer.parseInt(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);
}
}
- 而且是使用elasticTemplate 的 queryForPage 方法搞定的,这个高版本已经没有了哦,
- 所以要用的话,记得下载6.*的版本哈。
到这里就完成了利用elasticsearch进行数据的增删改查了哈。
|