写在前:因为工作开发内容需要,需要用到搜索引擎同时又要用到分词,这个给我带来了很大的问题,百度了下最后选择了elk+ik这种。写本文的目的是整理总结下自己部署的过程和经验教训,小白都会遇到的坑,中间有一些自己的理解,若有大神希望批评指正共同进步!小弟不胜感激!!!
开始正文:springboot+elasticsearch+kibana+logstash(ELK)+IK中文分词的整合,以及报错问题 。
前提先确定版本和环境(这个尤为重要,因为版本问题能搞死个人!!!)
我的环境是: docker +springboot2.1.5 +elasticsearch5.6.8+kibana5.6.8+logstash:5.6.8 +ik5.6.8,后面我会放上各版本配置,希望只做到从搭建到开发代码一条龙。
docker 的安装我不多说了,直接从elasticsearch5.6.8 安装开始讲起,以下简称ES。
第一步:安装ES
首先建好如下目录我们要从容器映射到宿主机上持久化的:
config、data1(存放es单节点数据)、data2、data3、plugins(待会ik分词会映射到该目录下)
config中的配置ES的配置信息我配置了三个节点,测试库上我就用了一个 所以我只讲es1的配置:
es1.yml文件配置
cluster.name: elasticsearch-cluster
node.name: es-node1
network.bind_host: 0.0.0.0
network.publish_host: 0.0.0.0
http.port: 9200
transport.tcp.port: 9300
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["192.168.199.111:9300","192.168.199.111:9301","192.168.199.111:9302"]
discovery.zen.minimum_master_nodes: 1
es2.yml
cluster.name: elasticsearch-cluster
node.name: es-node2
network.bind_host: 0.0.0.0
network.publish_host: 192.168.199.111
http.port: 9201
transport.tcp.port: 9301
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["192.168.199.111:9300","192.168.199.111:9301","192.168.199.111:9302"]
discovery.zen.minimum_master_nodes: 2
es3.yml
cluster.name: elasticsearch-cluster
node.name: es-node3
network.bind_host: 0.0.0.0
network.publish_host: 192.168.199.111
http.port: 9202
transport.tcp.port: 9302
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["192.168.199.111:9300","192.168.199.111:9301","192.168.199.111:9302"]
discovery.zen.minimum_master_nodes: 2
network.publish_host: 0.0.0.0 为外网也能访问,如果不想可以指定本机ip
http.port :外部端口
transport.tcp.port: 内部端口
discovery.zen.ping.unicast.hosts:我配了三个节点 分别是9300、9301、9302 内部开放端口,对应外部端口是9200、9201、9202
discovery.zen.minimum_master_nodes:1 最少1个节点为一个集群
node.master : true 主节点
node.data: true 节点也存储数据
跨域问题配置解决:
http.cors.enabled: true
http.cors.allow-origin: "*"
暴露端口:不暴露访问可能会出错,在集群的时候,会发现不了节点,导致ES启动出错(docker logs -f 容器Id 查看报错信息)
[root@localhost elasticsearch]# cd config/
[root@localhost config]# firewall-cmd --add-port=9300/tcp
success
[root@localhost config]# firewall-cmd --add-port=9301/tcp
success
[root@localhost config]# firewall-cmd --add-port=9302/tcp
success
同时更改配置:
宿主机中加入:
在/etc/sysctl.conf文件最后添加一行:
vm.max_map_count=262144
立即生效, 执行:
/sbin/sysctl -p
若没有安装vim
apt-get update
#安装VIM
apt-get install vim
可以参考此篇:https://www.cnblogs.com/jianxuanbing/p/9410800.html
ES的工作准备好后就是,docker拉镜像了,不要问我为什么用docker,问就是我懒
docker pull elasticsearch:5.6.8 #拉取镜像 docker命令行
docker run -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -d -p 9200:9200 -p 9300:9300 -v /home/zddts/es/elasticsearch/config/es1.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /home/zddts/es/elasticsearch/data1:/usr/share/elasticsearch/data -v /home/zddts/es/elasticsearch/plugins:/usr/share/elasticsearch/plugins --name ES01 elasticsearch:5.6.8
ES_JAVA_OPTS 指定了ES的运行内存,已ES01 节点为例,二三节点如此安装
-v : 映射文件,持久保存数据,防止容器删了,配置数据gg
--name 容器名称随意
查看容器启动了:
docker ps -a (docker ps 能查看启动的)
访问:
http://192.168.199.111:9200/ 192.168.199.111是我测试机子ip 自行更正为自己的ip,安装成功
查看集群:
http://192.168.199.111:9200/_cat/nodes?pretty (就一个节点惊不惊喜意不意外?哈哈测试我只跑一个节点没必要跑三个)
第二安装kibana:
建文件夹目录yml配置都是给映射用的:
Kibana.yml 配置:
# Kibana is served by a back end server. This setting specifies the port to use.
server.port: 5601
server.host: "0.0.0.0"
server.name: "kibana"# The URL of the Elasticsearch instance to use for all your queries.
elasticsearch.url: "http://192.168.199.111:9200"
server.port: 5601 kibana 的访问端口
elasticsearch.url: 我是连接到 ES01
拉取镜像 并且映射文件:
docker run --name kibana -p 5601:5601 -v /home/zddts/es/kibana/kibana.yml:/usr/share/kibana/config/kibana.yml:ro -d -e ELASTICSEARCH_URL=http://192.168.199.111:9200 kibana:5.6.8
直接查看是否安装成功:
第三安装logstash:(我依靠他来自动增量同步mysql 数据到ES上,已经删除的数据不太好处理,后面继续更新)
同样建好映射文件目录logstash,
docker pull docker.io/logstash:5.6.8
# 执行安装启动
docker run -u root --name logstash -d --privileged=true \ -p 5044:5044 \ -p 9600:9600 \
--log-driver json-file --log-opt max-size=50m \ -v /home/zddts/es/logstash/config:/usr/share/logstash/config \
-v /home/zddts/es/logstash/jars/mysql-connector-java-5.1.46.jar:/usr/share/logstash/logstash-core/lib/jars/mysql-connector-java-5.1.46.jar \
-v /home/zddts/es/logstash/log:/var/log/logstash/logstash-plain.log \ -e xpack.monitoring.elasticsearch.hosts=http://192.168.199.111:9200\ logstash:5.6.8 \ -f /usr/share/logstash/config/logstash-sample.conf
//logstash 安装运行后对服务器cpu 和磁盘都产生很大的压力,cpu调优 还没彻底解决
磁盘压力是由于运行 ,docker 中logstash容器日志以恐怖的方式增加瞬间写掉50g的磁盘 所以我加了
-log-driver json-file --log-opt max-size=50m 该内容限制了日志文件大小,
映射出来的文件:
mysql-connector-java-5.1.46 是我用来连接数据库用来同步用的,请更具自己数据库版本自行选择合适的版本上传
配置logstash.yml文件
http.host: 0.0.0.0
xpack.monitoring.elasticsearch.hosts: http://192.168.199.111:9200
配置 logstash-sample.conf用来增量更新数据文件:
# Sample Logstash configuration for creating a simple
# Beats -> Logstash -> Elasticsearch pipeline.input {
jdbc {
type => "patentBo"
jdbc_driver_library => "/usr/share/logstash/logstash-core/lib/jars/mysql-connector-java-5.1.46.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
jdbc_connection_string => "jdbc:mysql://192.168.199.111:3306/zddts-patmarket"
jdbc_user => "zddts-patmarket"
jdbc_password => "***"
schedule => "* * * * *"
jdbc_default_timezone => "Asia/Shanghai"#字段名称我都用驼峰格式,主要是我bo属性名就是驼峰格式,可以不需要转换就能直接映射值
statement => "SELECT a.pat_id patId, a.pat_sort_id patSortId, a.pat_sort_no patSortNo, a.pat_sort_name patSortName, a.pat_no patNo, a.pat_title patTitle, a.pat_img patImg, a.pat_content patContent, a.resource_type resourceType, a.pat_type patType, a.pat_belone patBelone,
a.legal_status legalStatus, a.status STATUS, a.sort_id sortId, a.show_prc showPrc, a.chg_log chgLog, a.pat_end patEnd, a.pay_endtime payEndtime, a.recovery_end recoveryEnd, a.raise_prc raisePrc, a.proposed_prc proposedPrc,
a.reach_prc reachPrc, a.commission_prc commissionPrc, a.chg_fee chgFee, a.year_fee yearFee, a.overdue_fee overdueFee, a.recovery_fee recoveryFee, a.tax_fee taxFee, a.bus_server_fee busServerFee, a.manage_fee manageFee,
a.sale_org_no saleOrgNo, a.sale_org_name saleOrgName, a.sale_cons_id saleConsId, a.sale_cons_name saleConsName, a.pat_right patRight, a.calced_flag calcedFlag, a.calc_agree calcAgree, a.sale_status saleStatus,
a.good_flag goodFlag, a.top_flag topFlag, a.rare_flag rareFlag, a.hot_flag hotFlag, a.top_order topOrder, a.hits hits, a.add_time ADDTIME, a.end_time endTime, a.up_time upTime, a.remark remark, b.pat_deatil_id patDeatilId,
b.patuse_code patuseCode, b.proposer proposer, b.inventor inventor, b.pro_time proTime, b.submit_time submitTime, b.bro_arch_name broArchName, b.prin_attor prinAttor, b.contact_name contactName, b.contact_addr contactAddr,
b.contact_code contactCode, b.pub_annou_no pubAnnouNo, b.pub_annou_time pubAnnouTime, b.authorize_time authorizeTime, b.obligee obligee, b.publisher publisher, b.tel_publisher telPublisher, b.publisher_id publisherId
FROM
`pa_patent` a, `pa_pat_deatil` b
WHERE a.pat_id = b.pat_id
AND a.pat_no = b.pat_no "
lowercase_column_names => false
clean_run => "false" # 是否清除last_run_metadata_path的记录,需要增量同步时此字段必须为false
}
jdbc {
type => "patPayableBo"
jdbc_driver_library => "/usr/share/logstash/logstash-core/lib/jars/mysql-connector-java-5.1.46.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
jdbc_connection_string => "jdbc:mysql://192.168.199.111:3306/zddts-patmarket"
jdbc_user => "zddts-patmarket"
jdbc_password => "******"#密码
schedule => "* * * * *" #每分钟执行一次
jdbc_default_timezone => "Asia/Shanghai"
statement => " SELECT id id,pat_no patNo ,STATUS ,fee_type feeType,fee fee,pay_endtime payEndtime FROM pat_payable "
lowercase_column_names => false
clean_run => "false"
}
}
filter {
json {
source => "message"
remove_field => ["message"]
}
# convert 字段类型转换,将字段xxx数据类型改为float;
mutate {
convert => {
"xxx" => "float"
}
}
}
output{
stdout {
codec => json_lines
}
#elasticsearch{
# hosts => "192.168.199.111:9200" # ES连接
# index => "zddts-patmarket" # ES索引名称
# document_type => "patentBo"
# document_id => "%{patId}" # id对应ORACLE中主键字段
#}
if[type]=="patentBo"{
elasticsearch {
#ESIP地址与端口
hosts => "192.168.199.111:9200"
#ES索引名称(自己定义的)
index => "zddts-patmarket"
#文档类型
document_type => "patentBo"
#文档类型id
document_id => "%{patId}"
}
}if[type]=="patPayableBo"{
elasticsearch {
#ESIP地址与端口
hosts => "192.168.199.111:9200"
#ES索引名称(自己定义的)
index => "zddts-patmarket"
#文档类型
document_type => "patPayableBo"
#文档类型id
document_id => "%{id}"
}
}
}
第四步 安装管理ElasticSearch-Head:
docker pull mobz/elasticsearch-head:5
docker run -d --name es-head -p 9100:9100 mobz/elasticsearch-head:5
测试:http://192.168.199.111:9100/
访问:
第五步安装中文ik 分词器插件,这一步可以在ES安装好启动后操作
版本比对:
docker exec -it ES01 /bin/bash
进入插件目录
cd plugins/
下载ik插件【注意版本问题】
wget http://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.6.8/elasticsearch-analysis-ik-5.6.8.zip
解压
unzip elasticsearch-analysis-ik-5.6.8.zip
删除压缩包
rm elasticsearch-analysis-ik-5.6.8.zip
退出容器
exit
安装好后 我就可以在映射的文件夹中看到,很方便,直接改这里的配置,重启容器就会生效这也是我映射文件的一个原因之一,方便,安全,不怕容器被删了
ok那我们测试下吧,java 代码 如何写可以参考:https://my.oschina.net/fusublog/blog/3050964
用restful 也可以访问: 我用的是postman来做测试,分词效果不错
至此安装已经完成,那么接下来就是优化了:可能同学“上中真实个好东西”没有在返回结果中。跟我的不一样,哈哈那么接下来就是要说下ik 分词的 扩展了
进入ik插件的配置目录我们可以看见:IKAnalyzer.cfg.xml和main.dic
这个IKAnalyzer.cfg.xml 是ik分词对热词的一个扩展,就是玩家开自定义自己的分词 ,在这个文件中配置,main.dic是自带的
截图中我配置了my.dic
并且正在IKAnalyzer.cfg.xml 引入改字典
重启ES01
然后重新访问分词测试那么 你也会达到我一样的效果了。
ps: 某些单个字可能查询不到结果,但是词可以查到,我就是“装置” 能查到数据,“置”就查不到,就是没对“置”这个字维护索引建立热词
配置好扩展热词,重启服务器就可以了。
更改模板 使用ik分词:
PUT /_template/template_1
{
"template": "*",
"version": 50001,
"settings": {
"index.refresh_interval": "5s"
},
"mappings": {
"_default_": {
"_all": {
"enabled": true,
"norms": false
},
"dynamic_templates": [
{
"message_field": {
"path_match": "message",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"norms": false
}
}
},
{
"string_fields": {
"match": "*",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"norms": false,
"analyzer": "ik_max_word",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
],
"properties": {
"@timestamp": {
"type": "date",
"include_in_all": false
},
"@version": {
"type": "keyword",
"include_in_all": false
}
}
}
}
}
延伸问题:这样我每次维护热词是不是都要起服务,感觉这样完全不是我们程序员可以忍受的了,应该是我可以在数据库维护热词,然后这边可以热部署我的分词,这样就是完美了。(20191120改,配置远端扩展)
关于这个问题有兴趣的同学、大哥大姐可以参考:
https://www.liangzl.com/get-article-detail-9284.html 文章十分的话 我给11分,绝对通俗易懂。
ps:以上配置安装好后,可以做成自己独立镜像,我是直接做成镜像的就像自己做个jdk,(其他镜像完全满足不了我这个巨婴的需求) 那么下次在生产上就直接拉取镜像就好了,可以跳过这些重复步骤,只要改过配置就行。努力学习中,知识从群众中来加工消化后到群众中去,持续更新中。。。