企业级搜索系统案例源码(已经非常精简),根据现公司项目搭建,基于 elasticsearch + canal,可支持千万量级以上实时搜索。

版权声明:版权所有 盗版爆菊 https://blog.csdn.net/u012888052/article/details/81876152

一、准备工作:

  • IDEA:

  • JDK1.8:

  • mysql数据库:

安装完mysql数据库后,把bin_log设置打开,如果不确定是否已经打开,可执行 show variables like ‘log_bin%’;
如果显示如下,那说明已经开启bin_log日志,如果没有,如果想使用canal进行数据同步,自行百度开启bin_log
这是个人数据库截图,用于演示bin_log是否开启

接下来,新建数据库:db_search 并运行准备好的sql文件 db_search.sql (项目源码中包含这个sql文件,可自行下载)
执行完sql后,数据库中数据应该是这样的:
数据库数据

如果不需要进行字段的分词查询,可不安装分词器,但是绝大多数业务场景,都是需要分词查询的,并且目前Demo中有分词代码,建议安装。

打开链接,下载第一个压缩包,然后解压,解压后应该是这个样子的:
canal服务端文件夹
bin为启动文件夹
conf为配置文件夹
lib为相关jar包文件夹
logs为日志文件夹
前面我们已经安装好Mysql数据库,并且已经建好了一个测试数据库,那么我们接下来进行 Mysql + canal 服务端的配置
打开canal的conf文件夹,在里面新建 articlesubscibe 文件夹,再在 articlesubscibe 文件夹中,复制conf文件夹下example中的instance.properties 文件并修改配置,如下图(配置是我本机的配置,可根据实际需要改成自己的):
canal配置数据库
接下来,找到 canal.properties 配置文件进行编辑,找到 canal.destinations 配置参数,进行文件夹扫描配置,如下图:
canal配置文件图解
文件夹名称可自行定义,与上一步新建的文件夹名称相同即可。然后将conf文件夹下自带的 example 文件夹删除,为什么要删除呢?因为实际开发中需要同步的数据库、数据表是很多的,自带的文件夹是个案例,用于第一次配置时copy,后面我们应该根据实际需要,新建多个文件夹,区分不同的业务监听,便于后续维护。
至此,conf文件夹应该是这个样子:
canal中conf文件夹

  • **git安装(用于代码管理,主要是为下一步下载Demo做准备):**略

  • 项目源程序Demo(已经是最精简的例子了,单表同步,单表查询)GitHub地址(喜欢的朋友帮忙点个star):https://github.com/HappyWjl/es-home.git

以上,就是项目的准备工作,接下来就着重讲解项目结构,以及数据是如何同步、如何查询的干货。


二、项目结构:

  • 具体描述项目前,我经常想到大象装冰箱的步骤:

  • 打开冰箱门、将大象放进去、关上冰箱门

  • 现在做这个项目,也分为三个步骤:

  • 同步实时数据(data-dump)、同步历史数据(data-migration)、按条件查询es数据(data-search)

  • 同步实时数据:
    当数据库中 新增/删除/更新 一条数据时,需要实时同步到es
    注意!这里进行实时同步时,需要避免监听表的批量修改数据,不然会造成数据积压,一时间同步不过来。
    如果必须要批量修改Mysql表数据时,应先把canal服务端停掉

  • 同步历史数据:
    当数据库中已经有旧的数据,且数据量很多,es中没有时,需要将历史数据批量灌入到es
    如果没有历史数据,需要同步到es,就不需要这一步了

  • 按条件查询es数据:
    前两步能够保证es中的数据完整性,只能算前提条件,这一步是最出活的,做完这一步,能够查询出想要的,就算完成

利用git下载完项目后,就可以进行项目部署了,将项目导入到IDEA中,可以看到es-home主项目,下图是项目主要结构:
es-home项目主结构

项目采用的相关技术:spring-boot、mybatis、maven、elasticsearch、canal

具体可查看详细脑图:
es-home脑图1
es-home脑图2
es-home脑图3


##data-dump模块:

  • 这个项目主要的功能是实时同步数据,其中包含了canal客户端代码,用于接收canal服务端传来的数据库数据

  • 首先启动 DataDumpApplication.java ,可以看到启动文件会加载数据源、扫描spring下的配置文件、指定启动顺序(@Order注解)、执行run方法,建立es链接
    DataDumpApplication.java文件截图

  • 在启动完后,ElasticsearchEnvInitRunner.java文件会接下来运行,因为实现了CommandLineRunner,并且有@Order(2)注解
    这里会进行索引检查,如果es中没有代码中的索引,会新建一个索引名称
    ElasticsearchEnvInitRunner.java文件

  • 在新建索引过程中,可以对新建的索引进行设置,例如:设置字段分词、设置字段经纬度,用于距离排序
    设置初始索引

  • 接下来,CanalClientRunner.java文件会继续执行,因为实现了CommandLineRunner
    这个文件会和canal服务端建立链接
    CanalClientRunner.java文件

