从零搭建Spring Boot脚手架(7):Elasticsearch应该独立服务

1,468 阅读5分钟

1. Spring Data Elasticsearch

Spring Data ElasticsearchSpring Data项目的子项目,提供了ElasticsearchSpring的集成。实现了Spring Data Repository风格的Elasticsearch文档交互风格,让你轻松进行Elasticsearch客户端开发。

2. 个人的一些看法

应粉丝要求特地将Elasticsearch整合到Spring Boot 中去。本来打算整合到kono脚手架中,但是转念一想这样并不是非常合适,一般搜索建议作为一个独立的平台运作,小公司可作为一个独立的服务,大公司可作为一个搜索中台。一般我认为虽然Elasticsearch提供了搜索功能,大部分情况下我们并不像常规的关系型数据库一样进行直接写入,而是通过同步的方式进行同步或者预热写入数据。

数据通过Logstash同步到ES

具体的架构不是本文要讲的,在ES的CSDN官方博客里面有比较具体的解决方案。本文是在你已经搭建好Elasticsearch集群的前提下进行的。

2. 版本对应

相关项目的版本对应关系如下:

Spring Data Release TrainSpring Data ElasticsearchElasticsearchSpring Boot
Neumann4.0.x7.6.22.3.x
Moore3.2.x6.8.62.2.x
Lovelace3.1.x6.2.22.1.x
Kay3.0.x5.5.02.0.x
Ingalls2.1.x2.4.01.5.x

根据我平常的做法,我选择Elasticsearch 7.6.2Spring Boot 2.3.3作为版本基准进行集成。

3. 依赖引入及配置

只需要引入下面的依赖就可以集成Elasticsearch :

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

关于配置有两种一种面向传统的Restful:

spring:
  elasticsearch:
    rest:
      # 逗号分隔的Elasticsearch实例使用的列表 
      uris: http://localhost:9200
      # 链接超时时间
      connection-timeout:
      # 读取超时时间
      read-timeout:
      # ES 用户名
      username:
      # ES 密码
      password:

如果你都采用默认的配置,可以什么都不配置,包括uris

另一种面向反应式:

spring:  
  data:
    elasticsearch:
      client:
        #  反应式相关的配置
        reactive:
        #  端点       
          endpoints:
          connection-timeout:
          max-in-memory-size:
          socket-timeout:
          use-ssl:
          username:
          password:

这里配合的是Spring Webflux反应式框架,我个人其实更加倾向于此,但是作为目前的主流还是选择了第一种。

务必保证spring.data.elasticsearch.repositories.enabled = true,否则无法使用Spring Data Repository模式。

4. 操作

这里演示面向传统的Restful,一共有两种风格。假如我们向写入了Blog

{
  "blogId": "132435553",
  "blogTitle": "脚手架集成elasticsearch",
  "author": "felord",
  "content": "全称为Object Storage Service,也叫对象存储服务,是一种解决和处理离散单元的方法,可提供基于分布式系统之上的对象形式的数据存储服务,具有可拓展、可管理、低成本等特点,支持中心和边缘存储,能够实现存储需求的弹性伸缩,主要应用于海量数据管理的各类场景。\n\n这概念真是够难以理解的。简单说点我知道的吧,平常我们的文件地址都是 /User/felord/video/xxx.mp4的目录树结构,系统先要找到User,然后一级一级往下找一直到目标为止,这是一种结构化的存储方式。对象存储就不一样了,所有的文件都放在一个特定的池子里,只不过文件的携带有它自己的元信息,通过元信息去检索文件。",
  "url": "https://felord.cn/my-spring-boot-day7.html",
  "publishedTime": "2020-08-30T22:17:40"
}

对应的POJO对象为:

/**
 * @author felord.cn
 * @since 2020/8/30 16:10
 */
@Document(indexName = "blogs")
@Data
public class Blog {
    @Id
    private String blogId;
    private String blogTitle;
    private String author;
    private String content;
    private String url;
    @Field(type = FieldType.Date,format = DateFormat.date_hour_minute_second)
    private LocalDateTime publishedTime;
}
  • @Document用来标记文档对象,包含了该文档的一些元信息,索引副本数,分片数。
  • @Id 文档的标识符。
  • @Field 文档字段的一些元信息配置,类型、名称、分词器等等。

主要有以上三种,还有其它的一些注解标记,这里不再讲述。

4.1 ElasticsearchRestTemplate

RedisTemplate相信你已经不陌生了,同样的,Spring Data Elasticsearch提供了ElasticsearchRestTemplate来操作Elasticsearch,增删改查应有尽有。这里演示进行复杂的Criteria查询。

从blogs索引中查询blogId为132435553而且包含elastic词汇的标题的文档,同时查询词汇高亮

@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Test
void testTemplate() {

    // 构造条件  
    Criteria criteria = Criteria.where(new SimpleField("blogId"))
            .is("132435553")
            .and(new SimpleField("blogTitle"))
            .contains("elastic");

    CriteriaQuery criteriaQuery = new CriteriaQuery(criteria);
    // 高亮
    HighlightBuilder blogTitle = SearchSourceBuilder.highlight().field("blogTitle");
    HighlightQuery highlightQuery = new HighlightQuery(blogTitle);
    criteriaQuery.setHighlightQuery(highlightQuery);
    SearchHits<Blog> blogSearchHits = elasticsearchRestTemplate.search(criteriaQuery, Blog.class);
    blogSearchHits.getSearchHits().forEach(System.out::println);
}

4.2 Spring Data Repository

Spring Data Repository的核心接口是Repository。这个接口需要领域类(比如上面的Blog)跟领域类的ID类型作为参数。这个接口主要是让你能知道继承这个类的接口的类型。CrudRepository提供了对被管理的实体类的一些常用增删改查方法。那么针对Elasticsearch提供了各种特色的接口:

Elasticsearch Repository 接口家族

Repository模式提供了一种利用方法名称进行条件构造的查询方式。

IDEA 提供了智能提示来帮助我们构造方法条件

这种方式好处就是语义化,坏处就是方法名称可能非常的长。对于4.1中的例子我们可以简化为:

/**
 * @author felord.cn
 * @since 2020/8/30 21:32
 */
public interface BlogRepository extends ElasticsearchRepository<Blog,String> {



    @Highlight(fields = {
            @HighlightField(name = "blogTitle")
    })
    List<SearchHit<Blog>> searchBlogByBlogIdAndBlogTitleContains(String blogId, String titleContains);


}

另一种是采用注解方式,使用@Query注解,比如我们根据blogId进行查询我们可以这么写:

    @Query("{\"match\": {\"blogId\": \"?0\" }}")
//    @Query("{\"match\": {\"blogId\":{\"query\": \"?0\"}}}")
    Blog searchById(String blogId);

这个优点就是更加灵活,而且写法也更加随意简单;缺点就是需要熟悉Spring Data Elasticsearch以及Elasticsearch的查询语法,有一定的学习成本。

总结

以上就是简单的Spring Data Elasticsearch入门,对于使用Elasticsearch的项目来说,一般都具有了很大的数据量,所以要根据业务的需要进行具体的设计,Spring Data Elasticsearch能让我们非常方便进行搜索操作,如果你在使用中遇到什么问题可以通过公众号:码农小胖哥留言进行讨论。

关注公众号:Felordcn获取更多资讯

个人博客:https://felord.cn