Elastic Stack——Elastic Stack简介和Elasticsearch核心详解

2022-09-24 10:01:50 浏览数 (1)

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、搜索数据
  1. 根据id搜索数据
代码语言:javascript复制
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": "女"
    }
}
  1. 搜索全部数据 Get 127.0.0.1:9200/hello/user/1001
  2. 关键字搜素数据
代码语言:javascript复制
#查询年龄等于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": "男"}
  1. 批量删除:
代码语言:javascript复制
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

0 人点赞