35 Spring整合Elasticsearch

这篇具有很好参考价值的文章主要介绍了35 Spring整合Elasticsearch。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Spring整合Elasticsearch

引入依赖

  • spring-boot-starter-data-elasticsearch
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
		</dependency>

配置Elasticsearch

  • cluster-name集群名
  • cluster-nodes集群节点
# ElasticsearchProperties
# 配置集群名,与es配置文件中的一致
spring.data.elasticsearch.cluster-name=nowcoder
# 集群节点,格式  节点ip地址:端口
spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300

解决冲突

如果项目中使用了redis,则需要解决冲突

es和redis都基于netty,这两者在启动netty时,会产生冲突:系统会认为redis已经启动了netty,es无法再启动

要尽可能在服务启动早期的时候,修改es.set.netty.runtime.available.processors为 false

修改入口类,因为入口类是最先被加载的

@PostConstruct: 管理bean的生命周期,主要用于初始化的方法,该注解修饰的方法在构造器调用完以后被执行

在这个初始化方法中修改系统属性就足够早

@SpringBootApplication
public class CommunityApplication {
	
    @PostConstruct
    public void init() {
        // 解决netty启动冲突问题
        // es.set.netty.runtime.available.processors 从 Netty4Utils.setAvailableProcessors() 中找到
        // 设置系统属性
        System.setProperty("es.set.netty.runtime.available.processors", "false");
    }

    public static void main(String[] args) {
        SpringApplication.run(CommunityApplication.class, args);
    }

}

使用Elasticsearch

Spring Data Elasticsearch

用于访问es服务器的API

  • ElasticsearchTemplate :有特殊情况,DiscussPostRepository处理不了时使用

  • ElasticsearchRepository: 接口,需要定义一个子接口继承他,声明访问哪些数据,Spring会自动实现这个接口

    所有的代码都是Spring自动生成的,Spring会自动将实体数据和es服务器的索引进行映射,因此需要用注解

    代码实例:

    // es可以看成特殊的数据库,因此加上注解@Repository
    // @Mapper是MyBa'ti'd专有注解
    // @Repository是spring提供的,针对数据访问层的注解
    @Repository
    // es的接口一般取名XXXRepository,该接口访问的是帖子,故叫DiscussPostRepository
    public interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost, Integer> {
        // 继承时要用泛型声明:当前接口要处理的实体类,以及实体类中的id类型
    
        // 父接口ElasticsearchRepository中 已经定义好了对es服务器访问的增删改查方法
        // 声明完泛型,加上注解之后,spring会自动实现自定义的子接口DiscussPostRepository
    }
    

建立映射关系

要对spring说明哪个实体类和es的索引怎样进行对应,建立映射关系,映射完成后,spring底层就可以帮我们生成实现类

  1. 用@Document指明 表 和 es 中索引的对应关系

    @Document ( indexName = “…”, type = “…”, shards = , replicas = )

    indexName: 实体数据映射到哪个索引上。通常为全小写的类名
    type: 实体数据映射到哪个类型上。类型已经在逐步被弱化甚至取消了,因此写成固定的 _doc
    shards: 创建几个分片。根据服务器处理能力配
    replicas: 创建几个副本。
    没有指定索引会创建这个索引,并且是根据指定分片和副本进行创建的

  2. 指明 实体中属性 和 es中字段 的对应关系

    给类中每个 属性 上加注解用于和 索引中的字段 相关联

​ 表的id属性要 加 @id 注解

    @Id // 与索引中id字段对应
    private int id;

​ 其他普通属性 加 @Field注解并指明字段类型

    // 用于普通字段,需指明字段类型
    @Field(type = FieldType.Integer)
    private int userId;

​ 当某些属性 对应的 es字段要用于关键词匹配时,需在注解中指明使用的analyzer和searchAnalyzer

​ analyzer为存储时候的解析器/分词器。

当我们存一句话时,会提取出关键词,并用关键词关联这句话,搜索时就可以通过关键词搜到这句话
因此存的时候,因该尽可能将一句话拆出尽可能多的关键词,以扩大搜索范围。
故需要一个范围非常大的分词器,而我们安装的中文分词器中存在这样的分词器——ik_max_word

​ searchAnalyzer为搜索时候解析器/分词器

搜索时,输入的句子不需要拆出过多关键词,不用拆的过细
如”互联网校招“,可以拆出:互联网、联网、网校、校招等关键词,但实际上我们没有这些意思
此时要使用拆分出尽可能少但满足用户需求的词语——ik_smart

    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String content;
