Jasper Ji

博观而约取,厚积而薄发。

Spring Boot使用Elasticsearch

2021-04-26 05:23

主要是想把Elasticsearch整合到当前的系统中,用来搜索文章。

环境

Elasticsearch 7.12.0
Logstash 7.12.0
Mysql 8.0

数据同步

把Elasticsearch整合到现有系统意味需要把当前要搜索的数据添加到Elasticsearch里面,这就有个数据同步问题。因为是测试工程使用的是Logstash的全量数据同步。Logstash的新版本已经包含了Jdbc的插件,所以不需要安装。

input {
  jdbc {
      # myslq驱动,可以官网下载,我用的是Maven依赖已经下载的Jar文件
      jdbc_driver_library => ""
      # Mysql驱动类全类名,注意mysql8.x以上需要加cj
      jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
      # mysql连接url
      jdbc_connection_string => ""
      # mysql 用户名
      jdbc_user => ""
      # mysql 密码
      jdbc_password => ""
      # 设置定时任务,多久执行一次查询,默认一分钟,需要无延迟可使用schedule => "* * * * * *"
      schedule => "* * * * *"
      # 清空上次的sql_last_value记录
      clean_run => true
      # 要执行的sql(同步)语句,替换成你自己的sql
      statement => "SELECT * FROM t_article"
  }
}

output {
   elasticsearch {
      # es主机和端口
      hosts => ["127.0.0.1:9200"]
      # 同步数据在ES的索引名称,替换为你自己的。
      index => "my-cms"
      # es文档的id,表示使用mysql表的id
      document_id => "%{id}"
  }
}

生产环境的数据同步可以参考阿里云Elasticsearch

参考:
Jdbc input plugin

Spring Boot配置

添加Maven依赖

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

添加Elasticsearch客户端配置类

@Configuration
@EnableElasticsearchRepositories(basePackages = "io.pratik.elasticsearch.repositories")
@ComponentScan(basePackages = { "io.pratik.elasticsearch" })
public class ElasticsearchClientConfig extends AbstractElasticsearchConfiguration {
	@Override
	@Bean
	public RestHighLevelClient elasticsearchClient() {
		// 配置连接信息
		final ClientConfiguration clientConfiguration = ClientConfiguration.builder().connectedTo("localhost:9200")
				.build();

		return RestClients.create(clientConfiguration).rest();
	}
    
    /**
     * 这个很重要,不添加的话无法使用@Filed注解
     */
    @Bean
    @Override
    public EntityMapper entityMapper() {

        ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(
                elasticsearchMappingContext(), new DefaultConversionService()
        );
        entityMapper.setConversions(elasticsearchCustomConversions());

        return entityMapper;
    }
}

测试文章类,必须要加type='_doc',不然无法使用。另外遇到的问题是我数据库的日期用的是Date话,一直提示解析错误,最后使用LocalDateTime后就好了。

@Data
@Document(indexName = "my-cms", type = "_doc")
public class EsArticle {
	@Id // org.springframework.data.annotation.Id
	private Integer id; // 文章ID

	@Field(type = FieldType.Text, analyzer = "ik_max_word")
	private String title; // 文章标题

	@Field(name = "content", type = FieldType.Text, analyzer = "ik_max_word")
	private String articleContent; // 文章正文内容

	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	@Field(name = "create_time")
	private LocalDateTime createTime; // 文章创建时间
}

创建Repository类。

public interface ElasticArticleRepository extends ElasticsearchRepository<EsArticle, Integer> {
	
}

生成Controller,使用Postman测试接口是否正常工作。

@RestController
@RequestMapping("/article")
public class SearchController { 
	@Autowired
    private ElasticArticleRepository elasticRepository;

    @PostMapping(value = "/search")
    public List<EsArticle> handleSearchRequest(
            @RequestParam Map<String, Object> requestParam) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 构造ES查询条件
        String keyword = (String) requestParam.get("keyword");
        queryBuilder.should(QueryBuilders.matchPhraseQuery("title", keyword))
                .should(QueryBuilders.matchPhraseQuery("content", keyword));
 
        StopWatch watch = new StopWatch();
        watch.start(); // 开始计时
 
        Page<EsArticle> articles = (Page<EsArticle>)
                elasticRepository.search(queryBuilder);  // 检索数据
 
        watch.stop();  // 结束计时
        System.out.println(String.format("数据检索耗时:%s ms",
                watch.getTotalTimeMillis()));
 
        return articles.getContent();
    }
}

Comments