vlambda博客
学习文章列表

Mysql百万文章导入ES springboot毫秒级的搜索响应


springboot百万文章的模糊搜索

    之前做一个项目,内容主要是文章。操作主要是搜索,参考论坛贴吧啥的。由于搜索不仅是标题,还有作者,内容啥的。数据是存在mysql, 项目之前是不支持内容搜索。mysql对于模糊搜索的效率我就不说了。


    既然是文章 是论坛那么少不了点赞收藏啥的咯,分页点赞啥的最讨厌了,貌似简单实则坑


废话不多说了,上代码


  1. 从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)文章的模糊搜索就可以了, 毫秒级的响应。是不是很简单呢