// 将数据库中帖子存到es服务器里,就可以去es服务器中搜索这些帖子了
@Document(indexName = "discusspost", type = "_doc", shards = 6, replicas = 3)
public class DiscussPost {

    @Id // 与索引中id字段对应
    private int id;

    // userId为普通字段
    @Field(type = FieldType.Integer)
    private int userId;

    // 搜帖子主要在title和content中查找
    @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;

    // 不用在这些字段进行搜索,就不用analyzer和searchAnalyzer属性
    @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;
 }

常用方法

添加数据

一次添加一条数据:save(一条数据)

    @Test
    public void testInsert() {
        // 给es服务器添加数据:save(一条数据)
        // 在mysql中找到一条数据discussMapper.selectDiscussPostById(241),添加到es服务器
        // 不用特地创建索引,索引不存在时,es会帮我们自动创建
        discussRepository.save(discussMapper.selectDiscussPostById(241));
        discussRepository.save(discussMapper.selectDiscussPostById(242));
        discussRepository.save(discussMapper.selectDiscussPostById(243));
    }

一次添加多条数据:saveAll(多条数据)

    @Test
    public void testInsertList() {
        // 一次添加多条数据:saveAll(多条数据)
        // discussMapper.selectDiscussPosts(101, 0, 100) mysql分页查找
        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));
    }

修改数据

调用save方法将之前的数据再覆盖一遍

    @Test
    public void testUpdate() {
        // 查出第231条数据,修改属性
        DiscussPost post = discussMapper.selectDiscussPostById(231);
        post.setContent("我是新人,使劲灌水.");
        // 用save覆盖原来的
        discussRepository.save(post);
    }

删除数据

一次删除一条数据:deleteById( id )

    @Test
    public void testDelete() {
        discussRepository.deleteById(231);
    }

一次删除所有数据:deleteAll

风险高,不常用

    @Test
    public void testDelete() {
        discussRepository.deleteAll();
    }

搜索数据(es核心)

