1. 前言:
先从官方入门视频、官方文档和一些入门博客入手学习。
推荐博客系列:
https://www.cnblogs.com/qdhxhz/p/11448451.html
2. 入门:
- 如何下载/运行 Elasticsearch
- 使用容器环境安装ES和Kibana
- 在Linux系统中配置ES集群
- Elasticsearch概念简析
- 通过REST API执行CRUD
- ES集群相关命令
- 索引CRUD命令
- 文档CRUD命令
- 举例
- 关于查询
- Query查询
- Filter查询
- 举例
- 复合查询
- 聚合:Elasticsearch 的面向和分析的主功能
- 聚合概念
- Metric聚合
- Bucket聚合
2.1. 如何下载/运行 Elasticsearch,及其先决条件
可以通过直接下载或者包管理工具下载ES和Kibana到本地,也可以使用容器安装ELK。
2.1.1. 使用容器环境安装ES和Kibana
通过docker可以运行单节点ES,也可以运行ES集群(通过compose),这里先安装单节点ES和单节点Kibana组成集群。
使用容器环境安装ES:https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html
- 创建桥接网络elastic
docker network create elastic
- 拉取es7镜像
docker pull docker.elastic.co/elasticsearch/elasticsearch:7.17.0
- 创建容器es01-test,网络为elastic,镜像为es7
docker run --name es01-test --net elastic -p 127.0.0.1:9200:9200 -p 127.0.0.1:9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.17.0
注意: 9200 是供 http 访问端口,9300 是供 tcp 访问的端口,如果不做端口映射,浏览器就不能访问 elasticsearch 的服务。 - 查看es
http://127.0.0.1:9200
使用容器环境安装Kibana:https://www.elastic.co/guide/en/kibana/current/docker.html
- 在新的终端,拉kibana镜像
docker pull docker.elastic.co/kibana/kibana:7.17.0
- 跑容器kib01-test
docker run --name kib01-test --net elastic -p 127.0.0.1:5601:5601 -e "ELASTICSEARCH_HOSTS=http://es01-test:9200" docker.elastic.co/kibana/kibana:7.17.0
- 查看kibana
http://localhost:5601
这里kibana是没有数据的,需要添加,可以添加一个示例数据,我这里添加web log。
终止、移除容器:
docker stop es01-test
docker stop kib01-test
docker network rm elastic
docker rm es01-test
docker rm kib01-test
2.1.2. 在Linux系统上配置Elasticsearch集群
集群基础配置:https://www.elastic.co/guide/en/elasticsearch/reference/7.17/important-settings.html#path-settings
在elasticsearch.yml中可以配置存储路径(不建议动),集群名称,节点名称,网络等等。以及重要生产环境配置:discovery和cluster formation,这两项配置能使集群中的节点发现彼此并选举出一个主节点(master node)。
cluster.name:设置集群名称
node.name:设置节点名称
network.host:设置网络地址,默认是127.0.0.1和[::1]
,可以用于开发但是不能用于生产。修改这个IP会使ES从开发模式变成生产模式,ES启动检测会发生变化。
discovery.seed**_hosts:默认情况下,没有进行网络配置时,ES会绑定本地IP并监听9300和9305端口,与所在主机上的其他ES节点构成集群。当想要进行集群配置时,该参数可以接受集群中所有符合主节点条件的节点地址构成的 YAML 序列或数组(以 - 开头)。每个地址可以是 IP 地址,也可以是能够通过 DNS 解析为一个或多个 IP 地址的主机名。总之该参数下的节点能够被选举为主节点。 cluster.initial_master_nodes:当第一次启动 Elasticsearch 集群时, 集群引导步骤会确定在第一次选举中计票的符合主节点资格的节点集。在生产模式下启动新集群时,必须通过此设置明确列出应在第一次选举中计票的符合主节点选举条件的节点集。注意!在集群首次启动成功后需要在各节点删除此配置,不要在重启集群或向集群中加入新节点时使用该配置** 该配置项只能使用节点名称(node name),以YAML数组形式列出。
2.2. Elasticsearch概念简析
2.2.1. Index
索引index是文档doc的容器,是一类文档的集合。
作为名词,类比关系型数据库,索引相当于SQL中的一个Database。索引由其名称(必须为全小写字符)进行标识。
作为动词,含义为保存一个文档到索引的过程。这类似于SQL语句中的 INSERT关键词。如果该文档已存在时那就相当于数据库的UPDATE。
关系型数据库通过增加一个B+树索引到指定的列上,以便提升数据检索速度。索引ElasticSearch 使用了一个叫做倒排索引的结构来达到相同的目的。mapping就是index的结构,相当于关系型数据库中的库表结构
2.2.2. Document、Doc
Index 里面单条的记录称为Document(文档)。等同于关系型数据库表中的行。
- _index:文档所属索引名称。
- _type:文档所属类型名。
- _id:Doc的主键。在写入的时候,可以指定该Doc的ID值,如果不指定,则系统自动生成一个唯一的UUID值。
- _version:文档的版本信息。Elasticsearch通过使用version来保证对文档的变更能以正确的顺序执行,避免乱序造成的数据丢失。
- _seq_no:严格递增的顺序号,每个文档一个,Shard级别严格递增,保证后写入的Doc的_seq_no大于先写入的Doc的_seq_no。
- _primary_term:_/primary_term也和_seq_no一样是一个整数,每当Primary Shard发生重新分配时,比如重启,Primary选举等,_primary_term会递增1
- found:查询的ID正确那么ture, 如果 Id 不正确,就查不到数据,found字段就是false。
- _source:文档的原始JSON数据。
2.2.3. Type(被淘汰)
在7.0开始,一个索引只能建一个Type为_doc
2.2.4. Cluster
ElasticSearch集群实际上是一个分布式系统,它需要具备两个特性:高可用性和可扩展性。
- 允许有节点停止服务
- 部分节点丢失,不会丢失数据
- 随着请求量的不断提升,数据量的不断增长,系统可以将数据分布到其他节点,实现水平扩展
集群健康值有绿黄红三种状态:
- Green:所有主要分片和复制分片都可用
- Yellow:所有主要分片可用,但不是所有复制分片都可用
- Red:不是所有的主要分片都可用。当集群状态为red,它仍然正常提供服务,它会在现有存活分片中执行请求,我们需要尽快修复故障分片,防止查询数据的丢失。
集群引导(Bootstrapping)是指首次启动 Elasticsearch集群需要在集群中的一个或多个符合主节点的节点上明确定义初始的主节点集。
从技术上讲,在集群中设置一个符合主节点资格的节点就足够cluster.initial_master_nodes了,并且只在设置值中提及该单个节点,但这在集群完全形成之前没有提供容错能力。
因此,最好使用至少三个符合主节点资格的节点进行引导,每个节点的cluster.initial_master_nodes设置都包含所有三个节点。
2.2.5. Node
节点是一个ElasticSearch的实例,其本质就是一个Java进程。一台机器上可以运行多个ElasticSearch实例,但是建议在生产环境中一台机器上只运行一个ElasticSearch实例。Node是组成集群的一个单独的服务器,用于存储数据并提供集群的搜索和索引功能。
与集群一样,节点也有一个唯一名字,默认在节点启动时会生成一个uuid作为节点名,该名字也可以手动指定。
单个集群可以由任意数量的节点组成。如果只启动了一个节点,则会形成一个单节点的集群。
2.2.6. 分片(Shard)
Primary Shard(主分片)
- ES中的shard用来解决节点的容量上限问题,通过主分片,可以将数据分布到集群内的所有节点之上。
- 一个节点对应一个ES实例
- 一个节点可以有多个index(索引)
- 一个index可以有多个shard(分片)
- 一个分片是一个lucene index(此处的index是lucene自己的概念,与ES的index不是一回事)
- 主分片数是在索引创建时指定,后续不允许修改,除非Reindex
- 一个索引中的数据保存在多个分片中(默认为一个),相当于水平分表。一个分片便是一个Lucene 的实例,它本身就是一个完整的搜索引擎。我们的文档被存储和索引到分片内,但是应用程序是直接与索引而不是与分片进行交互。
Replica Shard(副本)
- 服务高可用:由于数据只有一份,如果一个node挂了,那存在上面的数据就都丢了,有了replicas,只要不是存储这条数据的node全挂了,数据就不会丢。因此分片副本不会与主分片分配到同一个节点
- 扩展性能:通过在所有replicas上并行搜索提高搜索性能.由于replicas上的数据是近实时的(near realtime),因此所有replicas都能提供搜索功能,通过设置合理的replicas数量可以极高的提高搜索吞吐量
分片设定
- 对于生产环境中分片的设定,需要提前做好容量规划,因为主分片数是在索引创建时预先设定的,后续无法修改。
- 分片数过小会导致后续无法增加节点进行水平扩展、导致分片的数据量太大,数据在重新分配时耗时
- 分片数过大会影响搜索结果的相关性打分,影响统计结果的准确性、单个节点上过多的分片,会导致资源浪费,同时也会影响性能;
2.2.7. 倒排索引
ES的搜索功能是基于lucene,而lucene搜索的基本原理就是倒叙索引,倒序排序的结果跟分词的类型有关。
假设我们搜索谷歌地图之父,搜索流程会是这样分词,分词插件将句子分为3个term 谷歌,地图,之父,然后将这3个term拿到倒叙索引中去查找(会很高效,比如二分查找),如果匹配到了就拿对应的文档id,获得文档内容。
TF、IDF在结果排序中起到了作用。
2.3. 通过REST API执行CRUD
2.3.1. ES集群相关命令
_cat系列提供了一系列查询Elasticsearch集群状态的接口
- _cat/shards #查看各shard的详细情况
- _cat/nodes #查看所有节点信息
- _cat/count #查看当前集群的doc数量
- _cat/allocation #查看单节点的shard分配整体情况
- _cat/health #查看集群当前状态:红、黄、绿
- …etc
- 每个命令都支持使用?v参数,让输出内容表格显示表头; pretty则让输出缩进更规范。 如
GET _cat/health?v
- ?pretty参数可以使输出更美观
2.3.2. 索引CRUD命令
查询索引举例
_cat/indices #查看集群中所有index的详细信息
_cat/indices/{index} #查看集群中指定index的详细信息
_cat/segments #查看各index的segment详细信息,包括segment名, 所属shard, 内存(磁盘)占用大小, 是否刷盘
_cat/segments/{index}#查看指定index的segment详细信息
_cat/indices?v&health=yellow #查询健康状态为yellow的索引
_cat/indices?v&health=yellow&s=docs.count:desc #根据文档数量进行索引排序
创建索引举例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17PUT student
{
"settings":{
"number_of_shards":1,
"number_of_replicas":1
},
"mappings":{
"properties":{
"name":{"type":"text"},
"sid":{"type":"integer"},
"address":{"type":"keyword"},
"age":{"type":"integer"},
"interests":{"type":"text"},
"birthday":{"type":"date"}
}
}
}
查看创建结果GET /_cat/indices/student?v
更新索引
使用PUT也可以更新索引
删除索引curl -X DELETE "localhost:9200/index-name"
2.3.3. 文档CRUD命令
POST /uri用于创建,DELETE /uri/xxx用于删除,PUT /uri/xxx用于更新或创建,GET /uri/xxx用于查询。
POST与PUT的区别:
- 在ES中,如果不确定文档的ID,那么就需要用POST,它可以自己生成唯一的文档ID。如果确定文档的ID,那么就可以用PUT,当然也可以用POST,它们都可以创建或修改文档(如果是修改,那么_version版本号提高1)
- PUT、GET、DELETE是幂等的,而POST并不一定是幂等。如果你对POST也指定了文档ID,那它其实和PUT没啥区别,那它就是幂等。如果你没有指定文档ID那么就不是幂等操作了,因为同一数据,你执行多次POST,那么生成多个UUID的文档,也就是每POST一次都会新增一条数据
创建文档:
PUT方式:PUT /student/_doc/1 {"name": "xxx","country": "tj","age": "3","date": "2019-09-04"}
POST方式:POST /student/_doc {"name": "xxx","country": "tj","age": "3","date": "2019-09-04"}
- POST也可以指定文档ID,如果指定文档ID,那么就和PUT没有区别。ID不存在则创建,存在则更新并且\_version版本+1.
- 批量插入:通过\_bulk接口,先声明所属index(一个json),而后跟n条数据(n个json)
查看文档:GET /student/_doc/1
更新文档:
PUT和POST执行的时候,如果指定的文档ID存在,那么就可以执行更新操作。不过它们执行的是全量更新,如果需要单独对某字段更新我们可以使用关键字_update。如POST /student/_update/1 {"doc" : {"age": 5}}
还可以通过POST student/_update_by_query
api进行更新操作,也就是通过query进行更新
删除文档:DELETE /{index}/{type}/{id}
举点例子,实践一下上面的概念
1 | 查看es页面的接口信息: |
2.4. 关于查询
简单查询:就是按照文档_id,通过ES的RESTFUL API 的GET请求来进行文档查询
条件查询:
- 条件查询请求的协议方法是POST方法(为什么使用get也可以查询)
- 条件查询需要使用_search关键字
- 条件查询需要在请求体内将条件写在一个json体内,如下面的query和filter
聚合查询:aggs是聚合查询的关键词
对mapping中的字段type,text表示可以进行全文搜索、进行分词的字段,keyword表示用于聚合查询、统计分析的字段,同一个字段可同时支持这两种type
2.4.1. Query查询
Query context(查询上下文)这种语句在执行时既要计算文档是否匹配,还要计算文档相对于其他文档的匹配度有多高,匹配度越高,_score 分数就越高
- match查询
- match query: 知道分词器的存在,会对filed进行分词操作,然后再查询
- match_all: 查询所有文档
- multi_match: 可以指定多个字段
- match_phrase: 短语匹配查询,ElasticSearch引擎首先分析(analyze)查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变
- 文档字段属性如果是一个keyword类型,那就需要完全匹配才能命中。好比这个字段值是12345,那么你不论是1234还是123456都不会命中。
- 如果是match_phrase,那就是真正的包含关系。好比这个字段值是12345,那么你是1234就会命中,而123456不会命中。因为12345包含1234而不包含123456。
- term查询和terms查询
- term query: 会去倒排索引中寻找确切的term,它并不知道分词器的存在。这种查询适合keyword 、numeric、date
- term:查询某个字段为该关键词的文档(它是相等关系而不是包含关系)
- terms:查询某个字段里含有多个关键词的文档
- 范围查询
- range: 实现范围查询
- from, to:指定范围,如年龄、日期等
- include_lower: 是否包含范围的左边界,默认是true
- include_upper: 是否包含范围的右边界,默认是true
- wildcard查询
- 允许使用通配符* 和?来进行查询, *代表0个或多个字符, ? 代表任意一个字符
- 如
"name": "徐*" "name": "徐小?"
- 中文数据在使用通配符时可能有bug
- 控制查询返回的数量和位置,通过from,size
- 通过_source指定返回的字段,或也可以控制显示要的字段和去除不需要的字段,此时可使用通配符*
- 通过sort:[{}]进行排序,如其中可填入
"age":{"order": "desc"}
- fuzzy实现模糊查询,模糊查询可以在Match和 Multi-Match查询中使用以便解决拼写的错误,模糊度是基于Levenshteindistance计算与原单词的距离
- highlight高亮搜索结果
2.4.2. Filter查询
- Filter context(过滤上下文)过滤上下文中的语句在执行时只关心文档是否和查询匹配,不会计算匹配度,也就是得分(score)
- filter是不计算相关性的,同时可以cache。因此,filter速度要快于query
- 将上面的query替换为post_filter
2.4.3. 复合查询
2.4.3.1. 布尔查询bool query
概念、特点:
- 通过布尔逻辑将较小的查询组合成较大的查询
- 子查询可以任意顺序出现
- 可以嵌套多个查询,包括bool查询
- 如果bool查询中没有must条件,should中必须至少满足一条才会返回结果
操作符: - must:必须出现在匹配文档中 ,贡献算分
- must_not:必须不能出现在匹配文档中,但不贡献算分
- should:选择性匹配,至少满足一条,贡献算分
- filter:过滤子句,必须出现在匹配文档中,但不贡献算分
2.4.3.2. 提高查询boosting query
在bool复合查询我们可以通过 must_not+must 先剔除不想匹配的文档,再获取匹配的文档,但是有一种场景就是我并不需要完全剔除,而是把需要剔除的那部分文档的分数降低。这个时候就可以使用boosting query
boosting需要搭配三个关键字:positive , negative , negative_boost
- 只有匹配了 positive查询 的文档才会被包含到结果集中
- 但是在匹配了 positive 的同时匹配了negative查询 的文档会被降低相关度并也包含在结果中,通过将文档原本的_score和negative_boost参数进行相乘来得到新的_score
- 所以negative_boost参数一般小于1.0,这样才能降低得分,如该参数等于0.5时匹配 negative 时会降低一半得分
应用场景:
例如搜索“苹果公司”相关信息,查询中用于匹配的信息为“苹果”。那么我们查询的条件是:must = ‘苹果’。但如果你的文档是 ‘苹果树’,’苹果水果’,那么此时如果匹配到其实没有任何意义。那么我们修改查询条件为:must = ‘苹果’ AND must_not = ‘树 or 水果’ 因为我们要查的苹果公司相关信息,如果你是苹果树那对我来讲确实是不匹配,所以直接过滤掉。但直接过滤会过于粗暴,因为一个文档中包含’苹果’和’树’那不代表一定是苹果树,而可能是 ‘苹果公司组织员工一起去种树’ 那么这条文档理应出现,此时产生了 boosting 应用的场景
2.4.3.3. 固定分数查询constant_score
常量分值查询,目的就是返回指定的score,一般都结合filter使用,因为filter context忽略score
例如 constant_score 中先加入一个filter,后跟boost参数,此时所有结果文档的score都会变为boost参数指定的值
2.4.3.4.最佳匹配查询dis_max
如果在查询中有多个匹配条件,则结果的得分只是取分数最高的那个query的分数
可以通过指定 tie**_breaker** 这个参数将其他匹配语句的评分也考虑其中,但最佳匹配语句依然占最终结果里的很大一部分
tie_breaker 参数提供了一种 dis_max 和 bool 之间的折中选择,它的评分方式如下:
- 获得最佳匹配语句的评分 _score
- 将其他匹配语句的评分结果与 tie_breaker 相乘
- 对以上评分求和并规范化
tie_breaker 可以是 0 到 1 之间的浮点数,其中 0 代表使用 dis_max 最佳匹配语句的普通逻辑, 1 表示所有匹配语句同等重要。最佳的精确值需要根据数据与查询调试得出,但是合理值应该与零接近(处于 0.1 - 0.4 之间),这样就不会颠覆 dis_max 最佳匹配性质的根本
2.4.3.5. 函数查询function_score (简单介绍)
概念:
- function_score是处理分值计算过程的终极工具,它让你能够对所有匹配了主查询的每份文档调用一个函数来调整甚至是完全替换原来的_score
- 要使用function_score,用户必须定义一个查询和一个或多个函数,这些函数计算查询返回的每个文档的新分数
一些预定义的函数: - weight: 对每份文档适用一个简单的提升,且该提升不会被归约,例如当weight为2时,结果为2 * _score
- field_value_factor: 使用文档中某个字段的值来改变_score,比如将受欢迎程度或者投票数量考虑在内
- random_score: 使用一致性随机分值计算来对每个用户采用不同的结果排序方式,对相同用户仍然使用相同的排序方式
- 衰减函数Decay Function
- linear,exp,gauss等
- script_score: 使用自定义的脚本来完全控制分值计算逻辑。如果你需要以上预定义函数之外的功能,可以根据需要通过脚本进行实现。
使用场景举例: - 假设有一个资讯类APP,我们希望让人阅读量高的文章出现在结果列表的头部,但是主要的排序依据仍然是全文搜索分值
- 当用户搜索酒店,它的要求是 1、离他目前位置1Km内 2、价格在500元内。如果我们只是使用一个 filter 排除所有市中心方圆 1KM以外的酒店,再用一个filter排除每晚价格超过500元的酒店,这种作法太过强硬,可能有一间房在2K米,但是超级便宜一晚只要100元,用户可能会因此愿意妥协住这间房。
官方文档: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html
举点Query和Filter的例子,数据接用上个例子中的。
1 | 查询兴趣里包含'旅游'的: |
2.5. 聚合:Elasticsearch 的面向和分析的主功能
在Mysql中,我们可以获取一组数据的 最大值(Max)、最小值(Min)。同样我们能够对这组数据进行 分组(Group)。那么对于Elasticsearch中我们也可以实现同样的功能。
官方对聚合有四个关键字: Metric(指标)、Bucketing(桶)、Matrix(矩阵)、Pipeline(管道
聚合是Elasticsearch除全文检索功能外提供的针对Elasticsearch数据做统计分析的功能。它的实时性高,所有的计算结果都是即时返回。
- Metric(指标): 指标分析类型,如计算最大值、最小值、平均值等等 (对桶内的文档进行聚合分析的操作)
- Bucket(桶): 分桶类型,类似SQL中的GROUP BY语法 (满足特定条件的文档的集合)
- Pipeline(管道): 管道分析类型,基于上一级的聚合分析结果进行再分析
- Matrix(矩阵): 矩阵分析类型(聚合是一种面向数值型的聚合,用于计算一组文档字段中的统计信息)
- 在查询请求体中以aggregations节点按规定语法定义聚合分析,可简写为aggs,如
{"aggs" : {"<aggregation_name>" :{"<aggregation_type>" : {<aggregation_body> } } } }
2.5.1. Metric聚合
官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics.html
简介:
桶(Bucket)能让我们划分文档到有意义的集合,但是最终我们需要的是对这些桶内的文档进行一些指标的计算。分桶是一种达到目的地的手段:它提供了一种给文档分组的方法来让我们可以计算感兴趣的指标。
大多数指标是简单的数学运算(如:最小值、平均值、最大值、汇总),这些是通过文档的值来计算的。
Metric聚合分析分为单值分析和多值分析两类
- 单值分析:只输出一个分析结果,如min、max、avg、sum…
- 多值分析:输出多个分析结果,如stats、percentile、extended_stats、percentile_rank…
1、Avg(均值)
计算从聚合文档中提取的数值的平均数
如:{"aggs" : {"avg_grade" : { "avg" : { "field" : "grade" } }}}
2、Max&Min
计算从聚合文档中提取的数值的最值
如:"max_price" : { "max" : { "field" : "price" } }
3、Sum(总和)
计算从聚合文档中提取的数值的总和
如:"hat_prices" : { "sum" : { "field" : "price" } }
4、Cardinality(唯一值)
cardinality 求唯一值,即不重复的字段有多少(相当于mysql中的distinct)
如:"type_count" : {"cardinality" : {"field" : "type"} }
5、Stats(统计)
stats 统计,请求后会直接显示多种聚合结果,count、min、max、avg、sum等
如:"grades_stats" : { "stats" : { "field" : "grade" } }
6、Percentiles(文档占比)
对指定字段的值按从小到大累计每个值对应的文档数的占比,返回指定占比比例对应的值,如对字段 “load_time” 使用percentiles返回"50.0": 445.0,
,则表示占比为百分之五十的文档”load_time”值小于等于445
下面给几种使用方法:
- 默认取百分比,则按照[ 1, 5, 25, 50, 75, 95, 99 ]来统计,如:
"percentiles" : { "field" : "load_time" }
- 指定分位值,则可在body内增加如
"percents" : [95, 99, 99.9]
- Keyed Response
- 默认情况下,keyed标志设置为true,它将唯一的字符串键与每个存储桶相关联,并将范围作为哈希而不是数组返回
- 也可以修改keyed为false,在body内
"keyed": false
,这样则会返回一个数组,通过结果也可以看出percentiles中键值对是按照百分比作键,字段值作值构成的
7、Percentile_Ranks
percentiles是通过指定百分比求文档值,这里通过文档值求百分比,即字段值作键,百分比作值
如:"percentile_ranks" : { "field" : "load_time" , "values" : [500,600] }
,返回结果若为"500.0": 55.1, "600.0": 64.0
则表示 时间小于500的文档占比为55.1%,时间小于600的文档占比为64%
注意这里一定要通过values指定值数组
8、Top_Hits
一般用于分桶后获取该桶内匹配前n的文档列表,例如可以展示出某一个网站文档浏览前N名的文档
2.5.2. Bucket聚合
简介:
简单来说桶就是满足特定条件的文档的集合,它会遍历文档中的内容,凡是符合某一要求的就放入一个桶中,分桶相当于 SQL 中的 group by。
当聚合开始被执行,每个文档里面的值通过计算来决定符合哪个桶的条件,如果匹配到,文档将放入相应的桶并接着开始聚合操作。
桶也可以被嵌套在其他桶里面。
1、Terms Aggregation
根据某一项的每个唯一的值的聚合
如:"terms" : { "field" : "brand" }
,根据品牌分桶
常见使用:
- 若只显示数量前n的桶,可通过size参数控制,如在body中加入
"size" : 3
则只显示前三的桶 - 若分桶后需要排序,可通过order参数控制,如在body中加入
"order" : { "_count" : "asc" }
- 若要显示文档数量不小于n的桶,可通过
min_doc_count
参数控制,如:"min_doc_count": 3
则只显示文档数量大于等于3的桶 - 也可使用精确的指定字段值分组,通过include参数控制,如:
"include" : ["BMW", "Audi"]
则只通过宝马和奥迪分桶
2、Filter Aggregation&Filters Aggregation
Filter Aggregation指具体的域和具体的值,可以说是在 Terms Aggregation 的基础上进行了过滤,只对特定的值进行了聚合
Filter Aggreagtion 只能指定一个过滤条件,响应也只是单个桶。如果想要只对多个特定值进行聚合,使用 Filter Aggreagtion 只能进行多次请求。而使用 Filters Aggreagation 就可以解决上述的问题,它可以指定多个过滤条件,也是说可以对多个特定值进行聚合
3、Histogram Aggregation
Histogram与Terms聚合类似,都是数据分组,区别是Terms是按照Field的值分组,而Histogram可以按照指定的间隔对Field进行分组
如:"histogram" : {"field" : "price" , "interval" : 10000}
表示根据价格区间为10000分桶
4、Range Aggregation
根据用户传递的范围参数作为桶,进行相应的聚合。在同一个请求中,可以传递多组范围,每组范围作为一个桶
如:"range" : { "field" : "price", "ranges" : [ { "to" : 50000 },{ "from" : 5000, "to" : 80000 }, { "from" : 80000 } ] }
通过ranges参数的数组传递了三个范围,则返回结果中包含三个桶
也可以在ranges中指定key的名称,如:[{ "key" : "xiaoyu", "to" : 50000 }]
5、Date Aggregation
Date Aggregation是针对于时间格式数据的直方图聚合,基本的特性与 Histogram Aggregation 一致
可以实现按指定时间区间分桶等date相关操作,具体参见官方文档
3. 深入
- 原理探究
- score
- 分词器
- 倒排索引
- 安全性
- X-Pack
3.1. 原理探究
3.1.1. score
3.1.2. 分词器
3.1.3. 倒排索引
3.2. 安全性
Elasticsearch早期版本安全部分收费(7.1 & 6.8 版本之前),实际中各个公司6.x,5.x,2.x,1.x都有在用,且非少数。多数只是使用nginx代理防护,不暴露端口,不外网映射。
如果9200或者改成其他端口的ES暴露在公网,一旦被扫到,集群及数据会受到灾难式影响。
3.2.1. X-Pack
3.2.1.1. 啥是X-Pack
X-Pack是Elastic Stack扩展功能,提供安全性,警报,监视,报告,机器学习和许多其他功能。 ES7.0+之后,默认情况下,当安装Elasticsearch时,会安装X-Pack,无需单独再安装(也就是内置了)。自6.8以及7.1+版本之后,基础级安全永久免费。
基础级安全包括:加密通信、基于角色的访问控制、文件和原生身份验证、Kibana功能控制、Kibana Spaces和API密钥管理。
安全等级有:Minimal、Basic和Basic+TLS for REST,基础级指Basic。
Basic security比Minimal security多了节点间的TLS(加密通信和身份验证)。
3.2.1.2. 如何配置X-Pack(基础级安全)
默认情况下,拥有安全免费许可证时,Elasticsearch安全功能被禁用。 要启用安全功能,需要先在es主配置文件中添加xpack.security.enabled: true
。生产模式下若进行此配置则必须完成Basic security的所有配置,否则集群无法启动。
一、为内建用户创建密码
在Minimal和Basic下,只需要为elastic和kibana_system用户创建密码。
1、在集群的每个节点上启动Elasticsearch
2、./bin/elasticsearch-setup-passwords interactive
为每个用户创建密码,注意该命令可以在集群的任一节点上运行,但一个集群只能运行一次。interactive换成auto会自动生成密码,该命令只能运行一次!
二、使用用户名和密码登录Kibana
当安全特性被启动后,用户必须通过合法的用户名和密码才能登录Kibana。刚刚配置好的内建用户kibana_system用于配置Kibana的某些后台任务,但并不能作为个人用户登录Kibana界面。要想登录Kibana界面需要使用超级用户”elastic”。
1、在kibana.yml中添入elasticsearch.username: "kibana_system"
2、./bin/kibana-keystore create
创建Kibana密钥库(keystone)
3、./bin/kibana-keystore add elasticsearch.password
输入之前定义的密码
4、重启Kibana
5、使用”elastic”超级用户登录Kibana界面
三、配置节点间传输层安全(TLS)
在集群中有多个节点时,必须配置节点间的传输层安全!否则处于生产模式下的Elasticsearch集群不会被启动。该安全应用包含了节点间的通信加密和身份验证。
(画外音,教程中出现传输层协议特指ES用于节点间交互的协议,transport用于区分http端口和节点间通信端口transport port,虽然TLS和transport port都出现了transport一词,但表示不同含义,我们在将TLS应用到http port和transport port)
四、将TLS应用到节点间加密通信
节点间的通信被transport模块处理,为了保护集群必须确保节点间通信的加密和验证工作正常,即互相的TLS。节点间通信使用证书确定身份,推荐做法是集群选择一个信任的CA,当新节点要加入集群时需要提供该CA的签名的证书。使用elasticsearch-certutil工具为集群生成CA。
1、./bin/elasticsearch-certutil ca
使用工具,提示后选择默认文件名”elastic-stack-ca.p12”,这个文件包含生成CA的公共证书和它为每个节点签名的私钥。
2、为生成的CA选择一个密码,可以为空(非生产)。
3、在同一个节点上运行./bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12
该命令使用刚才生成的CA为集群上的节点们生成一个证书和一把私钥。
4、 提示后首先输入CA的密码,然后为节点证书选择一个密码并使用默认文件名”elastic-certificates.p12”,这个文件包含了节点证书、节点私钥和CA证书。
5、最后在集群的所有节点上,在elasticsearch的config目录中放入刚才生成的节点证书文件”elastic-certificates.p12”,他们都是相同的。
以上步骤为生成CA和证书,下面开始布置加密节点间通信。由于Elasticseach会定期(默认5s)监视一些配置文件(包括CA和证书),所以不用停止集群就可以进行下列步骤。
1、打开ES主配置文件,对所有集群中的节点配置统一的集群名称cluster.name,并对各个节点配置各自的节点名称node.name
2、在所有节点的主配置文件下加入以下配置(由于默认证书文件名一致)
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.client_authentication: required
xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: elastic-certificates.p12
3、如果在创建节点证书(elastic-certificates.p12)时设定了密码,则进行以下两项配置将证书密码加入Elasticsearch密钥库(keystore),在所有节点上。
./bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password
./bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password
4、重启整个集群,确保每个节点的ES都进行了重启,否则可能无法通信。
五、将TLS应用到HTTP层
之前已经将TLS在传输层进行了应用,现在要应用到HTTP层。分为两个部分,为Elasticsearch加密HTTP客户端通信和为Kibana加密HTTP客户端通信,Kibana部分包括浏览器与Kibana间的通信加密与Kibana与Elasticsearch间的通信加密。
1、 停止各节点服务,在任一节点上ESHOME运行./bin/elasticsearch-certutil http
。该命令生成一个zip压缩文件,其中包含用于 Elasticsearch 和 Kibana 的证书和密钥。每个文件夹都包含一个README.txt 解释如何使用这些文件。详细步骤如下:
- 当询问您是否要生成 CSR 时,请输入n。
- 当询问您是否要使用现有 CA 时,输入y。
- 输入您的 CA 的路径。elastic-stack-ca.p12这是您为集群生成的文件的绝对路径。
- 输入您的 CA 的密码。
- 输入证书的到期值,您可以输入年、月或日的有效期。例如,输入90D表示90 天。
- 当询问您是否要为每个节点生成一个证书时,输入y。节点的名称,如ESNODE-001等。每个证书都有自己的私钥,并针对特定的主机名或 IP 地址颁发。
- 出现提示时,输入集群中第一个节点的名称,即生成节点证书(”elastic-certificates.p12”)时使用的节点名称。
- 输入连接到您的第一个节点的所有主机名,这些主机名将作为 DNS 名称添加到证书的Subject Alternative Name(主题备用名称 SAN) 字段中。列出需要通过 HTTPS 连接到集群的每个主机名和变体。主机名如ZMC-MacBook-Air.local。
- 输入客户端可用于连接到您的节点的 IP 地址,通常为本机地址。然后会有新增证书选项,选择确认为节点二创建。总之集群中的节点都需要有这些证书。
2、为每个节点生成证书后,在出现提示时输入您的私钥密码,可以为空。
3、解压生成的elasticsearch-ssl-http.zip文件。此压缩文件包含 Elasticsearch 和 Kibana 的目录。如果对多个节点创建了证书,那么elasticsearch目录下会根据节点名分为若干个子目录。
/elasticsearch
|_ README.txt
|_ http.p12
|_ sample-elasticsearch.yml
/kibana
|_ README.txt
|_ elasticsearch-ca.pem
|_ sample-kibana.yml
4、在集群的每个节点上进行操作,复制对应的http.p12文件到ESHOME下config文件夹中,然后修改主配置文件,增加如下配置。注意一定要对应节点的文件。
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: http.p12
最后./bin/elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password
添加之前设置的私钥密码到elasticsearch密钥库。
5、启动ES,Elasticsearch加密HTTP客户端通信配置完毕。此时Kibana将无法使用,需要进行进一步加密配置。
下面配置Kibana加密部分。
1、第一部分创建的zip文件中包含elasticsearch-ca.pem文件,使用该文件配置Kibana使其信任HTTP 层的 Elasticsearch CA。复制该文件到Kibana的config目录下。
2、在kibana.yml下增加并修改配置如下,指定认证文件目录,并提供Elasticsearch集群特定的HTTPS URL。目录可以用相对的,如config/.pem。
elasticsearch.ssl.certificateAuthorities: $KBN_PATH_CONF/elasticsearch-ca.pem
elasticsearch.hosts: https://<your_elasticsearch_host>:9200
3、重启Kibana使配置生效。如果配置了Elastic monitoring在集群上,也可以将监控功能加密(即通过HTTPS方式)。至此Kibana至ES加密配置完成,Kibana可以正常工作,但从浏览器访问时仍然是http连接。
4、要对浏览器到Kibana间通信进行加密,首先需要为Kibana创建服务器证书和私钥。回到Elasticsearch目录下输入命令,
./bin/elasticsearch-certutil csr -name kibana-server -dns example.com,www.example.com
这个CSR中包含普通名称kibana-server和两个SAN,example.com和www.example.com。
5、CSR即Certificate Signing Request,证书签名请求,它包含 CA 用于生成和签署安全证书的信息。上述命令生成一个名为csr-bundle.zip的压缩文件,目录如下。
/kibana-server
|_ kibana-server.csr
|_ kibana-server.key
6、解压csr-bundle.zip文件,获取未签名的安全证书kibana-server.csr和未加密的私钥kibana-server.key。
7、将kibana-server.csr证书签名请求发送给您的内部 CA 或受信任的 CA 进行签名以获得签名证书。签名文件可以是不同的格式,例如crt文件,即kibana-server.crt。这里可以选择使用openssl进行签名,openssl x509 -req -days 1800 -in kibana-server.csr -signkey kibana-server.key -out kibana-server.crt
8、打开kibana.yml增加以下配置。同样,目录可以用相对的。
server.ssl.certificate: $KBN_PATH_CONF/kibana-server.crt
server.ssl.key: $KBN_PATH_CONF/kibana-server.key
server.ssl.enabled: true
9、启动Kibana完成配置,配置完成后,则必须通过https连接Kibana。
六、配置Logstash适应HTTPS
bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12 --ip 192.168.0.123 --name LOGSTASH-001
复制证书到Logstash服务器。由于logstash不能使用PKCS#12类型的证书,运行命令openssl pkcs12 -in LOGSTASH-001.p12 -clcerts -nokeys -chain -out ca.pem
转换证书格式。
logstash.yml增加配置如下:
xpack.monitoring.enabled: true
xpack.monitoring.elasticsearch.username: elastic
xpack.monitoring.elasticsearch.password: weblog
xpack.monitoring.elasticsearch.hosts: ["https://192.168.0.xxx:9200"]
xpack.monitoring.elasticsearch.ssl.certificate_authority: "/etc/logstash/ca.pem"
xpack.monitoring.elasticsearch.ssl.verification_mode: certificate
xpack.monitoring.elasticsearch.sniffing: false
Conf文件输出插件增加配置如下,并把http修改为https。
cacert => "/etc/logstash/ca.pem"
ssl => true
ssl_certificate_verification => false