开源ElasticSearch是一个基于Lucene的实时分布式的搜索与分析引擎,是遵从Apache开源条款的一款开源产品,是当前主流的企业级搜索引擎。作为一款基于RESTful API的分布式服务,Elasticsearch可以快速地、近乎于准实时地存储、查询和分析超大数据集,通常被用来作为构建复杂查询特性和需求强大应用的基础引擎或技术。
Elasticsearch、Logstash和Kibana这三个技术就是我们常说的ELK技术栈
初识ElasticSearch
ElasticSearch概念和适用场景
ElasticSearch是一个开源的分布式全文检索和分析引擎,实时快速存储分析海量数据。
分布式、全文检索、实施快速、Restful
ElasticSearch VS MySQL
ElasticSearch、Kibana安装和部署
ElasticSearch与Kibana版本要对应
ElasticSearch
-
官网下载ElasticSearch
-
双击 elasticsearch/bin/elasticsearch.bat 启动
默认情况下,ElasticSearch使用两个端口来监听外部TCP流量。
9200端口: HTTP 协议的 RESTful 接口。包括搜索、聚合、监控、以及其他任何使用HTTP协议的请求。所有的客户端库都会使用该端口与ElasticSearch进行交互。
9300端口:TCP 通讯端口,用于集群中各节点之间的通信。用于诸如集群变更、主节点选举、节点加入/离开、分片分配等事项。
Kibana
-
官网下载Kibana
-
双击kibana/bin/kibana.bat启动
-
kibana配置文件config/kibana.yml
# 默认端口
server.port: 5601
# ES 服务器的地址
elasticsearch.hosts: ["http://localhost:9200"]
# 索引名
kibana.index: ".kibana"
# 支持中文
i18n.locale: "zh-CN"
postman、kibana对ES的交互
postman实例
-
查看所有索引
GET:http://localhost:9200/_all
-
创建索引-test
PUT:http://localhost:9200/test
-
删除索引-test
DELETE:http://localhost:9200/test
-
创建索引-person
PUT:http://localhost:9200/person -
新增数据-person-1
PUT:http://localhost:9200/person/_doc/1
-
新增数据-person-2
PUT:http://localhost:9200/person/_doc/2
-
新增数据-person-id
GET:http://localhost:9200/person/_doc/1
-
搜索数据-person-name
GET:http://localhost:9200/person/_doc/_search?q=first_name:john
kibana实例
kibana Dev Tools
- 查询数据
POST /person/_search
{
"query":{
"bool": {
"should": [
{
"match": {
"first_name": "Smith"
}
},
{
"match": {
"about": "basketball"
}
}
]
}
}
}
博客网站全文检索
级域MySQL实现
MySQL建表语句:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_blog
-- ----------------------------
DROP TABLE IF EXISTS `t_blog`;
CREATE TABLE `t_blog` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(60) DEFAULT NULL COMMENT '博客标题',
`author` varchar(60) DEFAULT NULL COMMENT '博客作者',
`content` mediumtext COMMENT '博客内容',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4;
SET FOREIGN_KEY_CHECKS = 1;
查询语句
select * from t_blog where title like '%spring%' or content like '%spring%'
高性能的索引策略
1、独立的列:
如果查询中的列不是独立的,则Mysql就不会使用索引。独立的含义是指索引列不能是表达式的一部分,也不能是函数的参数。
/*使用了表达式,不是独立的列,不会命中索引*/
select * from t_blog where id + 0 = 1;
2、like查询不能以%开头
# LIKE查询以%为开头,不会命中索引
select * from t_blog where title like '%spring%'
# LIKE查询不以%为开头,会命中索引
select * from t_blog where title like 'spring%'
3、列类型是字符串,一定要在条件中将数据使用引号引用起来
/*在name列有索引,字符串未用引号引用,不会命中索引*/
select * from t_blog where title = 123;
/*在name列有索引,字符串用引号引用,会命中索引*/
select * from t_blog where title = '123';
4、最左匹配原则
在mysql建立联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配, 删除所有索引,对列name、列address和列phone建一个联合索引
alter table `t_blog` add index index_combile ( `title`, `author`,`content`);
联合索引 index_combile
实际建立了(title)、(title,author)、(title,author,content)
三个索引。所以下面的三个SQL语句都可以命中索引。
select * from t_blog where title= 'myGKHeCwAm';
select * from t_blog where title= 'myGKHeCwAm' and author= 'KPSTOrpBMf';
select * from t_blog where title= 'myGKHeCwAm' and content= 'pjZvejKYKF' and author= 'KPSTOrpBMf';
上面三个查询语句执行时会依照最左前缀匹配原则,检索时分别会使用索引进行数据匹配。索引的字段可以是任意顺序的。
基于ES实现
ES倒排索引工作原理
ES对新增的数据进行分词,可以使用内部支持的分词规则或特定的分词来实现,分词后ES会维护最小词源(Term)到文档ID的映射。
ES节点
MySQL、ES数据同步
数据库同步中间件
全量、增量
全量:第一次建立完ES索引后,把MySQL数据一次性打包同步过去,这个过程是全量。
增量:以后MySQL产生新的数据(新插入的数据、以前老数据得到update、以前老数据得到delete),这三种情况同样需要同步到index去,让它对应的去做新增、更新、删除操作。
几种方式
开源中间件
MySQL的binlog订阅
:它用于实时记录MySQL数据产生的变化。通过MySQL主从复制协议,自己实现客户端,和MySQL主节点连接,把自己伪装成slave节点(从节点),主节点发生数据变更,会将变更事件传递到客户端。
Binlog 即 Binary Log,是MySQL中的一种二进制日志文件。它可以记录MySQL内部对数据库的所有修改,设计Binlog最主要的目的是满足数据库主从复制和增量恢复的需要。
canal
阿里巴巴MySQL binlog增量订阅&消费组件
go-mysql-elasticsearch
logstash
Logstash是具有实时流水线能力的开源的数据收集引擎。Logstash可以动态统一不同来源的数据,并将数据标准化到您选择的目标输出。它提供了大量插件,可帮助我们解析,丰富,转换和缓冲任何类型的数据。
logstash全量、增量同步解决方案
logstash同步数据操作
1、在logstash官网下载对应版本的logstash
2、解压后,引入mysql-connector-java-5.1.32.jar包
3、config目录下新增mysql.conf配置文件
mysql.conf配置文件:
input{
jdbc{
# jdbc驱动包位置
jdbc_driver_library => "D:\\Program\\logstash-6.8.20\\mysql-connector-java-5.1.32.jar"
# 要使用的驱动包类,不同数据库调用的类不一样
jdbc_driver_class => "com.mysql.jdbc.Driver"
# mysql数据库连接信息
jdbc_connection_string => "jdbc:mysql://localhost:3306/blog"
# mysql用户
jdbc_user => "root"
# mysql密码
jdbc_password => ""
# 定时任务,多久执行一次查询,默认一分钟,如果想要没有延迟,可以使用 schedule => "* * * * * *"
schedule => "* * * * *"
# 清空上次的sql_last_value记录
clean_run => true
# 你要执行的语句
statement => "select * from t_blog where update_time >= :sql_last_value and update_time < now() order by update_time desc"
}
}
output{
elasticsearch{
# es host:port
hosts => ["127.0.0.1:9200"]
# 索引
index => "blog"
# _id
document_id => "%{id}"
}
}
4、启动elasticsearch、kibana,cmd切换至logstashd的bin目录,执行logstash -f ../config/mysql.conf
5、kibana 查看数据 GET /blog/_stats
执行语句对于临界点的处理
- 1.0版本
数据有缺失
select * from t_blog where update_time > :sql_last_value order by update_time desc
以T开头的是时间节点,以R开头的是表格里的行数据
- 2.0版本
产生额外的性能开销
select * from t_blog where update_time >= :sql_last_value order by update_time desc
- 3.0版本
select * from t_blog where update_time > :sql_last_value and update_time < now() order by update_time desc
SpringBoot集成ES
ES内置分词器介绍
-
standard:标准分词器,是Elasticsearch中默认的分词器,将单词转成小写形式,去除标点符号,支持中文【单字分割】。基于Unicode文本分隔算法
-
simple:通过非字母的字符分割文本,将单词转为小写形式,同时去除数字类型的字符。例如:数字、标点符号、特殊字符等,会去掉非字母的词,大写字母统一转换成小写。
-
whitespace:仅去除空格,不支持中文,大写字母不会转换成小写。
-
language:特定语言的分词器,不支持中文。
设置分词器
POST _analyze
{
"analyzer": "standard",
"text":"我是中国人"
}
ES中文分词器
1、在官网下载ES版本对应的分词器
2、在elasticsearch/plugins目录下新建ik文件夹,将ik分词器安装包解压至该文件夹下
3、重启elasticsearch服务,使用ik分词器
POST _analyze
{
"analyzer": "ik_smart",
"text" :"我是中国人"
}
POST _analyze
{
"analyzer": "ik_max_word",
"text" :"我是中国人"
}
- main.dic中存储常用中文词语
- 分词效果
我是慕课网
POST _analyze
{
"analyzer": "ik_max_word",
"text" :"我是慕课网"
}
- extra_main.dic新增
慕课网
,重启elasticsearch
- 分词效果
我是慕课网
SpringBoot项目搭建集成ES
ES模糊查询 - Kibana
POST /blog/_search
{
"query": {
"bool": {
"should": [
{
"match_phrase": {
"title": "11"
}
},
{
"match_phrase": {
"content": "22"
}
}
]
}
}
}
ES模糊查询 - Java
BoolQueryBuilder builder = QueryBuilders.boolQuery();
builder.should(QueryBuilders.matchPhraseQuery("title", param.getKeyword()));
builder.should(QueryBuilders.matchPhraseQuery("content", param.getKeyword()));
String s = builder.toString();
System.out.println(s);
Page<EsBlog> search = (Page<EsBlog>) esBlogRepository.search(builder);
List<EsBlog> content = search.getContent();
map.put("list", content);
GitHub地址:
慕课网课程:Springboot + ElasticSearch 构建博客检索系统