步骤
  1. 构造搜索条件 并 应用

    搜索条件:要不要排序、分页、结果要不要高亮显示等

    高亮显示:给关键词加em标签,在文本显示到网页上时,前端可以给em加样式

    搜索条件构造方式:SearchQuery对象,实现类是NativeSearchQuery,而NativeSearchQueryBuilder是一个可以构造NativeSearchQuery的工具类

            SearchQuery searchQuery = new NativeSearchQueryBuilder()
                    // 1)指定查询条件:withQuery
                    // 查询条件由QueryBuilders对象构造,multiMatchQuery用于指定查询关键词和查询字段范围
                    .withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
                    // 2)指定排序条件
                    // 优先按照置顶排序,再按分数(精品贴会被折算成分数),都相同就按创建时间排序
                    .withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
                    .withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
                    .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                    // 3)指定分页条件
                    .withPageable(PageRequest.of(0, 10))
                    // 4)指定给哪些字段里匹配词进行高亮显示
                    .withHighlightFields(
                            new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),
                            new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
                    )
                    // 5)执行,即应用搜索条件
                    .build();
    
  2. 进行查询

    分页查询结果用spring提供的Page对象接收
    Page中封装多个实体,即当前这一页的实体

    方法一:用Repository进行搜索

            Page<DiscussPost> page = discussRepository.search(searchQuery);
    

    存在问题:

    es返回结果包含:原始结果(即匹配到的结果) 和 高亮显示部分(即匹配到的关键词前后一部分内容,不是整个内容,不会浪费空间)
    需要将高亮显示部分整合到原始结果中,进行一个替换,太过麻烦,不够完善

    问题原因:

    查询方法discussRepository.search(searchQuery)的源码底层调用如下方法进行查询:

    elasticTemplate.queryForPage(searchQuery, class, SearchResultMapper)
    

    得到的两份数据,需要用SearchResultMapper进行组装,但默认实现类底层没有组装,即底层获取得到了高亮显示部分, 但是没有返回(结果里看不到).

    35 Spring整合Elasticsearch,spring,elasticsearch,java

    方法二:直接用ElasticsearchTemplate进行搜索

    elasticTemplate. queryForPage(搜索条件, 实体类型, 处理两部分结果合并问题的接口)
    

    通过匿名内部类方式,实现接口:

    new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
                    ... ...
                }
    }
    

    实现接口方法:

    1. 获取搜索命令查询结果

      通过response获取搜索命令的数据,可能会得到多条数据,放在SearchHits中

      SearchHits hits = response.getHits();
      
    2. 判断结果是否为空

      搜索命令返回结果的数据量,即返回结果有几条数据

      if (hits.getTotalHits() <= 0) {
          return null;
      }
      
    3. 遍历每一条数据,转成目标实体存储

      将这些实体存储在集合中List<DiscussPost> list

      for (SearchHit hit : hits)
      

      hits中每一条数据hit的形式如下

      35 Spring整合Elasticsearch,spring,elasticsearch,java

      1)处理非高亮显示内容:

      获取非高亮内容:

      es的返回数据是json格式,SearchHit对象里将json格式对象数据封装成了Map格式

      hit.getSourceAsMap():可以获取map形式数据,通过指定map的key可以调用每一个字段的值

      处理步骤:
      (1)对所有的字段,不管实际有没有高亮显示,都先获取非高亮显示版本

      不能直接获取高亮显示内容并存入实体,可能导致某些实体属性为空,因为不确定具体在哪个字段中匹配到关键字,某些字段可能没有匹配到关键字

      后续处理高亮显示数据时,会用有高亮显示的字段,覆盖 实体属性 原来的非高亮内容

      hit.getSourceAsMap().get("id")
      

      (2)再把 获取到的任何类型的数据 都转成 字符串

      String id = hit.getSourceAsMap().get("id").toString();
      

      (3)存到java实体中时,转为对应类型

      post.setId(Integer.valueOf(id));
      

      2)处理高亮显示内容

      获取高亮显示数据

      hit.getHighlightFields()
      

      (1)获取指定字段高亮显示数据

       HighlightField contentField = hit.getHighlightFields().get("content");
      

      高亮数据格式:

      35 Spring整合Elasticsearch,spring,elasticsearch,java

      (2)判断该字段是否有高亮显示数据:有些字段中没有关键字,就没有高亮内容

      if (contentField != null)
      

      (3)有高亮显示数据时,获取高亮内容第一段

      getFragments():返回值是个数组,将内容做了分段,每一段都是 匹配的词语 前后的一部分内容,如上图

      由于字段中匹配的词语可能是多个,因此我们只需要第一段设置高亮了就可以

      contentField.getFragments()[0].toString()
      

      (4)存入实体对应属性(此时就替换了属性中非高亮数据)

      post.setContent(contentField.getFragments()[0].toString());
      
    4. 返回一个包含 实体集合 的数据

      方法返回值是AggregatedPage类型
      因此为需要构造AggregatedPage接口的实现类AggregatedPageImpl
      实现类中会传多个参数,参数顺序需要看底层源码

      // list: 结果集合
      // pageable:方法的参数
      // hits.getTotalHits():数据总条数
      return new AggregatedPageImpl(list, pageable, hits.getTotalHits(), response.getAggregations(), response.getScrollId(), hits.getMaxScore());
      

    代码汇总文章来源地址https://www.toymoban.com/news/detail-840474.html

            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.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();
                        // String转Date:String-->Long-->Date
                        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());
                }
            });
    
  3. 使用查询结果
            // 一共查到多少数据匹配
            System.out.println(page.getTotalElements());
            // 一共有多少页
            System.out.println(page.getTotalPages());
            // 当前处在第几页
            System.out.println(page.getNumber());
            // 每一页显示多少条数据
            System.out.println(page.getSize());
            // 遍历Page中数据,逐一查看
            // Page继承了Iterable接口,可以被遍历
            for (DiscussPost post : page) {
                System.out.println(post);
            }
    