注:在使用SpringBoot构建项目时,我们通常有一些预先数据的加载。那么SpringBoot提供了一个简单的方式来实现–CommandLineRunner。
CommandLineRunner是一个接口,我们需要时,只需实现该接口就行。如果存在多个加载的数据,我们也可以使用@Order注解来排序。

  • 当canal服务端接收到mysql传过来的bin_log日志,会通过和客户端的链接,传到客户端 AbstractCanalCoreManager.java 类,客户端可根据设置批量读取传过来的数据,取决于业务数据的变动速度,以及canal客户端同步到es中的消费速度
    canal处理数据1

  • 消费过程中,由于真正企业中的数据量变动比较大,所以采用多线程的方式去消费数据
    canal处理数据2

  • 接下来,通过 entry.getEntryType() 可进行数据库事物判断,并分别对数据进行处理,再通过多线程依次处理这些数据
    canal处理数据3

  • 分别判断每条数据是 增/删/改 哪种类型,分别进行处理。当是删除时,进行es删除操作;当是 增/改 时,进行es增改操作
    canal处理数据4

  • 在向es中修改数据前,调用了analysisColumn(rowData.getBeforeColumnsList()); 方法,这是对数据库特殊字段的处理,因为es接收数据的类型和Mysql不完全一致,所以需要将特殊字段处理下,目前已知的特殊字段有:timestamp、datetime、date、time、blob 真的是万恶的时间,费我青春,害我敲码!
    处理数据库特殊字段

注:时间类型存储到es中会自动有时区转换,例如传入时间是2018-08-21 18:00:00 es中会存储成 2018-08-21 10:00:00 中间会差8小时,所以需要在查询数据时,进行时间差的转换

  • 删除操作,调用的是封装的删除方法
    es删除方法封装

  • getDateMap()方法,是在对es进行操作的最后一步之前,可对特殊数据进行处理,根据实际的需求来,简单的需求或者优质的表结构,不需要这一步,经过封装好的es新增/更新方法,就可以到es了
    es特殊索引数据处理

  • 新增/修改操作,调用的是封装的方法
    es新增/更新 方法封装


##data-migration模块:

  • 这个项目主要的功能是同步历史数据,当数据库中已经有旧的数据,且数据量很多,es中没有时,需要将历史数据批量灌入到es。如果没有历史数据,需要同步到es,就不需要这一步了

  • 这个项目和data-dump项目有相当一部分相同的代码,下面讲到的话就简单略过

  • 首先启动 DataMigrationApplication.java ,可以看到启动文件会扫描spring下的配置文件
    DataMigrationApplication启动

  • spring下的配置文件被扫描,mybatis相关配置也会被加载,此处省略,这里不是重点。。。

  • 在启动完后,ElasticSearchInitRunner.java文件会接下来运行,因为实现了CommandLineRunner
    这里会进行es连接池检查

  • 在启动完后,可以看到项目启动端口为:8082
    data-migration 模块启动

  • 接下来在浏览器中请求url:http://localhost:8082/api/article/checkindex
    可以进行索引检查,如果没有这个索引,会新建索引,这里同上面data-dump一样,索引可以设置分词等属性

  • 然后请求url:http://localhost:8082/api/article/articletoes
    就可以进行数据批量同步,接下来我简单讲下历史数据批量同步的步骤

  • 请求接口经过网络中的层层传递,一直访问到ArticleController.java
    进行url请求

  • 然后通过 articleSyncToEsManager.syncDataControl(); 同步数据到ES主控方法
    这个方法,首先通过mybatis批量查询出要同步表的历史数据,再进行循环,逐条处理数据
    es主同步方法

  • 当看到 getDateMap()时,如果上面data-dump模块的结构看的够仔细,那就能接上了,后面是完全一样的数据处理,接下来的介绍省略~可以参考上面写到的getDateMap()续读


##data-search模块:

  • 这个模块是进行数据的查询,在做这一步前,请确保es中已经有相关数据,不然程序写对了,也查不出来的,这时es应该可以看到初始数据如下图:
    es数据展示图

  • 首先启动 DataSearchApplication.java ,可以看到启动文件会扫描spring下的配置文件
    DataSearchApplication启动

  • 在启动完后,可以看到项目启动端口为:8083
    data-search模块启动

  • 接下来在postman中请求url(也可以用其他接口请求工具,注意是post请求):http://localhost:8083/api/article/getArticleList
    postman请求url

  • 可以看到请求返回结果已经查询到了结果

  • 请求接口经过网络中的层层传递,一直访问到ArticleController.java
    ArticleController被请求

  • 再经过service实现层,进行es查询,由于es查询后返回结果被封装成String,所以还需要转成Object才方便处理数据,再返回
    service.impl进行es查询

  • 由于这个模块主要实现的是查询功能,那么具体的查询需要仔细讲一下了,serviceImpl进行查询时,调用了 articleSearchManager.queryArticleList(queryArticleSearchVO);

  • 进行查询时,首先通过 elasticSearchInitClientManager.getElasticClient(); 获取es连接

  • 再设置索引、设置查询文章类型、组装查询条件

  • 查询出来时,是es的数据类型 SearchResponse ,然后通过方法转换成了Map

  • 但是这里有一点需要注意,存数据到es中时,时间类型是有转换的,现在是查询出来,es中存储的经转换的类型是字符串,需要转换成Data类型,并且可以留意下有没有时差,之前提到过的时差如果出现了,这里也可以进行数据修正

  • 再经过最后数据的组装,转成通用型的JSON字符串,返回
    es查询逻辑1

  • 组装逻辑应该根据实际情况封装
    组装查询逻辑1
    组装查询逻辑2


暂时写到这里吧,项目整体就是这个样子,实际使用中会比这个业务场景更复杂,这个Demo还是比较接近实际应用场景的,当然很多高级用法我没有加在里面,Demo复杂了就更难上手es了。

关于更多的查询业务,可自行探索,我也在慢慢探索中,加油。

有什么问题可以加QQ问,或者留言,看到就回。

作者:Happy王子乐
QQ:820155406
(近期迷上地下城,有富裕金币的同学,给点金币用,ID:血色冥灵,古灵精怪,跨六)

猜你喜欢

转载自blog.csdn.net/u012888052/article/details/81876152