Mysql百万文章导入ES springboot毫秒级的搜索响应
springboot百万文章的模糊搜索
之前做一个项目,内容主要是文章。操作主要是搜索,参考论坛贴吧啥的。由于搜索不仅是标题,还有作者,内容啥的。数据是存在mysql, 项目之前是不支持内容搜索。mysql对于模糊搜索的效率我就不说了。
既然是文章 是论坛那么少不了点赞收藏啥的咯,分页点赞啥的最讨厌了,貌似简单实则坑
废话不多说了,上代码
从mysql导入Elasticsearch(这里用的 logstash )配置
input {
stdin {}
jdbc {
# 驱动
jdbc_driver_library => "D:/logstash-7.9.2/bin/mysql-connector-java-8.0.20.jar"
# 驱动类名
jdbc_driver_class => "com.mysql.jdbc.Driver"
# mysql 数据库链接,test为数据库名
jdbc_connection_string => "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC"
# 用户名和密码
jdbc_user => "root"
jdbc_password => "root"
# 是否分页查询
jdbc_page_size => "1000"
jdbc_paging_enabled => "true"
#使用其它字段追踪,而不是用时间
use_column_value => "true"
#追踪的字段
tracking_column => "work_id"
# 是否将 column 名称转小写
lowercase_column_names => "false"
jdbc_default_timezone => "UTC"
# 执行的sql 文件路径+名称
statement_filepath => "D:/logstash-7.9.2/bin/jdbc.sql"
# 设置监听间隔 各字段含义(由左至右)分、时、天、月、年,全部为*默认含义为每分钟都更新
schedule => "* * * * *"
type => "jdbc"
}
}
filter {
json {
source => "message"
remove_field => ["message"]
}
}
output {
elasticsearch {
hosts => "localhost:9200"
index => "test"
document_type=> "works"
document_id => "%{workId}"
}
stdout {
codec => json_lines
}
}
注意:编码格式 一定要 utf-8!这个utf-8 + BOM深深的伤害过我。
因为你怎么转存改编码啥的 它依然是utf-8 + BOM, EditPlus可以转存为纯粹的utf-8。
然后就是input一定要顶在第一行第一个字符
注意几个重点参数
1:驱动参数, 最好是全路径并指定到具体的jar包
jdbc_driver_libraryutf-8
2:mysql 数据库链接, 就把你properties里面的直接cv过来就行
jdbc_connection_string
3:mysql查询语句 全路径具体到文件
statement_filepath
4:相当于mysql的库(es没有有库表的概念, 它就是大的JSON)
index
5:相当于mysql的表
document_type
6:相当于mysql的表的主键
document_id
导入完成以后开始java编码。
两个依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty4-client</artifactId>
<version>6.2.3</version>
</dependency>
启动类加个注解(ES的实体和mysql不一样,所以不能放到一个扫描区域,在项目上也是不推荐两者混在一起)
@SpringBootApplication
@EntityScan("toolers.manage.model")
@EnableElasticsearchRepositories(basePackages = "toolers.manage.search")
@EnableSwagger2
@EnableJpaAuditing
public class LifeToolsManageApplication {
public static void main(String[] args) {
SpringApplication.run(LifeToolsManageApplication.class, args);
}
}
Controller
@ApiOperation("根据查询条件获取诗词列表, 只有根据内容模糊匹配时会不按照热度排序")
@PostMapping("/pageWorksByField")
@ApiImplicitParams({
@ApiImplicitParam(name = "field", value = "查询的字段(查询结果列表中的字段都可以)", defaultValue = "content", required = false),
@ApiImplicitParam(name = "text", value = "查询内容")
})
public ResponseResult<QueryResult<EsWork>> pageWorksByField(
@RequestParam(value="pageSize", defaultValue="20") int pageSize,
@RequestParam(value="pageIndex", defaultValue="1") int pageIndex,
@RequestParam(value="field", defaultValue="content") String field,
@RequestParam(value="text", defaultValue="") String text
){
pageIndex = pageIndex > 0 ? pageIndex - 1 : pageIndex;
QueryResult<EsWork> esWorks = workersService.searchWorks(pageIndex, pageSize, field, text);
return ResponseResult.success(CommonCode.SUCCESS, esWorks);
}
Service
// 根据筛选条件分页查询(ES的数据)
public QueryResult<EsWork> searchWorks(int pageIndex, int pageSize, String field, String text) {
Pageable pageable = PageRequest.of(pageIndex, pageSize);
// 构建查询
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
if (StringUtils.isNotBlank(field) && StringUtils.isNotBlank(text)) {
if(field.equals("authorId")){
queryBuilder.withSort(SortBuilders.fieldSort("likesCount").order(SortOrder.DESC));
queryBuilder.withQuery(QueryBuilders.termQuery(field, text));
}else{
BoolQueryBuilder boolQueryBuilder= QueryBuilders.boolQuery() .should(QueryBuilders.matchQuery(field, text));
queryBuilder.withQuery(boolQueryBuilder).withPageable(pageable)
.withHighlightFields(new HighlightBuilder.Field(field))
.withHighlightBuilder(new HighlightBuilder().preTags("<font style='color:red'>").postTags("</font>")).build();
}
}else{
queryBuilder.withSort(SortBuilders.fieldSort("likesCount").order(SortOrder.DESC));
}
queryBuilder.withPageable(pageable);
// 搜索,获取结果
Page<EsWork> query = esWorksDao.search(queryBuilder.build());
QueryResult<EsWork> esWorkQueryResult = new QueryResult<>();
esWorkQueryResult.setData(query.getContent());
esWorkQueryResult.setTotal(query.getTotalElements());
esWorkQueryResult.setPageIndex(pageIndex + 1);
esWorkQueryResult.setPageSize(pageSize);
return esWorkQueryResult;
}
至此一个百万条数据(差不多1G)文章的模糊搜索就可以了, 毫秒级的响应。是不是很简单呢