到了这里,关于35 Spring整合Elasticsearch的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring整合Elasticsearch(2)

            可以查询的范围更精确,当ElasticsearchRepository提供的基本方法无法满足我们所需要的查询可以使用原生的方式查询                 高亮查询的配置类,固定写法         高亮查询         高亮显示的字段可以将指定的字段添加标签,然后前端写样式来改变展示的样

    2024年02月16日
    浏览(34)
  • Spring Boot 整合Elasticsearch入门

    Spring Data Elasticsearch 是 Spring Data 项目的子项目,提供了 Elasticsearch 与 Spring 的集成。实现了 Spring Data Repository 风格的 Elasticsearch 文档交互风格,让你轻松进行 Elasticsearch 客户端开发。 应粉丝要求特地将 Elasticsearch 整合到 Spring Boot  中去。本来打算整合到 kono 脚手架中,但是转

    2024年04月13日
    浏览(46)
  • spring boot es | spring boot 整合elasticsearch | spring boot整合多数据源es

    目录 Spring Boot与ES版本对应 Maven依赖 配置类 使用方式 @Test中注入方式 @Component中注入方式 查询文档 实体类 通过ElasticsearchRestTemplate查询 通过JPA查询 保存文档 参考链接 项目组件版本: Spring Boot:2.2.13.RELEASE Elasticsearch:6.8.0 JDK:1.8.0_66 Tips: 主要看第3列和第5列,根据ES版本选择

    2023年04月18日
    浏览(59)
  • 使用ElasticsearchRepository和ElasticsearchRestTemplate操作Elasticsearch,Spring Boot整合Elasticsearch

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Elasticsearch官网参考文档:https://www.elastic.co/guide/index.html Elasticsearch官方下载地址:https://www.elastic.co/cn/downloads/elasticsearch https://docs.spring.io/spring-data/elasticsearch/reference/ 添加依赖 修改yml配置文件 【自定义

    2024年04月22日
    浏览(48)
  • Spring Boot整合Elasticsearch超详细教程

    SpringBoot整合Elasticsearch超详细教程 最新高级版 (1)导入springboot整合ES高级别客户端的坐标 (2)使用编程的形式设置连接的ES服务器,并获取客户端对象 (3)Book实体类 (4)连接Dao层 (5)使用客户端对象操作ES 例如创建索引:(这里需要先执行上面的删除索引操作,否则会报错)

    2023年04月09日
    浏览(53)
  • Spring Boot进阶(19):Spring Boot 整合ElasticSearch | 超级详细,建议收藏

            ElasticSearch是一款基于Lucene的开源搜索引擎,具有高效、可扩展、分布式的特点,可用于全文搜索、日志分析、数据挖掘等场景。Spring Boot作为目前最流行的微服务框架之一,也提供了对ElasticSearch的支持。本篇文章将介绍如何在Spring Boot项目中整合ElasticSearch,并展

    2024年02月06日
    浏览(46)
  • 在Spring Boot中整合Elasticsearch并实现高亮搜索

    本文详细介绍了如何在Spring Boot项目中整合Elasticsearch,实现高亮搜索功能。通过添加依赖、配置Spring Boot、为实体类添加注解,以及在Service层实现高亮搜索,读者能够了解如何在实际项目中利用Spring Boot Data Elasticsearch来操作Elasticsearch并实现高亮搜索。验证示例演示了如何使用RESTful API端点来搜索并获取包含高亮字段的用户列表,为读者提供了实际应用的参考。这篇文章将帮助读者轻松掌握Spring Boot与Elasticsearch的整合方法,从而为项目增加强大的搜索功能。

    2024年02月06日
    浏览(42)
  • Springboot --- 整合spring-data-jpa和spring-data-elasticsearch

    SpringBoot: 整合Ldap. SpringBoot: 整合Spring Data JPA. SpringBoot: 整合Elasticsearch. SpringBoot: 整合spring-data-jpa和spring-data-elasticsearch. SpringBoot: 整合thymeleaf. SpringBoot: 注入第三方jar包. SpringBoot: 整合Redis. SpringBoot: 整合slf4j打印日志. SpringBoot: 整合定时任务,自动执行方法. SpringBoot: 配置多数据源

    2023年04月25日
    浏览(73)
  • 知识点13--spring boot整合elasticsearch以及ES高亮

    本章知识点沿用知识点12的项目,介绍如何使用spring boot整合ES,没有ES的去我主页 各类型大数据集群搭建文档--大数据原生集群本地测试环境搭建三 中可以看到ES如何搭建 不管你有没有ES,最好是没有,因为一定要知道一点,一定要去官网查一下你当前用的spring boot data es的版

    2024年02月12日
    浏览(56)
  • 统一日志管理方案:Spring项目logback日志与logstash和Elasticsearch整合

    原创/朱季谦 最近在做一个将分布式系统的日志数据通过logstash传到kafka的功能,做完之后决定业余搭一个ELK日志分析系统,将logstash采集到的日志传给Elasticsearch。经过一番捣鼓,也把这个过程给走通了,于是写了这篇总结,可按照以下步骤搭建logstash采集spring日志数据并传输

    2024年02月03日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包