Elastic Stack之Elasticsearch教程
1.Elastic Stack简介
2.Elasticsearch
2.1 简介
2.2 安装
2.2.1 版本说明
2.2.2 下载
2.2.3 单机版安装
2.2.4 elasticsearch-head
2.3 基本概念
2.4 RESTful API
2.4.1 创建非结构化数据
2.4.2 插入数据
2.4.3 更新数据
2.4.4 删除数据
2.4.5 搜索数据
2.4.6 DSL搜索
2.4.7 高亮显示
2.4.8 聚合
3. 核心详解
3.1 文档
3.2 查询响应
3.2.1 pretty
3.2.2 指定响应字段
3.3 判断文档是否存在
3.4 批量操作
3.4.1 批量查询
3.4.2 _bulk操作
3.5 分页
3.6 映射
3.7 结构化查询
3.7.1 term查询
3.7.2 terms查询
3.7.3 range查询
3.7.4 exists 查询
3.7.5 match查询
3.7.6 bool查询
4. 中文分词
4.1 什么是分词
4.2 分词api
4.3 中文分词
5. 全文搜索
5.1 构造数据
5.2 单词搜索
5.3 多词搜索
5.4 组合搜索
5.5 权重
6. Elasticsearch集群
6.1 集群节点
6.2 搭建集群
6.3 分片和副本
6.4 故障转移
6.4.1 将data节点停止
6.4.2 将master节点停止
6.5 分布式文档
6.5.1 路由
6.5.2 文档写操作
6.5.3 搜索文档(单个文档)
6.5.4 全文搜索
7. Java客户端
7.1 REST客户端
7.2 构造数据
7.3 REST低级客户端
7.3.1 创建工程
7.3.2 编写测试用例
7.4 REST高级客户端
7.4.1 引入依赖
7.4.2 编写测试用例
------------------------------------------------------------------------------------------------------------------------------------
1.Elastic Stack简介
如果你没有听说过Elastic Stack,那你一定听说过ELK,实际上ELK是三款软件的简称,分别是Elasticsearch、Logstash、Kibana组成,在发展的过程中,又有新成员Beats的加入,所以就形成了Elastic Stack。所以说,ELK是旧的称呼,Elastic Stack是新的名字。
全系的Elastic Stack技术栈包括:
Elasticsearch
Elasticsearch 基于java,是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等。
Logstash
Logstash 基于java,是一个开源的用于收集,分析和存储日志的工具。
Kibana
Kibana 基于nodejs,也是一个开源和免费的工具,Kibana可以为 Logstash 和 ElasticSearch 提供的日志分析友好的Web 界面,可以汇总、分析和搜索重要数据日志。
Beats
Beats是elastic公司开源的一款采集系统监控数据的代理agent,是在被监控服务器上以客户端形式运行的数据收集器的统称,可以直接把数据发送给Elasticsearch或者通过Logstash发送给Elasticsearch,然后进行后续的数据分析活动。
Logstash和Beats在数据收集功能上有一定的重复,现在更多的是采用Beats来做数据采集,Logstash更多的做一些数据的处理,包括字符串分割、字符串提取,早期没有Beats的时候,使用Logstash做数据采集,现在有了Beats,就使用Beats,因为Beats功能更加强大。
Beats是一个综合的名字,它有一些子项目组成,由如下组成:
Packetbeat:是一个网络数据包分析器,用于监控、收集网络流量信息,Packetbeat嗅探服务器之间的流量,解析应用层协议,并关联到消息的处理,其支 持ICMP (v4 and v6)、DNS、HTTP、Mysql、PostgreSQL、Redis、MongoDB、Memcache等协议;
Filebeat:用于监控、收集服务器日志文件,其已取代 logstash forwarder;
Metricbeat:可定期获取外部系统的监控指标信息,其可以监控、收集 Apache、HAProxy、MongoDB、MySQL、Nginx、PostgreSQL、Redis、System、Zookeeper等服务;
Winlogbeat:用于监控、收集Windows系统的日志信息;
2.Elasticsearch
2.1 简介
ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口操作ES,也可以利用Java API。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
官网:https://www.elastic.co/cn/elasticsearch/
2.2 安装
2.2.1 版本说明
Elasticsearch的发展是非常快速的,所以在ES5.0之前,ELK的各个版本都不统一,出现了版本号混乱的状态,所以从5.0开始,所有Elastic Stack中的项目全部统一版本号。目前最新版本是7.9.3,我们将基于这一版本进行学习。
2.2.2 下载
地址:https://www.elastic.co/cn/downloads/elasticsearch
2.2.3 单机版安装
将下载好的elasticsearch解压到指定目录:tar -zxvf elasticsearch-7.9.3-linux-x86_64.tar.gz -C /opt/
修改Linux系统的限制配置,将文件创建数修改为65536个,使用root用户修改。
elsearch hard nofile 65536
elsearch soft nproc 4096
elsearch hard nproc 4096
再次启动:bin/elasticsearch -d 说明-d是指后台启动
验证: curl http://localhost:9200 如下,表示单机版启动成功,如果启动还报错,
2.2.4 elasticsearch-head
由于ES官方并没有为ES提供界面管理工具,仅仅是提供了后台的服务。elasticsearch-head是一个为ES开发的一个页面客户端工具,其源码托管于GitHub,地址为:https://github.com/mobz/elasticsearch-head
head提供了4种安装方式:
源码安装,通过npm run start启动(不推荐)
通过docker安装(推荐)
通过chrome插件安装(推荐)
通过ES的plugin方式安装(不推荐)
这里安装的谷歌插件,通过浏览器进行访问:
2.3 基本概念
2.4 RESTful API
在Elasticsearch中,提供了功能丰富的RESTful API的操作,包括基本的CRUD、创建索引、删除索引等操作。
2.4.1 创建非结构化数据
"settings": {
"index": {
"number_of_shards": "5",
"number_of_replicas": "0"
}
}
}
"acknowledged": true
}
2.4.2 插入数据
#数据
{
"id": 1001,
"name": "张三",
"age": 20,
"sex": "男"
}
{
"id": 1002,
"name": "张三",
"age": 20,
"sex": "男"
}
2.4.3 更新数据
在Elasticsearch中,文档数据是不为修改的,但是可以通过覆盖的方式进行更新。
PUT /haoke/user/1001
{
"id": 1001,
"name": "张三",
"age": 21,
"sex": "女"
}
可以看到数据已经被覆盖了。
问题来了,可以局部更新吗? -- 可以的。
前面不是说,文档数据不能更新吗? 其实是这样的:在内部,依然会查询到这个文档数据,然后进行覆盖操作,步骤如下:
1. 从旧文档中检索JSON
2. 修改它
3. 删除旧文档
4. 索引新文档
示例:
#注意:这里多了_update标识 POST /haoke/user/1001/_update
{
"doc": {
"age": 23
}
}
2.4.4 删除数据
在Elasticsearch中,删除文档数据,只需要发起DELETE请求即可。
DELETE /haoke/user/1001
说明:删除一个文档也不会立即从磁盘上移除,它只是被标记成已删除。Elasticsearch将会在你之后添加更多索引的时候才会在后台进行删除内容的清理。
2.4.5 搜索数据
根据id搜索数据 GET /haoke/user/yAjcnHUBau-AZQnWpW8f
搜索全部数据 GET /haoke/user/_search (默认返回10条数据)
关键字搜素数据
#查询年龄等于20的用户
2.4.6 DSL搜索
#请求体 match只是查询的一种
{
"query": {
"match": {
"age": 20
}
}
}
现有数据:
#请求数据
{
"query": {
"bool": {
"filter": {
"range": {
"age": {
"gt": 30
}
}
},
"must": {
"match": {
"sex": "男"
}
}
}
}
}
POST /haoke/user/_search
#请求数据
{
"query": {
"match": {
"name": "张三 李四"
}
}
}
2.4.7 高亮显示
POST /haoke/user/_search
{
"query": {
"match": {
"name": "张三 李四"
}
},
"highlight": {
"fields": {
"name": {}
}
}
}
2.4.8 聚合
在Elasticsearch中,支持聚合操作,类似SQL中的group by操作。
POST /haoke/user/_search
{
"aggs": {
"all_interests": {
"terms": {
"field": "age"
}
}
}
}
从结果可以看出,年龄31的有2条数据,20的有2条数据
3. 核心详解
3.1 文档
在Elasticsearch中,文档以JSON格式进行存储,可以是复杂的结构,如:
{
"_index": "haoke",
"_type": "user",
"_id": "1005",
"_version": 1,
"_score": 1,
"_source": {
"id": 1005,
"name": "孙七",
"age": 27,
"sex": "女",
"card": {
"card_number": "123456789"
}
}
}
提示:事实上,我们的数据被存储和索引在分片(shards)中,索引只是一个把一个或多个分片分组在一起的逻辑空间。然而,这只是一些内部细节——我们的程序完全不用关心分片。对于我们的程序而言,文档存储在索引(index)中。剩下的细节由Elasticsearch关心既可。
_type 在应用中,我们使用对象表示一些“事物”,例如一个用户、一篇博客、一个评论,或者一封邮件。每个对象都属于一个类(class),这个类定义了属性或与对象关联的数据。 user 类的对象可能包含姓名、性别、年龄和Email地址。
在关系型数据库中,我们经常将相同类的对象存储在一个表里,因为它们有着相同的结构。同理,在Elasticsearch中,我们使用相同类型(type)的文档表示相同的“事物”,因为他们的数据结构也是相同的。
每个类型(type)都有自己的映射(mapping)或者结构定义,就像传统数据库表中的列一样。所有类型下的文档被存储在同一个索引下,但是类型的映射(mapping)会告诉Elasticsearch不同的文档如何被索引。_type 的名字可以是大写或小写,不能包含下划线或逗号。我们将使用 blog 做为类型名。
_id id仅仅是一个字符串,它与 _index 和 _type 组合时,就可以在Elasticsearch中唯一标识一个文档。当创建一个文档,你可以自定义 _id ,也可以让Elasticsearch帮你自动生成(32位长度)。
3.2 查询响应
3.2.1 pretty
可以在查询url后面添加pretty参数,使得返回的json更易查看。
3.2.2 指定响应字段
在响应的数据中,如果我们不需要全部的字段,可以指定某些需要的字段进行返回
GET /haoke/user/1001?_source=id,name
如不需要返回元数据,仅仅返回原始数据,可以这样: GET /haoke/user/1001/_source
还可以这样: GET /haoke/user/1001/_source?_source=id,name
3.3 判断文档是否存在
如果我们只需要判断文档是否存在,而不是查询文档内容,那么可以这样:HEAD /haoke/user/1001 有返回200状态码,没有返回404状态码
3.4 批量操作
有些情况下可以通过批量操作以减少网络请求。如:批量查询、批量插入数据。
3.4.1 批量查询
POST /haoke/user/_mget
{
"ids": [
"1001",
"1003"
]
}
3.4.2 _bulk操作
POST /haoke/user/_bulk
在Elasticsearch中,支持批量的插入、修改、删除操作,都是通过_bulk的api完成的。请求格式如下:(请求格式不同寻常)
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
...
批量插入数据:
{"create":{"_index":"haoke","_type":"user","_id":2001}}
{"id":2001,"name":"name1","age": 20,"sex": "男"}
{"create":{"_index":"haoke","_type":"user","_id":2002}}
{"id":2002,"name":"name2","age": 20,"sex": "男"}
{"create":{"_index":"haoke","_type":"user","_id":2003}}
{"id":2003,"name":"name3","age": 20,"sex": "男"}
注意最后一行的回车。
{"delete":{"_index":"haoke","_type":"user","_id":2002}}
{"delete":{"_index":"haoke","_type":"user","_id":2003}}
整个批量请求需要被加载到接受我们请求节点的内存里,所以请求越大,给其它请求可用的内存就越小。有一个最佳的bulk请求大小。超过这个大小,性能不再提升而且可能降低。
最佳大小,当然并不是一个固定的数字。它完全取决于你的硬件、你文档的大小和复杂度以及索引和搜索的负载。
幸运的是,这个最佳点(sweetspot)还是容易找到的:试着批量索引标准的文档,随着大小的增长,当性能开始降低,说明你每个批次的大小太大了。开始的数量可以在1000~5000个文档之间,如果你的文档非常大,可以使用较小的批次。
通常着眼于你请求批次的物理大小是非常有用的。一千个1kB的文档和一千个1MB的文档大不相同。一个好的批次最好保持在5-15MB大小间。
3.5 分页
和SQL使用 LIMIT 关键字返回只有一页的结果一样,Elasticsearch接受 from 和 size 参数:
size: 结果数,默认10
from: 跳过开始的结果数,默认0
如果你想每页显示5个结果,页码从1到3,那请求如下:
GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10
应该当心分页太深或者一次请求太多的结果。结果在返回前会被排序。但是记住一个搜索请求常常涉及多个分片。每个分片生成自己排好序的结果,它们接着需要集中起来排序以确保整体排序正确。
GET /haoke/user/_search?size=1&from=2
在集群系统中深度分页
为了理解为什么深度分页是有问题的,让我们假设在一个有5个主分片的索引中搜索。当我们请求结果的第一页(结果1到10)时,每个分片产生自己最顶端10个结果然后返回它们给请求节点(requesting node),它再排序这所有的50个结果以选出顶端的10个结果。
现在假设我们请求第1000页——结果10001到10010。工作方式都相同,不同的是每个分片都必须产生顶端的10010个结果。然后请求节点排序这50050个结果并丢弃50040个!
你可以看到在分布式系统中,排序结果的花费随着分页的深入而成倍增长。这也是为什么网络搜索引擎中任何语句不能返回多于1000个结果的原因。
3.6 映射
前面我们创建的索引以及插入数据,都是由Elasticsearch进行自动判断类型,有些时候我们是需要进行明确字段类型的,否则,自动判断的类型和实际需求是不相符的。
自动判断的规则如下:
Elasticsearch中支持的类型如下:
string类型在ElasticSearch 旧版本中使用较多,从ElasticSearch 5.x开始不再支持string,由text和 keyword类型替代。
text类型,当一个字段是要被全文搜索的,比如Email内容、产品描述,应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text类型的字段不用于排序,很少用于聚合。
keyword类型适用于索引结构化的字段,比如email地址、主机名、状态码和标签。如果字段需要进行过滤(比如查找已发布博客中status属性为published的文章)、排序、聚合。
keyword类型的字段只能通过精确值搜索到
创建明确类型的索引:PUT /yz_test
{
"settings": {
"index": {
"number_of_shards": "2",
"number_of_replicas": "0"
}
},
"mappings": {
"person": {
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "integer"
},
"mail": {
"type": "keyword"
},
"hobby": {
"type": "text"
}
}
}
}
}
3.7 结构化查询
3.7.1 term查询
3.7.2 terms查询
3.7.3 range查询
3.7.4 exists 查询
3.7.5 match查询
3.7.6 bool查询
4. 中文分词
4.1 什么是分词
4.2 分词api
4.3 中文分词
5. 全文搜索
5.1 构造数据
5.2 单词搜索
5.3 多词搜索
5.4 组合搜索
5.5 权重
6. Elasticsearch集群
6.1 集群节点
6.2 搭建集群
6.3 分片和副本
6.4 故障转移
6.4.1 将data节点停止
6.4.2 将master节点停止
6.5 分布式文档
6.5.1 路由
6.5.2 文档写操作
6.5.3 搜索文档(单个文档)
6.5.4 全文搜索
7. Java客户端
7.1 REST客户端
7.2 构造数据
7.3 REST低级客户端
7.3.1 创建工程
7.3.2 编写测试用例
7.4 REST高级客户端
7.4.1 引入依赖
7.4.2 编写测试用例