springboot 整合 Elasticsearch

Elasticsearch

一个分布式的搜索引擎
支持各种类型的数据检索
搜索速度快,可以提供实时的搜索服务
便于水平扩展,每秒可以处理BP级海量数据。

Elasticsearch术语意思
索引相当于数据库
类型数据库中的表(最新版本已弃用)
文档一行数据(相当于一个对象全部数据)
字段就是一列一个字段
  • 然后我们要学习Elasticsearch的话,先下载
  • 可以去 www.elastic.co 下载哦!

版本问题

  • 这里要注意一下哈,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
  • 让我们用起来更方便的 下载地址:www.getpostman.com

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(){
		// 解决netty启动冲突问题
		// see Netty4Utils.setAvailableProcessors()
		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));
    }
  • 这里我们可以使用 postMan 进行查询一下哈

在这里插入图片描述

  • 可以看出来,直接插入了一百多条哈!!

我们也可以利用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();
    }
  • 删除全部,慎用哈!!!
  • 回不来的那种哦!!

数据的查询(代码)

  • 这个要重要说明哈!
  • 我们对 “互联网招聘” 进行搜索, 在 titlecontent 字段里面查询
  • 然后先按 类型 排降序,再按 成绩 排降序, 再按 创建时间 排降序
  • 然后继续分页,从第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进行数据的增删改查了哈。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木不会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值