前期准备
- Logstash简介:是ELK技术栈中的L,是数据采集引擎,可以从数据库、消息队列等数据源采集数据,设置过滤条件,输出到ElasticSearch等多种数据源中。
- 官网下载Logstash,选择下载zip文件
注意:ElasticSearch与Logstash需要统一版本(包括如果要用到Kibana也必须相同版本)(我用的均是7.8.0版本,mysql是8.x版本)
官网网址7.8.0网址
- 下载后解压Logstash压缩包,在根目录下的config文件夹中复制logstash-sample.conf到bin文件夹中,并改名为logstash.conf文件(主要是需要conf格式,以及之后按照conf参数运行logstash)
- logstash.conf文件内容(很多教程这一步之前还需要安装插件 logstash-input-jdbc,但是实测7.8.0不装此插件logstash照样可以正常实现mysql和ES之间的数据同步,初步估计可能是7.8.0版本的Logstash中已经集成这个插件了)
input {
stdin {
}
jdbc {
# 配置数据库信息
jdbc_connection_string => "jdbc:mysql://localhost:3306/legalretrievalsystem?useUnicode=true&useJDBCCompliantTimezoneShift=true&tinyInt1isBit=false&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8"
jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
jdbc_user => "root"
jdbc_password => "15907007907aB"
# 开启分页
jdbc_paging_enabled => "true"
# 分页每页数量,可以自定义
jdbc_page_size => "50000"
jdbc_default_timezone => "Asia/Shanghai"
# mysql驱动所在位置建议通过Maven下载
jdbc_driver_library => "E:\repository\mysql\mysql-connector-java\8.0.22\mysql-connector-java-8.0.22.jar"
# 标志目前logstash同步的位置信息(类似offset)。比如id、updatetime。logstash通过这个标志,可以判断目前同步到哪一条数据。
parameters => { "sql_last_value" => "UpdateTime" }
#sql执行语句
statement => "SELECT document_id,document_name,case_cause_name,document_num,court_name,case_type_name,trial_procedure_name,DATE_FORMAT(judgement_date,'%Y-%m-%d')judgement_date,party,legal_auth,full_text,document_type_name,court_level, DATE_FORMAT(create_time,'%Y/%m/%d %H:%i:%s')create_time, DATE_FORMAT(update_time,'%Y/%m/%d %H:%i:%s')update_time,is_deleted FROM legal_document WHERE update_time >=:sql_last_value"
# 定时字段 各字段含义(由左至右)分、时、天、月、年,全部为*默认含义为每分钟都更新
#schedule => "* * * * *"
#"*/5 * * * * *" 表示每 5 秒轮询一次。
schedule => "*/5 * * * * *"
# 是否将 sql 中 column 名称转小写
lowercase_column_names => false
#编码格式 UTF-8
codec => plain { charset => "UTF-8"}
}
}
filter {
json {
#要解析的字段名https://blog.51cto.com/wzlinux/2329811
source => "message"
#用 remove_field 参数来删除掉 message 字段https://blog.csdn.net/m0_47454596/article/details/123494564
remove_field => ["message"]
}
mutate {
rename => { "document_id" => "documentId"}
rename => { "document_name" => "documentName"}
rename => { "case_cause_name" => "caseCauseName"}
rename => { "document_num" => "documentNum"}
rename => { "court_name" => "courtName"}
rename => { "case_type_name" => "caseTypeName"}
rename => { "trial_procedure_name" => "trialProcedureName"}
rename => { "judgement_date" => "judgementDate"}
rename => { "legal_auth" => "legalAuth"}
rename => { "full_text" => "fullText"}
rename => { "document_type_name" => "documentTypeName"}
rename => { "court_level" => "courtLevel"}
rename => { "create_time" => "createTime"}
rename => { "update_time" => "updateTime"}
rename => { "is_deleted" => "isDeleted"}
convert => ["documentId","string"]
#将字段documentId进行类型转化,转化到string(因为document_id已经被重命名为documentId,所以这里是documentId)
}
}
output {
elasticsearch {
#es的ip和端口
hosts => ["127.0.0.1:9200"]
#ES索引名称(自己定义的)
index => "legaldocuments"
#文档类型
document_type => "_doc"
document_id => "%{documentId}" #(因为document_id已经被重命名为documentId,所以这里是documentId)
#这里要注意导入的documentId进入ES时要先将其转化成字符串(在mysql为了自增长documentId是bigint类型),不然19位的数字在中最后两位会丢失精度
}
stdout { #标准输出
codec => json_lines
}
}
- 在bin目录下打开cmd,输入命令:
logstash -f logstash.conf
- 打开浏览器,浏览器显示以下内容代表成功。
http://localhost:9600/
踩过的坑
注:ElasticSearch以下简称ES
-
插入date类型数据报错failed to parse field [case_date] of type [date]
因为MySQL中的update_time字段是timestamp类型,而在mysql中timestamp默认查出的是这种格式:2022-04-27T03:02:10.000Z这种格式,但是我们在ES中一般设置格式为"“yyyy/MM/dd HH:mm:ss”",所以我们需要借助MySQL的DATE_FORMAT函数。
DATE_FORMAT(create_time,‘%Y/%m/%d %H:%i:%s’)可以Mysql的update_time更改为ES需要的格式
关于MySQL DATE_FORMAT() 函数参数格式 -
Logstash默认是按照MySQL表中的字段名向ES中插入对应字段名。
Logstash会按照关系性数据库表中的字段名(我的习惯名字如果是多个单词之间用_隔开),在ES索引中增添文档,而ES中的字段名(名字如果是多个单词按照驼峰命名法),所以导致添加的文档字段名与ES不同,导致同步时不是将文档的字段值加入到相应字段下,而是创建了新的字段,并加入到新字段下。现在该怎么让logstash同步时,把Mysql的每行的值按照字段映射到对应的字段下,而不创建新的字段?
解决办法:
在logstash的filter插件模块中,同步时用rename改名,
(在select查询语句后面用as别名这样不行 SELECT document_id as documentId) -
在MySQL中因为主键需要自增长,所以主键设置为bigint类型。
但是自增长是19位,如果是以数字形式存入ES中,ES中导致最后3位精度确实,如298存成->300.(展现的形式是,每次更新因为自增长结尾都是二百,所以每次都缺失精度近似为300,结果传入ES每次的id均相同,导致多次修改的结果都覆盖了上次的结果)
解决mysql的id转换到ES的精度确实,需要将提取到的mysql的id从bigint类型改变类型为string。
在filter插件中,
-
每次重启都全量更新怎么办?重启后只能增量更新