1、Elastic Stack简介
如果你没有听说过Elastic Stack,那你一定听说过ELK,实际上ELK是三款软件的简称,分别是Elasticsearch、 Logstash、Kibana组成,在发展的过程中,又有新成员Beats的加入,所以就形成了Elastic Stack。所以说,ELK是旧的称呼,Elastic Stack是新的名字。
* Elasticsearch Elasticsearch 基于java,是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引 副本机制,restful风格接口,多数据源,自动搜索负载等。 * Logstash Logstash 基于java,是一个开源的用于收集,分析和存储日志的工具。 * Kibana Kibana 基于nodejs,也是一个开源和免费的工具,Kibana可以为 Logstash 和 ElasticSearch 提供的日志分析友好的 Web 界面,可以汇总、分析和搜索重要数据日志。 * Beats Beats是elastic公司开源的一款采集系统监控数据的代理agent,是在被监控服务器上以客户端形式运行的数据收集 器的统称,可以直接把数据发送给Elasticsearch或者通过Logstash发送给Elasticsearch,然后进行后续的数据分析活 动。
Beats由如下组成: 1. Packetbeat:是一个网络数据包分析器,用于监控、收集网络流量信息,Packetbeat嗅探服务器之间的流量, 解析应用层协议,并关联到消息的处理,其支 持ICMP (v4 and v6)、DNS、HTTP、Mysql、PostgreSQL、Redis、MongoDB、Memcache等协议; 2. Filebeat:用于监控、收集服务器日志文件,其已取代 logstash forwarder; 3. Metricbeat:可定期获取外部系统的监控指标信息,其可以监控、收集 Apache、HAProxy、MongoDB MySQL、Nginx、PostgreSQL、Redis、System、Zookeeper等服务; 4. Winlogbeat:用于监控、收集Windows系统的日志信息;
2、Elasticsearch
2.1、简介
ElasticSearch是一个基于Lucene的搜索服务器。 它提供了一一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。 官网:https://www.elastic.co/cn/elasticsearch
2.2、安装
下载地址::https://www.elastic.co/cn/downloads/elasticsearch 解压即可 点击bin目录下的elasticsearch.bat即可启动服务器, http://localhost:9200/ 访问得到相关的版本信息
解决允许跨域访问 在 /config/elasticsearch.yml 文件最后添加如下代码
代码语言:javascript复制http.cors.enabled: true
http.cors.allow-origin: "*"
2.3、可视化工具elasticsearch-head
由于ES官方并没有为ES提供界面管理工具,仅仅是提供了后台的服务。elasticsearch-head是一个为ES开发的一个页面客户端工具,其源码托管于GitHub, 地址为:https://github.com/mobz/elasticsearch-head
安装启动 1. 首先要有node环境 2. 使用npm install安装模块包 3. npm run srart即可后台启动elasticsearch-head的服务器 4. 使用 http://localhost:9100 即可访问可视化页面
2.4、基本概念
索引
- 索引(index)是Elasticsearch对逻辑数据的逻辑存储,所以它可以分为更小的部分。
- 可以把索引看成关系型数据库的表,索引的结构是为快速有效的全文索引准备的,特别是它不存储原始值。
- Elasticsearch可以把索引存放在一台机器或者分散在多台服务器上,每个索引有一或多个分片(shard),每个 分片可以有多个副本(replica)。
文档
- 存储在Elasticsearch中的主要实体叫文档(document)。用关系型数据库来类比的话,一个文档相当于数据库表中的一行记录。
- Elasticsearch和MongoDB中的文档类似,都可以有不同的结构,但Elasticsearch的文档中,相同字段必须有相同类型。
- 文档由多个字段组成,每个字段可能多次出现在一个文档里,这样的字段叫多值字段(multivalued)。
- 每个字段的类型,可以是文本、数值、日期等。字段类型也可以是复杂类型,一个字段包含其他子文档或者数组。
映射
- 所有文档写进索引之前都会先进行分析,如何将输入的文本分割为词条、哪些词条又会被过滤,这种行为叫做映射(mapping)。一般由用户自己定义规则。
文档类型
- 在Elasticsearch中,一个索引对象可以存储很多不同用途的对象。例如,一个博客应用程序可以保存文章和评论。
- 每个文档可以有不同的结构。
- 不同的文档类型不能为相同的属性设置不同的类型。例如,在同一索引中的所有文档类型中,一个叫title的字段必须具有相同的类型。
2.5、RESTful API
在Elasticsearch中,提供了功能丰富的RESTful API的操作,包括基本的CRUD、创建索引、删除索引等操作。
2.5.1、创建非结构化索引
在Lucene中,创建索引是需要定义字段名称以及字段的类型的,在Elasticsearch中提供了非结构化的索引,就是不需要创建索引结构,即可写入数据到索引中,实际上在Elasticsearch底层会进行结构化操作,此操作对用户是透明的。 创建空索引:
代码语言:javascript复制put: 127.0.0.1:9200/hello
#第一个参数:分片数
#第二个参数:副本数
{
"settings":{
"index":{
"number_of_shards":"2",
"number_of_replicas":"0"
}
}
}
#删除索引
DELETE: 127.0.0.1:9200/hello
{
"acknowledged": true
}
2.5.2、插入数据
URL规则: POST /{索引}/{类型}/{id}
代码语言:javascript复制POST 127.0.0.1:9200/hello/user/1001
#数据
{
"id":1001,
"name":"张三",
"age":20,
"sex":"男"
}
#响应
{
"_index":"haoke",
"_type":"user",
"_id":"1",
"_version":1,
"result":"created",
"_shards":{
"total":1,
"successful":1,
"failed":0
},
"_seq_no":0,
"_primary_term":1
}
不指定id插入数据:
代码语言:javascript复制POST 127.0.0.1:9200/hello/user/
{
"id":1002,
"name":"张三",
"age":20,
"sex":"男"
}
2.5.3、更新数据
在Elasticsearch中,文档数据是不为修改的,但是可以通过覆盖的方式进行更新。
代码语言:javascript复制PUT 127.0.0.1:9200/hello/user/1001
{
"id":1001,
"name":"张三",
"age":21,
"sex":"女"
}
这时到数据已经被覆盖了,如果有字段没有值,那么值就为空 如果要局部更新
代码语言:javascript复制#注意:这里多了_update标识和"doc"
POST 127.0.0.1:9200/hello/user/1001_update
{
"doc":{
"age":23
}
}
可以看到数据已经被局部更新了。
2.5.4、删除数据
在Elasticsearch中,删除文档数据,只需要发起DELETE请求即可。 DELETE 127.0.0.1:9200/hello/user/1001 需要注意的是,result表示已经删除,version也更加了。 如果删除一条不存在的数据,会响应404:
2.5.5、搜索数据
- 根据id搜索数据
Get 127.0.0.1:9200/hello/user/1001
#响应数据
{
"_index": "hello",
"_type": "user",
"_id": "1001",
"_version": 3,
"found": true,
"_source": {
"id": 1001,
"name": "张三",
"age": 66,
"sex": "女"
}
}
- 搜索全部数据 Get 127.0.0.1:9200/hello/user/1001
- 关键字搜素数据
#查询年龄等于20的用户
GET 127.0.0.1:9200/hello/user/_search?q=age:20
2.5.6、DSL搜索
Elasticsearch提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。 DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现。
代码语言:javascript复制#实现:查询年龄等于20的用户
POST 127.0.0.1:9200/hello/user/_search
#请求体
{
"query":{
"match":{
"age":"20"
}
}
}
#实现:查询年龄大于30岁的男性用户。
POST 127.0.0.1:9200/hello/user/_search
#请求体
{
"query":{
"bool":{
"filter":{
"range":{
"age":{
"gt":25
}
}
},
"must":{
"match":{
"sex":"男"
}
}
}
}
}
#实现:高亮显示
POST 127.0.0.1:9200/hello/user/_search
#请求体
{
"query":{
"match":{
"name":"张三 李四"
}
},
"highlight":{
"fields":{
"name":{
}
}
}
}
#实现:聚合
在Elasticsearch中,支持聚合操作,类似SQL中的group by操作。
POST 127.0.0.1:9200/hello/user/_search
#请求体
{
"aggs":{
"all_interests":{
"terms":{
"field":"age"
}
}
}
}
索引
代码语言:javascript复制{
"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、核心详解
3.1、文档
在Elasticsearch中,文档以JSON格式进行存储,可以是复杂的结构 * 元数据(metadata) 一个文档不只有数据。它还包含了元数据(metadata)——关于文档的信息。三个必须的元数据节点是:
* _index 索引(index)类似于关系型数据库里的“数据库”——它是我们存储和索引关联数据的地方 * _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、指定响应字段
在响应的数据中,如果我们不需要全部的字段,可以指定某些需要的字段进行返回
代码语言:javascript复制GET http://127.0.0.1:9200/itcast/person/If6JeXEBTDVmGkzkSswT?_source=age,name
响应数据
{
"_index": "itcast",
"_type": "person",
"_id": "If6JeXEBTDVmGkzkSswT",
"_version": 1,
"found": true,
"_source": {
"name": "张三",
"age": 20
}
}
如不需要返回元数据,仅仅返回原始数据,可以这样:
代码语言:javascript复制GET http://127.0.0.1:9200/itcast/person/If6JeXEBTDVmGkzkSswT/_source
#响应数据
{
"name": "张三",
"age": 20,
"mail": "111@qq.com",
"hobby": "羽毛球、乒乓球、足球"
}
还可以这样:
GET http://127.0.0.1:9200/itcast/person/If6JeXEBTDVmGkzkSswT/_source?_source=age,name
#响应数据
{
"name": "张三",
"age": 20
}
3.3、判断文档是否存在
如果我们只需要判断文档是否存在,而不是查询文档内容,那么可以这样: HEAD http://127.0.0.1:9200/itcast/person/1001/ 如果文档存在:响应头信息状态码200 如果文档不存在:响应头信息状态码404
3.4、批量操作
有些情况下可以通过批量操作以减少网络请求。如:批量查询、批量插入数据。
3.4.1、批量查询
_mget
代码语言:javascript复制http://127.0.0.1:9200/itcast/person/_mget
{
"ids" : [ "1001", "1003" ]
}
如果,某一条数据不存在,不影响整体响应,需要通过found的值进行判断是否查询到数据。
3.4.2、_bulk操作
在Elasticsearch中,支持批量的插入、修改、删除操作,都是通过_bulk的api完成的。 请求格式如下:(请求格式不同寻常)
代码语言:javascript复制{ action: { metadata }}n
{ request body }n
{ action: { metadata }}n
{ request body }n
...(这个一定要有一个换行)
注意:末尾一定要有一个换行 1. 批量插入数据:
代码语言:javascript复制POST 127.0.0.1:9200/itcast/_bulk
{"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": "男"}
- 批量删除:
POST 127.0.0.1:9200/itcast/_bulk
{"delete":{"_index":"haoke","_type":"user","_id":2001}}
{"delete":{"_index":"haoke","_type":"user","_id":2002}}
{"delete":{"_index":"haoke","_type":"user","_id":2003}}
由于delete没有请求体,所以,action的下一行直接就是下一个action。 其他操作类似。 一次请求多少性能最高? 通常着眼于你请求批次的物理大小是非常有用的。一千个1kB的文档和一千个1MB的文档大不相同。一个好的 批次最好保持在5-15MB大小间。
3.5、分页
和SQL使用 LIMIT 关键字返回只有一页的结果一样,Elasticsearch接受 from 和 size 参数: size: 结果数,默认10 from: 跳过开始的结果数,默认0 如果你想每页显示5个结果,页码从1到3,那请求如下:
代码语言:javascript复制GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10
GET 127.0.0.1:9200/hello/user/_search?size=2&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类型的字段只能通过精 确值搜索到。
创建明确类型的索引:
代码语言:javascript复制PUT`127.0.0.1:9200/itcast
{
"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"
}
}
}
}
}
查看映射: GET 127.0.0.1:9200/itcast/_mapping 插入数据:
代码语言:javascript复制POST 127.0.0.1:9200/itcast/_bulk
{"index":{"_index":"itcast","_type":"person"}}
{"name":"张三","age": 20,"mail": "111@qq.com","hobby":"羽毛球、乒乓球、足球"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"李四","age": 21,"mail": "222@qq.com","hobby":"羽毛球、乒乓球、足球、篮球"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"王五","age": 22,"mail": "333@qq.com","hobby":"羽毛球、篮球、游泳、听音乐"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"赵六","age": 23,"mail": "444@qq.com","hobby":"跑步、游泳"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"孙七","age": 24,"mail": "555@qq.com","hobby":"听音乐、看电影"}
测试搜索:
代码语言:javascript复制POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"match":{
"hobby":"音乐"
}
}
}
3.7、结构化查询
3.7.1、term查询
term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型):
代码语言:javascript复制{ "term": { "age": 26 }}
{ "term": { "date": "2014-09-01" }}
{ "term": { "public": true }}
{ "term": { "tag": "full_text" }}
#示例
POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"term":{
"age":20
}
}
}
3.7.2、terms查询
terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配:
代码语言:javascript复制POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"terms":{
"age" : [20,21]
}
}
}
3.7.3、range查询
range 过滤允许我们按照指定范围查找一批数据: 范围操作符包含: gt :: 大于 gte :: 大于等于 lt :: 小于 lte :: 小于等于 示例
代码语言:javascript复制POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"range":{
"age":{
"gte":20,
"lte":22
}
}
}
}
3.7.4、exists 查询
exists 查询可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的 IS_NULL 条件
代码语言:javascript复制POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"exists":{
"field": "hobby"
}
}
}
3.6.5、match查询
match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。 如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析 match 一下查询字符: 如果用 match 下指定了一个确切值,在遇到数字,日期,布尔值或者 not_analyzed 的字符串时,它将为你搜索你 给定的值:
代码语言:javascript复制{ "match": { "age": 26 }}
{ "match": { "date": "2014-09-01" }}
{ "match": { "public": true }}
{ "match": { "tag": "full_text" }}
3.7.6、bool查询
- bool 查询可以用来合并多个条件查询结果的布尔逻辑,它包含一下操作符:
- must :: 多个查询条件的完全匹配,相当于 and 。
- must_not :: 多个查询条件的相反匹配,相当于 not 。
- should :: 至少有一个查询条件匹配, 相当于 or 。
这些参数可以分别继承一个查询条件或者一个查询条件的数组:
代码语言:javascript复制POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"bool":{
"must":{
"match":{"hobby":"足球"}
},
"must_not":{
"match":{"hobby":"音乐"}
},
"should":[
{
"match":{
"hobby":"足球"
}
},
{
"match":{
"hobby":"羽毛球"
}
}
]
}
}
}
3.8、过滤查询
前面讲过结构化查询,Elasticsearch也支持过滤查询,如term、range、match等。 示例:查询年龄为20岁的用户。
代码语言:javascript复制POST 127.0.0.1:9200/itcast/person/_search
{
"query":{
"bool":{
"filter":{
"term":{
"age":20
}
}
}
}
}
查询和过滤的对比 * 一条过滤语句会询问每个文档的字段值是否包含着特定值。 * 查询语句会询问每个文档的字段值与特定值的匹配程度如何。 一条查询语句会计算每个文档与查询语句的相关性,会给出一个相关性评分 _score,并且 按照相关性对匹配到的文档进行排序。 这种评分方式非常适用于一个没有完全配置结果的全文本搜索。 * 一个简单的文档列表,快速匹配运算并存入内存是十分方便的, 每个文档仅需要1个字节。这些缓存的过滤结果 集与后续请求的结合使用是非常高效的。 * 查询语句不仅要查找相匹配的文档,还需要计算每个文档的相关性,所以一般来说查询语句要比 过滤语句更耗时,并且查询结果也不可缓存。
建议: 做精确匹配搜索时,最好用过滤语句,因为过滤语句可以缓存数据。
配套软件和教程下载
点击下载 链接:https://pan.baidu.com/s/1HJbA3Wsgbuqyd8pX4g7cpA 提取码:e506