Spring Data Elasticsearch入门

本文通过一个简单的访问普通log并添加Movie类型日志介绍如何使用spring-data-elasticsearch访问elasticsearch数据库。

关于ELK的理论以及使用场景不在本文的讨论访问,如何安装ELK全家桶也不再本文讨论范文。本文主要介绍一个简单的使用场景,就是如何通过spring-data-elasticsearch访问elasticsearch中数据,以及如何添加数据。

本文主要参考官方文档https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/和https://spring.io/projects/spring-data-elasticsearch

  • 前提

前提

  • 在Maven项目添加spring-data-elasticsearch和相关依赖
  • 编写domain对象
  • 继承ElasticsearchRepository接口
  • 实现service
  • 在Controller中访问
  • 修改配置文件
  • 运行截图
  • 总结

完整的代码在这里,欢迎fork,加星。

1, 前提

创建连接器

前提条件:ELK全套已经安装并运行良好。
网上关于如何安装ELK的介绍很多,本文就不再赘述。 笔者采用https://github.com/deviantony/docker-elk提供的docker-compose文件安装。 Kibana访问地址为http://localhost:5601

2, 添加java项目依赖。
主要是添加spring-boot-starter-data-elasticsearch依赖,参考spring boot guide

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

       ...

    </dependencies>

3, 编写domain对象
本文中的有两个对象Movie和Log,都比较简单。 需要注意的是要加上@NoArgsConstructor
和@AllArgsConstructory以及@Document, 其中@NoArgsConstructor自动为我们创建一个无参数的构造函数,@Document表示这个是ElasticSearch中的store会关联。

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = xxx-2018.07.06", type = "logs", shards = 1, replicas = 0)
public class Log {

    @Id
    private String id;

    private String HOSTNAME;
    private String level;
    private int port;
    private String thread_name;
    private int level_value;
    private String host;
    private String logger_name;
    private String message;

    private String[] tags;
    //private int version;

    //试图更改updateDate的时间显示格式
    //@Field(type = FieldType.Date, format = DateFormat.date_optional_time) ---timestamp is long
    //@Field(type = FieldType.Date, format = DateFormat.basic_date_time )
    @Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second )
    @JsonProperty(value = "@timestamp")
    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    @DateTimeFormat(pattern="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    private Date updateDate;
}
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "movie-store", type = "movie", shards = 1, replicas = 0)
public class Movie {

    @Id
    private Long id;

    private String name;

    private Double rating;
}

4,继承ElasticsearchRepository接口
ElasticsearchRepository就如同spring jpa中的JpaRepository一样, 已经帮我们实现很多save、delete、findAll、 findOne、分页等功能,还能根据方法的名称和查询关系字符串自动组成And、or 、GT、 LT等等。

LogRepository中的List findByLevel(String level);方法会自动按照日志级别帮我们查询Log,就相当于jpa中的select * from log-index where log-index.level =level

MovieRepository中的findByRatingBetween(Double start, Double end);方法就相当于就相当于jpa中的select * from movie-index where movie-index.rating between start, and end

注意这段代码来自官方例子

package com.yq.repository;

import com.yq.domain.Director;
import com.yq.domain.Movie;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.util.List;

/**
 * Created by Nasir on 12-09-2015.
 */
@Repository
public interface MovieRepository extends ElasticsearchRepository<Movie, Long> {

    List<Movie> findByName(String name);
    List<Movie> findByRatingBetween(Double start, Double end);
}

LogRepository代码与MovieRepository类似就不再此展示了,详细可见代码。 欢迎加star和fork。

5, 实现service
一般而言单个repository只是实现该对象自身的CRUD,如果我们要实现业务逻辑,需要在service中完成,本示例比较简单,service只是将repository做了加单包装。

6, 在Controller中访问
完成domain、repository和service就可以访问数据, 我们这里使用controller只是为了展示数据。
第一个controller,LogController会会查询日志,其中ElasticsearchTemplate是另外一种访问elasticsearch数据的方式,以后会单独在介绍。大家主要关注controller调用LogService就行。
第二个controller,MovieResource会展示添加、删除和查询

代码示例

@RestController
public class MovieResource {

    private MovieService movieService;

    @Autowired
    public MovieResource(MovieService movieService) {
        this.movieService = movieService;
    }

    @PostMapping("/movie/add")
    @ApiOperation(value = "add", notes="private")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "newMovie", value = "newMovie", required = true, dataType = "newMovie", paramType = "body")
    })
    public ResponseEntity<Movie> addMovie(@RequestBody  Movie newMovie) {
        Movie savedMovie = movieService.addMovie(newMovie);
        URI location = ServletUriComponentsBuilder.fromCurrentRequest().path(
                "/{id}").buildAndExpand(savedMovie.getId()).toUri();
        return ResponseEntity.ok(savedMovie).created(location).build();
    }

    @ApiOperation(value = "add", notes="private")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "id", required = true, dataType = "long", paramType = "path")
    })
    @DeleteMapping("/movie/{id}/delete")
    public ResponseEntity<String> deleteMovie(@PathVariable("id") Long id) {
        movieService.deleteMovie(id);
        return ResponseEntity.ok("Deleted");
    }

    @ApiOperation(value = "add", notes="private")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name", value = "name", required = true, dataType = "string", paramType = "path")
    })
    @GetMapping("/movie/get-by-name/{name}")
    public ResponseEntity<List<Movie>> findMovieByName(@PathVariable("name") String name) {
        List<Movie> fetchedMovie = movieService.getByName(name);
        return ResponseEntity.ok(fetchedMovie);
    }
}

LogController代码可参看github代码

7, 配置文件加上elasticsearc相关配置
需要在application.properties 中配置elasticsearch信息。

#Cluster node port configuration
spring.data.elasticsearch.cluster-name=docker-cluster
spring.data.elasticsearch.cluster-nodes=a.b.c.d:9300
spring.data.elasticsearch.repositories.enabled=true

8, 运行截图

截图1, 根据log id查询log

spring es 日期查询 spring.data.elasticsearch_ELK

截图2, 创建movie对象,并根据name字段查询

spring es 日期查询 spring.data.elasticsearch_ELK_02

8, 总结
使用spring-data-elasticsearch访问elasticsearch,就是通过domain(加上@Document注解)和ElasticsearchRepository完成elasticsearch的访问和操作。

关于如何使用ElasticsearchTemplate后面的博文会继续讨论。