ElasticSearch学习笔记(含SpringBoot整合)
Posted 是渣渣呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ElasticSearch学习笔记(含SpringBoot整合)相关的知识,希望对你有一定的参考价值。
ElasticSearch笔记
文章目录
- ElasticSearch笔记
- 带着问题上路——ES是如何产生的?
- 一、ES 基础一网打尽
- 二、Docker下安装ES+Kibana
- 三、初步检索
- 四、进阶检索
- 五、ElasticSearch-Rest-Client
- 六、附录-安装Nginx
带着问题上路——ES是如何产生的?
(1)思考:大规模数据如何检索?
如:当系统数据量上了10亿、100亿条的时候,我们在做系统架构的时候通常会从以下角度去考虑问题:
1)用什么数据库好?(mysql、sybase、oracle、达梦、神通、mongodb、hbase…)
2)如何解决单点故障;(lvs、F5、A10、Zookeep、MQ)
3)如何保证数据安全性;(热备、冷备、异地多活)
4)如何解决检索难题;(数据库代理中间件:mysql-proxy、Cobar、MaxScale等;)
5)如何解决统计分析问题;(离线、近实时)
(2)传统数据库的应对解决方案
对于关系型数据,我们通常采用以下或类似架构去解决查询瓶颈和写入瓶颈:
解决要点:
1)通过主从备份解决数据安全性问题;
2)通过数据库代理中间件心跳监测,解决单点故障问题;
3)通过代理中间件将查询语句分发到各个slave节点进行查询,并汇总结果
(3)非关系型数据库的解决方案
对于Nosql数据库,以mongodb为例,其它原理类似:
解决要点:
1)通过副本备份保证数据安全性;
2)通过节点竞选机制解决单点问题;
3)先从配置库检索分片信息,然后将请求分发到各个节点,最后由路由节点合并汇总结果
另辟蹊径——完全把数据放入内存怎么样?
我们知道,完全把数据放在内存中是不可靠的,实际上也不太现实,当我们的数据达到PB级别时,按照每个节点96G内存计算,在内存完全装满的数据情况下,我们需要的机器是:1PB=1024T=1048576G
节点数=1048576/96=10922个
实际上,考虑到数据备份,节点数往往在2.5万台左右。成本巨大决定了其不现实!
从前面讨论我们了解到,把数据放在内存也好,不放在内存也好,都不能完完全全解决问题。
全部放在内存速度问题是解决了,但成本问题上来了。
为解决以上问题,从源头着手分析,通常会从以下方式来寻找方法:
1、存储数据时按有序存储;
2、将数据和索引分离;
3、压缩数据;
这就引出了Elasticsearch。
一、ES 基础一网打尽
1.1 ES定义
ES=elaticsearch简写, Elasticsearch是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。
Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
1.2 Lucene与ES关系?
1)Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。
2)Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
(REST -- REpresentational State Transfer,英语的直译就是“表现层状态转移”。如果看这个概念,估计没几个人能明白是什么意思。那下面就让我来用一句人话解释一下什么是RESTful: URL定位资源,用HTTP动词(GET,POST,PUT,DELETE)描述操作。
所以RESTful API就是REST风格的API。 那么在什么场景下使用RESTful API呢?在当今的互联网应用的前端展示媒介很丰富。有手机、有平板电脑还有PC以及其他的展示媒介。那么这些前端接收到的用户请求统一由一个后台来处理并返回给不同的前端肯定是最科学和最经济的方式,RESTful API就是一套协议来规范多种形式的前端和同一个后台的交互方式。
RESTful API由后台也就是SERVER来提供前端来调用。前端调用API向后台发起HTTP请求,后台响应请求将处理结果反馈给前端。
1.3 ES主要解决问题:
1)检索相关数据;
2)返回统计结果;
3)速度要快。
1.4 ES工作原理
当ElasticSearch的节点启动后,它会利用多播(multicast)(或者单播,如果用户更改了配置)寻找集群中的其它节点,并与之建立连接。这个过程如下图所示:
1.5 ES核心概念
1)Cluster:集群。
ES可以作为一个独立的单个搜索服务器。不过,为了处理大型数据集,实现容错和高可用性,ES可以运行在许多互相合作的服务器上。这些服务器的集合称为集群。
2)Node:节点。
形成集群的每个服务器称为节点。
3)Shard:分片。
当有大量的文档时,由于内存的限制、磁盘处理能力不足、无法足够快的响应客户端的请求等,一个节点可能不够。这种情况下,数据可以分为较小的分片。每个分片放到不同的服务器上。
当你查询的索引分布在多个分片上时,ES会把查询发送给每个相关的分片,并将结果组合在一起,而应用程序并不知道分片的存在。即:这个过程对用户来说是透明的。
4)Replia:副本。
为提高查询吞吐量或实现高可用性,可以使用分片副本。
副本是一个分片的精确复制,每个分片可以有零个或多个副本。ES中可以有许多相同的分片,其中之一被选择更改索引操作,这种特殊的分片称为主分片。
当主分片丢失时,如:该分片所在的数据不可用时,集群将副本提升为新的主分片。
5)全文检索。
全文检索就是对一篇文章进行索引,可以根据关键字搜索,类似于mysql里的like语句。
全文索引就是把内容根据词的意义进行分词,然后分别创建索引,例如”你们的激情是因为什么事情来的” 可能会被分词成:“你们“,”激情“,“什么事情“,”来“ 等token,这样当你搜索“你们” 或者 “激情” 都会把这句搜出来。
1.6 ES数据架构的主要概念(与关系数据库Mysql对比)
(1)关系型数据库中的数据库(DataBase),等价于ES中的索引(Index)
(2)一个数据库下面有N张表(Table),等价于1个索引Index下面有N多类型(Type),
(3)一个数据库表(Table)下的数据由多行(ROW)多列(column,属性)组成,等价于1个Type由多个文档(Document)和多Field组成。
(4)在一个关系型数据库里面,schema定义了表、每个表的字段,还有表和字段之间的关系。 与之对应的,在ES中:Mapping定义索引下的Type的字段处理规则,即索引如何建立、索引类型、是否保存原始索引JSON文档、是否压缩原始JSON文档、是否需要分词处理、如何进行分词处理等。
(5)在数据库中的增insert、删delete、改update、查search操作等价于ES中的增PUT/POST、删Delete、改_update、查GET.
倒排索引
相关性得分:1)红海特工行动 (检索) 在记录中搜索: 3- 三个词命中了2个(2/3) 5- 四个词命中2个(1/2)
所以记录 3- 的相关性得分就高!
1.7 ELK是什么?
ELK=elasticsearch+Logstash+kibana
elasticsearch:后台分布式存储以及全文检索
logstash: 日志加工、“搬运工”
kibana:数据可视化展示。
ELK架构为数据分布式存储、可视化查询和日志解析创建了一个功能强大的管理链。 三者相互配合,取长补短,共同完成分布式大数据处理工作。
1.8 ES特点和优势
1)分布式实时文件存储,可将每一个字段存入索引,使其可以被检索到。
2)实时分析的分布式搜索引擎。
分布式:索引分拆成多个分片,每个分片可有零个或多个副本。集群中的每个数据节点都可承载一个或多个分片,并且协调和处理各种操作;
负载再平衡和路由在大多数情况下自动完成。
3)可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。也可以运行在单台PC上(已测试)
4)支持插件机制,分词插件、同步插件、Hadoop插件、可视化插件等。
相较于Lucene来说,Elasticsearch天然的分布式特性,让其可以支持海量的、PB级的大数据搜索。相对于Spark Streaming、Storm等大数据实时计算引擎来说,Elasticsearch天生为分布式执行数据分析操作而生的架构,海量数据量级下的近实时(秒级)性能支持,以及无比强大的搜索和聚合分析的语法支持,让ES更加适合进行大数据场景下的数据分析应用。
二、Docker下安装ES+Kibana
注意: 如果是在服务器上操作,所有跟访问url有关的一定要记得开放端口!
//拉取es镜像
docker pull elasticsearch:7.4.2
//查看镜像
[root@iZ2zegnzd0af38r6v96pcfZ test]# docker images
elasticsearch 7.4.2 b1179d41a7b4 16 months ago 855MB
//拉取kibana镜像并查看
[root@iZ2zegnzd0af38r6v96pcfZ test]# docker pull kibana:7.4.2
[root@iZ2zegnzd0af38r6v96pcfZ test]# docker images
kibana 7.4.2 230d3ded1abc 16 months ago 1.1GB
//创建es在本地的挂载目录
[root@iZ2zegnzd0af38r6v96pcfZ test]# mkdir -p /mydata/elasticsearch/config
[root@iZ2zegnzd0af38r6v96pcfZ test]# mkdir -p /mydata/elasticsearch/data
//往本地的elasticsearch.yml中写入http.host:0.0.0.0
[root@iZ2zegnzd0af38r6v96pcfZ test]# echo "http.host:0.0.0.0">>/mydata/elasticsearch/config/elasticsearch.yml
[root@iZ2zegnzd0af38r6v96pcfZ test]# cd /mydata/elasticsearch/config
[root@iZ2zegnzd0af38r6v96pcfZ config]# ls
elasticsearch.yml
[root@iZ2zegnzd0af38r6v96pcfZ config]# cat elasticsearch.yml
http.host: 0.0.0.0 //(注:这里(: 和 0 之间)必须有空格,否则会报错)
//启动容器(挂载目录+映射端口)
[root@iZ2zegnzd0af38r6v96pcfZ config]# docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx128m" -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins -d elasticsearch:7.4.2
f4ea47498fa0765f49c6993451806169b88329f1f952c7ea59ea8d7b61eaeb54(这个是容器的ID)
//检查一下是否启动成功
[root@iZ2zegnzd0af38r6v96pcfZ config]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
//发现并没有,于是看一下日志
[root@iZ2zegnzd0af38r6v96pcfZ config]# docker logs elasticsearch
"type": "server", "timestamp": "2021-03-14T12:16:05,490Z", "level": "WARN", "component": "o.e.b.ElasticsearchUncaughtExceptionHandler", "cluster.name": "elasticsearch", "node.name": "f4ea47498fa0", "message": "uncaught exception in thread [main]",
"stacktrace": ["org.elasticsearch.bootstrap.StartupException: ElasticsearchException[failed to bind service]; nested: AccessDeniedException[/usr/share/elasticsearch/data/nodes];",.....
"Caused by: java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/nodes"
//因为我们把这些数据挂载到外面了,但由于用户权限的原因,访问被禁止了(我们可以查看一下)
[root@iZ2zegnzd0af38r6v96pcfZ config]# cd ..
[root@iZ2zegnzd0af38r6v96pcfZ elasticsearch]# ls
config data plugins
[root@iZ2zegnzd0af38r6v96pcfZ elasticsearch]# ll
//ll:罗列出当前文件或目录的详细信息,含有时间、读写权限、大小、时间等信息
total 12
drwxr-xr-x 2 root root 4096 Mar 14 20:17 config
drwxr-xr-x 2 root root 4096 Mar 14 19:43 data
drwxr-xr-x 2 root root 4096 Mar 14 19:59 plugins
//可以看到只有root可读可写,所以我们要给权限(elasticsearch/下的所有文件)
[root@iZ2zegnzd0af38r6v96pcfZ elasticsearch]# chmod -R 777 /mydata/elasticsearch/
//再查看一下
[root@iZ2zegnzd0af38r6v96pcfZ elasticsearch]# ll
total 12
drwxrwxrwx 2 root root 4096 Mar 14 20:17 config
drwxrwxrwx 2 root root 4096 Mar 14 19:43 data
drwxrwxrwx 2 root root 4096 Mar 14 19:59 plugins
//于是重新启动elasticsearch容器
[root@iZ2zegnzd0af38r6v96pcfZ elasticsearch]# docker start elasticsearch
elasticsearch
[root@iZ2zegnzd0af38r6v96pcfZ elasticsearch]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f4ea47498fa0 elasticsearch:7.4.2 "/usr/local/bin/dock…" 25 minutes ago Up 34 seconds 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch
//这次我们可以发现过了一会儿容器也不会停止,并且可以在浏览器访问(主机地址:9200)
//开始安装kibana
[root@iZ2zegnzd0af38r6v96pcfZ elasticsearch]# docker run --name kibana -e ELASTICSEARCH_HOSTS=http:123.57.254.115:9200 -p 5601:5601 -d kibana:7.4.2
fd94e0dfffff8c87401f698783746876cfebb8267ab8618dcfe66c8f8875f5f4
//注: 123.57.254.115是自己的主机的ip
[root@iZ2zegnzd0af38r6v96pcfZ elasticsearch]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4673f1cb2527 kibana:7.4.2 "/usr/local/bin/dumb…" 4 seconds ago Up 3 seconds 0.0.0.0:5601->5601/tcp kibana
f4ea47498fa0 elasticsearch:7.4.2 "/usr/local/bin/dock…" 43 minutes ago Up 18 minutes 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch
//然后再访问一下kibana(主机地址:5601),成功则表示安装完成
补充的知识
- 读(read),写(write),执行r(recute)简写即为(r,w,x),亦可用数字来(4,2,1)表示
下图中文件所有者(属主)为root,所有组(属组)为root,文件名为install.log, 第一个减号“-”代表的是文件类型:
-:普通文件,d:目录文件,l:链接文件,b:设备文件,c:字符设备文件,p:管道文件
文件的权限为rw-r-r-也就是分别表示所有者(属主)有读写权限,所有组(属组)有读权限,其余人也仅有读权限。
-
docker run -e .. // -e 指定环境变量
三、初步检索
1、 _cat
GET /_cat/nodes : 查看所有节点
GET /_cat/health : 查看es健康状况
GET /_cat/master : 查看主节点
GET /_cat/indices : 查看所有索引 show databases;
2、索引一个文档(保存)
保存一个数据,保存在哪个索引的哪个类型下,指定用哪个唯一标识
PUT/POST customer/external/1; //在customer索引下的external类型下保存1号数据
"name":"John Doe"
//返回的数据: (以 _ 开头的数据是元数据)
"_index": "customer", //在那个索引下
"_type": "external", //在那个类型下
"_id": "1", //数据的唯一标识
"_version": 1, //数据的版本,再发起一次就会增加
"result": "created", //第一次保存是created(创建),后面就是updated(更新)
"_shards": //分片,集群时才考虑
"total": 2,
"successful": 1,
"failed": 0
,
"_seq_no": 0,
"_primary_term": 1
POST新增。
如果不指定id ,会自动生成id,并且每次都是**新增**(不会变成updated)。
指定id就会修改这个数据,并新增版本号
PUT可以新增可以修改。PUT必须指定id;由于PUT需要指定id,我们一般都用来做修改操作,不指定id会报错。
3、查询文档
GET customer/external/1; //查询在customer索引下的external类型下的1号数据
//返回数据
"_index": "customer", //在哪个索引
"_type": "external", //在哪个类型
"_id": "1", //记录id
"_version": 2, //版本号
"_seq_no": 1, //并发控制字段,每次更新就会+1,用来做乐观锁
"_primary_term": 1, //同上,主分片重新分配
"found": true, //找到了
"_source": //记录的具体信息
"name": "John Doe"
修改的(PUT/POST)url后面添加参数 ?if_seq_no=1&if_primary_term=1 //表示只有在满足等号条件时才会修改,否则会报409错误
(乐观锁模拟,先改的请求)
(乐观锁模拟,后改的请求)
4、更新文档
POST customer/external/1/_update; //更新在customer索引下的external类型下的1号数据
"doc":
"name":"John Doew" //带_update必须加doc,且会与原来数据进行对比,若一样就什么也不做,version,seq_no都不变,且 result是noop(第一次还是created)
//或者
POST customer/external/1;
"name":"John Doe2" //这种和下面那种都不会与原来的数据进行对比,直接更新
//或者
PUT customer/external/1;
"name":"John Doe"
5、删除文档&索引
DELETE 123.57.254.115:9200/customer/external/1 //删除在customer索引下的external类型下的1号数据
//再进行GET查询
GET customer/external/1; //会报404
DELETE 123.57.254.115:9200/customer //删除索引,但是不能直接删除type(比如这里的external),否则会报405
(试图删除type(external))
6、bulk批量API
//这种形式的话就不能在postman里测试了,需要用到kibana, 注:在kibana里就不能加ip了,否则会报错
POST /customer/external/_bulk
"index":"_id":"1" //index是保存操作?
"name":"John Doe"
"index":"_id":"2"
"name":"Jane Doe"
//返回数据
#! Deprecation: [types removal] Specifying types in bulk requests is deprecated.
"took" : 318, //花费时间ms
"errors" : false,
"items" : [
"index" :
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" :
"total" : 2,
"successful" : 1,
"failed" : 0
,
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 201
,
"index" :
"_index" : "customer",
"_type" : "external",
"_id" : "2",
"_version" : 1,
"result" : "created",
"_shards" :
"total" : 2,
"successful" : 1,
"failed" : 0
,
"_seq_no" : 1,
"_primary_term" : 1,
"status" : 201
]
//语法格式
action:metadata\\n
request body \\n
action:metadata\\n
request body \\n
//复杂实例 (delete操作的时候不需要请求体request body)
POST/_bulk
"delete":"_index":"website","_type":"blog","_id":"123"
"create":"_index":"website","_type":"blog","_id":"123"
"title": "My first blog post"
"index": "_index":"website","_type":"blog"
"title": "My second blog post"
"update":"_index":"website","_type":"blog","_id":"123"
"doc":"title":"My updated blog post"
//返回数据
#! Deprecation: [types removal] Specifying types in bulk requests is deprecated.
"took" : 293,
"errors" : false,
"items" : [
"delete" :
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 1,
"result" : "not_found",
"_shards" :
"total" : 2,
"successful" : 1,
"failed" : 0
,
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 404 //因为一开始还没有website,但不影响下面的操作!!!
,
"create" :
"_index" : "website",
"_type" : "blog",
"_id" : "123",
"_version" : 2,
"result" : "created"Elasticsearch学习笔记4:Springboot整合ES
Elasticsearch学习笔记4:Springboot整合ES