update docs

pull/14/head
dunwu 2022-01-19 22:49:16 +08:00
parent c0391aa540
commit 0c9f75b7ac
4 changed files with 1346 additions and 60 deletions

View File

@ -0,0 +1,188 @@
# Elasticsearch 排序
在 Elasticsearch 中,默认排序是**按照相关性的评分(\_score**进行降序排序,也可以按照**字段的值排序**、**多级排序**、**多值字段排序、基于 geo地理位置排序以及自定义脚本排序**,除此之外,对于相关性的评分也可以用 rescore 二次、三次打分它可以限定重新打分的窗口大小window size并针对作用范围内的文档修改其得分从而达到精细化控制结果相关性的目的。
## 默认相关性排序
在 Elasticsearch 中,默认情况下,文档是按照相关性得分倒序排列的,其对应的相关性得分字段用 `_score` 来表示,它是浮点数类型,`_score` 评分越高,相关性越高。评分模型的选择可以通过 `similarity` 参数在映射中指定。
相似度算法可以按字段指定,只需在映射中为不同字段选定即可,如果要修改已有字段的相似度算法,只能通过为数据重新建立索引来达到目的。关于更多 es 相似度算法可以参考 [深入理解 es 相似度算法(相关性得分计算)](https://www.knowledgedict.com/tutorial/elasticsearch-similarity.html)。
### TF-IDF 模型
Elasticsearch 在 5.4 版本以前text 类型的字段,默认采用基于 tf-idf 的向量空间模型。
在开始计算得分之时Elasticsearch 使用了被搜索词条的频率以及它有多常见来影响得分。一个简短的解释是,**一个词条出现在某个文档中的次数越多,它就越相关;但是,如果该词条出现在不同的文档的次数越多,它就越不相关**。这一点被称为 TF-IDFTF 是**词频**term frequencyIDF 是**逆文档频率**inverse document frequency
考虑给一篇文档打分的首要方式,是统计一个词条在文本中出现的次数。举个例子,如果在用户的区域搜索关于 Elasticsearch 的 get-together用户希望频繁提及 Elasticsearch 的分组被优先展示出来。
```
"We will discuss Elasticsearch at the next Big Data group."
"Tuesday the Elasticsearch team will gather to answer questions about Elasticsearch."
```
第一个句子提到 Elasticsearch 一次,而第二个句子提到 Elasticsearch 两次所以包含第二句话的文档应该比包含第一句话的文档拥有更高的得分。如果我们要按照数量来讨论第一句话的词频TF是 1而第二句话的词频将是 2。
逆文档频率比文档词频稍微复杂一点。这个听上去很酷炫的描述意味着,如果一个分词(通常是单词,但不一定是)在索引的不同文档中出现越多的次数,那么它就越不重要。使用如下例子更容易解释这一点。
```
"We use Elasticsearch to power the search for our website."
"The developers like Elasticsearch so far."
"The scoring of documents is calculated by the scoring formula."
```
如上述例子,需要理解以下几点:
- 词条 “Elasticsearch” 的文档频率是 2因为它出现在两篇文档中。文档频率的逆源自得分乘以 1/DF这里 DF 是该词条的文档频率。这就意味着,由于词条拥有更高的文档频率,它的权重就会降低。
- 词条 “the” 的文档频率是 3因为它出现在所有的三篇文档中。请注意尽管 “the” 在最后一篇文档中出现了两次,它的文档频率还是 3。这是因为逆文档频率只检查一个词条是否出现在某文档中而不检查它出现多少次。那个应该是词频所关心的事情。
逆文档频率是一个重要的因素,用于平衡词条的词频。举个例子,考虑有一个用户搜索词条 “the score”单词 the 几乎出现在每个普通的英语文本中,如果它不被均衡一下,单词 the 的频率要完全淹没单词 score 的频率。逆文档频率 IDF 均衡了 the 这种常见词的相关性影响,所以实际的相关性得分将会对查询的词条有一个更准确的描述。
一旦词频 TF 和逆文档频率 IDF 计算完成,就可以使用 TF-IDF 公式来计算文档的得分。
### BM25 模型
Elasticsearch 在 5.4 版本之后,针对 text 类型的字段,默认采用的是 BM25 评分模型,而不是基于 tf-idf 的向量空间模型,评分模型的选择可以通过 `similarity` 参数在映射中指定。
## 字段的值排序
在 Elasticsearch 中按照字段的值排序,可以利用 `sort` 参数实现。
```
GET books/_search
{
"sort": {
"price": {
"order": "desc"
}
}
}
```
返回结果如下:
```
{
"took": 132,
"timed_out": false,
"_shards": {
"total": 10,
"successful": 10,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 749244,
"max_score": null,
"hits": [
{
"_index": "books",
"_type": "book",
"_id": "8456479",
"_score": null,
"_source": {
"id": 8456479,
"price": 1580.00,
...
},
"sort": [
1580.00
]
},
...
]
}
}
```
从如上返回结果,可以看出,`max_score` 和 `_score` 字段都返回 `null`,返回字段多出 `sort` 字段,包含排序字段的分值。计算 \_score 的花销巨大,如果不根据相关性排序,记录 \_score 是没有意义的。如果无论如何都要计算 \_score可以将 `track_scores` 参数设置为 `true`
## 多字段排序
如果我们想要结合使用 price、date 和 \_score 进行查询,并且匹配的结果首先按照价格排序,然后按照日期排序,最后按照相关性排序,具体示例如下:
```
GET books/_search
{
"query": {
"bool": {
"must": {
"match": { "content": "java" }
},
"filter": {
"term": { "user_id": 4868438 }
}
}
},
"sort": [{
"price": {
"order": "desc"
}
}, {
"date": {
"order": "desc"
}
}, {
"_score": {
"order": "desc"
}
}
]
}
```
排序条件的顺序是很重要的。结果首先按第一个条件排序,仅当结果集的第一个 `sort` 值完全相同时才会按照第二个条件进行排序,以此类推。
多级排序并不一定包含 `_score`。你可以根据一些不同的字段进行排序,如地理距离或是脚本计算的特定值。
## 多值字段的排序
一种情形是字段有多个值的排序,需要记住这些值并没有固有的顺序;一个多值的字段仅仅是多个值的包装,这时应该选择哪个进行排序呢?
对于数字或日期,你可以将多值字段减为单值,这可以通过使用 `min`、`max`、`avg` 或是 `sum` 排序模式。例如你可以按照每个 date 字段中的最早日期进行排序,通过以下方法:
```
"sort": {
"dates": {
"order": "asc",
"mode": "min"
}
}
```
## 地理位置上的距离排序
es 的地理位置排序使用 **`_geo_distance`** 来进行距离排序,如下示例:
```
{
"sort" : [
{
"_geo_distance" : {
"es_location_field" : [116.407526, 39.904030],
"order" : "asc",
"unit" : "km",
"mode" : "min",
"distance_type" : "plane"
}
}
],
"query" : {
......
}
}
```
_\_geo_distance_ 的选项具体如下:
- 如上的 _es_location_field_ 指的是 es 存储经纬度数据的字段名。
- **_`order`_**:指定按距离升序或降序,分别对应 **_`asc`_****_`desc`_**
- **_`unit`_**:计算距离值的单位,默认是 **_`m`_**表示米meters其它可选项有 **_`mi`_**、**_`cm`_**、**_`mm`_**、**_`NM`_**、**_`km`_**、**_`ft`_**、**_`yd`_** 和 **_`in`_**
- **_`mode`_**:针对数组数据(多个值)时,指定的取值模式,可选值有 **_`min`_**、**_`max`_**、**_`sum`_**、**_`avg`_** 和 **_`median`_**,当排序采用升序时,默认为 _min_;排序采用降序时,默认为 _max_
- **_`distance_type`_**:用来设置如何计算距离,它的可选项有 **_`sloppy_arc`_**、**_`arc`_** 和 **_`plane`_**,默认为 _sloppy_arc__arc_ 它相对更精确些但速度会明显下降_plane_ 则是计算快,但是长距离计算相对不准确。
- **_`ignore_unmapped`_**:未映射字段时,是否忽略处理,可选项有 **_`true`_****_`false`_**;默认为 _false_,表示如果未映射字段,查询将引发异常;若设置 _true_,将忽略未映射的字段,并且不匹配此查询的任何文档。
- **_`validation_method`_**:指定检验经纬度数据的方式,可选项有 **_`IGNORE_MALFORMED`_**、**_`COERCE`_** 和 **_`STRICT`_**_IGNORE_MALFORMED_ 表示可接受纬度或经度无效的地理点即忽略数据_COERCE_ 表示另外尝试并推断正确的地理坐标_STRICT_ 为默认值,表示遇到不正确的地理坐标直接抛出异常。
## 参考资料
- [Elasticsearch 教程](https://www.knowledgedict.com/tutorial/elasticsearch-intro.html)

View File

@ -2,19 +2,106 @@
Elasticsearch 查询语句采用基于 RESTful 风格的接口封装成 JSON 格式的对象,称之为 Query DSL。Elasticsearch 查询分类大致分为**全文查询**、**词项查询**、**复合查询**、**嵌套查询**、**位置查询**、**特殊查询**。Elasticsearch 查询从机制分为两种,一种是根据用户输入的查询词,通过排序模型计算文档与查询词之间的**相关度**,并根据评分高低排序返回;另一种是**过滤机制**,只根据过滤条件对文档进行过滤,不计算评分,速度相对较快。
## 全文查询
<!-- TOC depthFrom:2 depthTo:3 -->
- [1. 全文查询](#1-全文查询)
- [1.1. intervals query](#11-intervals-query)
- [1.2. match query](#12-match-query)
- [1.3. match_bool_prefix query](#13-match_bool_prefix-query)
- [1.4. match_phrase query](#14-match_phrase-query)
- [1.5. match_phrase_prefix query](#15-match_phrase_prefix-query)
- [1.6. multi_match query](#16-multi_match-query)
- [1.7. combined_fields query](#17-combined_fields-query)
- [1.8. common_terms query](#18-common_terms-query)
- [1.9. query_string query](#19-query_string-query)
- [1.10. simple_query_string](#110-simple_query_string)
- [1.11. 全文查询完整示例](#111-全文查询完整示例)
- [2. 词项查询](#2-词项查询)
- [2.1. exists query](#21-exists-query)
- [2.2. fuzzy query](#22-fuzzy-query)
- [2.3. ids query](#23-ids-query)
- [2.4. prefix query](#24-prefix-query)
- [2.5. range query](#25-range-query)
- [2.6. regexp query](#26-regexp-query)
- [2.7. term query](#27-term-query)
- [2.8. terms query](#28-terms-query)
- [2.9. type query](#29-type-query)
- [2.10. wildcard query](#210-wildcard-query)
- [2.11. 词项查询完整示例](#211-词项查询完整示例)
- [3. 复合查询](#3-复合查询)
- [3.1. bool query](#31-bool-query)
- [3.2. boosting query](#32-boosting-query)
- [3.3. constant_score query](#33-constant_score-query)
- [3.4. dis_max query](#34-dis_max-query)
- [3.5. function_score query](#35-function_score-query)
- [3.6. indices query](#36-indices-query)
- [4. 嵌套查询](#4-嵌套查询)
- [4.1. nested query](#41-nested-query)
- [4.2. has_child query](#42-has_child-query)
- [4.3. has_parent query](#43-has_parent-query)
- [5. 位置查询](#5-位置查询)
- [5.1. geo_distance query](#51-geo_distance-query)
- [5.2. geo_bounding_box query](#52-geo_bounding_box-query)
- [5.3. geo_polygon query](#53-geo_polygon-query)
- [5.4. geo_shape query](#54-geo_shape-query)
- [6. 特殊查询](#6-特殊查询)
- [6.1. more_like_this query](#61-more_like_this-query)
- [6.2. script query](#62-script-query)
- [6.3. percolate query](#63-percolate-query)
<!-- /TOC -->
## 1. 全文查询
ES 全文查询主要用于在全文字段上主要考虑查询词与文档的相关性Relevance
### intervals query
### 1.1. intervals query
[**`intervals query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-intervals-query.html) 根据匹配词的顺序和近似度返回文档。
intervals query 使用**匹配规则**,这些规则应用于指定字段中的 term。
### match query
示例:下面示例搜索 `query` 字段,搜索值是 `my favorite food`,没有任何间隙;然后是 `my_text` 字段搜索匹配 `hot water`、`cold porridge` 的 term。
match query **用于搜索单个字段**,首先会针对查询语句进行解析(经过 analyzer主要是对查询语句进行分词分词后查询语句的任何一个词项被匹配文档就会被搜到默认情况下相当于对分词后词项进行 or 匹配操作。
当 my_text 中的值为 `my favorite food is cold porridge` 时,会匹配成功,但是 `when it's cold my favorite food is porridge` 则匹配失败
```bash
POST _search
{
"query": {
"intervals" : {
"my_text" : {
"all_of" : {
"ordered" : true,
"intervals" : [
{
"match" : {
"query" : "my favorite food",
"max_gaps" : 0,
"ordered" : true
}
},
{
"any_of" : {
"intervals" : [
{ "match" : { "query" : "hot water" } },
{ "match" : { "query" : "cold porridge" } }
]
}
}
]
}
}
}
}
}
```
### 1.2. match query
[**`match query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html) **用于搜索单个字段**,首先会针对查询语句进行解析(经过 analyzer主要是对查询语句进行分词分词后查询语句的任何一个词项被匹配文档就会被搜到默认情况下相当于对分词后词项进行 or 匹配操作。
[**`match query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html) 是执行全文搜索的标准查询,包括模糊匹配选项。
```bash
GET kibana_sample_data_ecommerce/_search
@ -45,7 +132,26 @@ GET kibana_sample_data_ecommerce/_search
}
```
如果想查询匹配所有关键词的文档,可以用 and 操作符连接,如下:
#### match query 简写
可以通过组合 `<field>``query` 参数来简化匹配查询语法。
示例:
```bash
GET /_search
{
"query": {
"match": {
"message": "this is a test"
}
}
}
```
#### match query 如何工作
匹配查询是布尔类型。这意味着会对提供的文本进行分析,分析过程从提供的文本构造一个布尔查询。 `operator` 参数可以设置为 `or``and` 来控制布尔子句(默认为 `or`)。可以使用 [`minimum_should_match`](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-minimum-should-match.html) 参数设置要匹配的可选 `should` 子句的最小数量。
```bash
GET kibana_sample_data_ecommerce/_search
@ -61,11 +167,92 @@ GET kibana_sample_data_ecommerce/_search
}
```
### match_phrase 查询
可以设置 `analyzer` 来控制哪个分析器将对文本执行分析过程。它默认为字段显式映射定义或默认搜索分析器。
> 参考https://www.elastic.co/guide/cn/elasticsearch/guide/current/phrase-matching.html
`lenient` 参数可以设置为 `true` 以忽略由数据类型不匹配导致的异常,例如尝试使用文本查询字符串查询数字字段。默认为 `false`
**`match_phrase`** 查询即短语匹配,首先会把 query 内容分词,分词器可以自定义,同时文档还要满足以下两个条件才会被搜索到:
#### match query 的模糊查询
`fuzziness` 允许基于被查询字段的类型进行模糊匹配。请参阅 [Fuzziness](https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#fuzziness) 的配置。
在这种情况下可以设置 `prefix_length``max_expansions` 来控制模糊匹配。如果设置了模糊选项,查询将使用 `top_terms_blended_freqs_${max_expansions}` 作为其重写方法,`fuzzy_rewrite` 参数允许控制查询将如何被重写。
默认情况下允许模糊倒转 (`ab` → `ba`),但可以通过将 `fuzzy_transpositions` 设置为 `false` 来禁用。
```bash
GET /_search
{
"query": {
"match": {
"message": {
"query": "this is a testt",
"fuzziness": "AUTO"
}
}
}
}
```
#### zero terms 查询
如果使用的分析器像 stop 过滤器一样删除查询中的所有标记,则默认行为是不匹配任何文档。可以使用 `zero_terms_query` 选项来改变默认行为,它接受 `none`(默认)和 `all` (相当于 `match_all` 查询)。
```bash
GET /_search
{
"query": {
"match": {
"message": {
"query": "to be or not to be",
"operator": "and",
"zero_terms_query": "all"
}
}
}
}
```
### 1.3. match_bool_prefix query
[**`match_bool_prefix query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-bool-prefix-query.html) 分析其输入并根据这些词构造一个布尔查询。除了最后一个术语之外的每个术语都用于术语查询。最后一个词用于 `prefix query`
示例:
```bash
GET /_search
{
"query": {
"match_bool_prefix" : {
"message" : "quick brown f"
}
}
}
```
等价于
```bash
GET /_search
{
"query": {
"bool" : {
"should": [
{ "term": { "message": "quick" }},
{ "term": { "message": "brown" }},
{ "prefix": { "message": "f"}}
]
}
}
}
```
`match_bool_prefix query``match_phrase_prefix query` 之间的一个重要区别是:`match_phrase_prefix query` 将其 term 匹配为短语,但 `match_bool_prefix query` 可以在任何位置匹配其 term。
上面的示例 `match_bool_prefix query` 查询可以匹配包含 `quick brown fox` 的字段,但它也可以快速匹配 `brown fox`。它还可以匹配包含 `quick`、`brown` 和以 `f` 开头的字段,出现在任何位置。
### 1.4. match_phrase query
[**`match_phrase query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase.html) 即短语匹配,首先会把 query 内容分词,分词器可以自定义,同时文档还要满足以下两个条件才会被搜索到:
1. **分词后所有词项都要出现在该字段中(相当于 and 操作)**。
2. **字段中的词项顺序要一致**。
@ -100,9 +287,9 @@ GET demo/_search
> - are 的位置应该比 How 的位置大 1 。
> - you 的位置应该比 How 的位置大 2 。
### match_phrase_prefix query
### 1.5. match_phrase_prefix query
**`match_phrase_prefix`** 和 **`match_phrase`** 类似,只不过 **`match_phrase_prefix`** 支持最后一个 term 的前缀匹配。
[**`match_phrase_prefix query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase-prefix.html) 和 [**`match_phrase query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase.html) 类似,只不过 [**`match_phrase_prefix query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase-prefix.html) 最后一个 term 会被作为前缀匹配。
```bash
GET demo/_search
@ -115,9 +302,9 @@ GET demo/_search
}
```
### multi_match query
### 1.6. multi_match query
**`multi_match`** 是 **`match`** 的升级,**用于搜索多个字段**。
[**`multi_match query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html)**`match query`** 的升级,**用于搜索多个字段**。
示例:
@ -136,7 +323,7 @@ GET kibana_sample_data_ecommerce/_search
}
```
**`multi_match`** 支持对要搜索的**字段的名称使用通配符**,示例如下:
**`multi_match query`** 的搜索字段可以使用通配符指定,示例如下:
```bash
GET kibana_sample_data_ecommerce/_search
@ -172,9 +359,32 @@ GET kibana_sample_data_ecommerce/_search
}
```
### common_terms query
### 1.7. combined_fields query
**`common_terms`** query 是一种在不牺牲性能的情况下替代停用词提高搜索准确率和召回率的方案。
[**`combined_fields query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-combined-fields-query.html) 支持搜索多个文本字段,就好像它们的内容已被索引到一个组合字段中一样。该查询会生成以 term 为中心的输入字符串视图:首先它将查询字符串解析为独立的 term然后在所有字段中查找每个 term。当匹配结果可能跨越多个文本字段时此查询特别有用例如文章的标题、摘要和正文
```bash
GET /_search
{
"query": {
"combined_fields" : {
"query": "database systems",
"fields": [ "title", "abstract", "body"],
"operator": "and"
}
}
}
```
#### 字段前缀权重
字段前缀权重根据组合字段模型进行计算。例如,如果 title 字段的权重为 2则匹配度打分时会将 title 中的每个 term 形成的组合字段,按出现两次进行打分。
### 1.8. common_terms query
> 7.3.0 废弃
[**`common_terms query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-common-terms-query.html) 是一种在不牺牲性能的情况下替代停用词提高搜索准确率和召回率的方案。
查询中的每个词项都有一定的代价以搜索“The brown fox”为例query 会被解析成三个词项“the”“brown”和“fox”每个词项都会到索引中执行一次查询。很显然包含“the”的文档非常多相比其他词项“the”的重要性会低很多。传统的解决方案是把“the”当作停用词处理去除停用词之后可以减少索引大小同时在搜索时减少对停用词的收缩。
@ -186,7 +396,7 @@ common_terms query 提供了一种解决方案,它把 query 分词后的词项
例如,文档频率高于 0.1% 的词项将会被当作高频词项,词频之间可以用 low_freq_operator、high_freq_operator 参数连接。设置低频词操作符为“and”使所有的低频词都是必须搜索的示例代码如下
```
```bash
GET books/_search
{
"query": {
@ -203,7 +413,7 @@ GET books/_search
上述操作等价于:
```
```bash
GET books/_search
{
"query": {
@ -223,29 +433,109 @@ GET books/_search
}
```
### query_string query
### 1.9. query_string query
**`query_string`** query 是与 Lucene 查询语句的语法结合非常紧密的一种查询允许在一个查询语句中使用多个特殊条件关键字AND | OR | NOT对多个字段进行查询建议熟悉 Lucene 查询语法的用户去使用。
[**`query_string query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html) 是与 Lucene 查询语句的语法结合非常紧密的一种查询允许在一个查询语句中使用多个特殊条件关键字AND | OR | NOT对多个字段进行查询建议熟悉 Lucene 查询语法的用户去使用。
### simple_query_string
用户可以使用 query_string query 来创建包含通配符、跨多个字段的搜索等复杂搜索。虽然通用,但查询是严格的,如果查询字符串包含任何无效语法,则会返回错误。
**`simple_query_string`** 是一种适合直接暴露给用户,并且具有非常完善的查询语法的查询语句,接受 Lucene 查询语法,解析过程中发生错误不会抛出异常。例子如下
示例
```
GET books/_search
```bash
GET /_search
{
"query": {
"simple_query_string": {
"query": "\"fried eggs\" +(eggplant | potato) -frittata",
"analyzer": "snowball",
"fields": ["body^5", "_all"],
"default_operator": "and"
"query_string": {
"query": "(new york city) OR (big apple)",
"default_field": "content"
}
}
}
```
## 词项查询
### 1.10. simple_query_string
[**`simple_query_string query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html) 是一种适合直接暴露给用户,并且具有非常完善的查询语法的查询语句,接受 Lucene 查询语法,解析过程中发生错误不会抛出异常。
虽然语法比 [**`query_string query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html) 更严格,但 [**`simple_query_string query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html) 不会返回无效语法的错误。相反,它会忽略查询字符串的任何无效部分。
示例:
```bash
GET /_search
{
"query": {
"simple_query_string" : {
"query": "\"fried eggs\" +(eggplant | potato) -frittata",
"fields": ["title^5", "body"],
"default_operator": "and"
}
}
}
```
#### simple_query_string 语义
- `+`:等价于 AND 操作
- `|`:等价于 OR 操作
- `-`:相当于 NOT 操作
- `"`:包装一些标记以表示用于搜索的短语
- `*`:词尾表示前缀查询
- `(` and `)`:表示优先级
- `~N`:词尾表示表示编辑距离(模糊性)
- `~N`:在一个短语之后表示溢出量
注意:要使用上面的字符,请使用反斜杠 `/` 对其进行转义。
### 1.11. 全文查询完整示例
```bash
#设置 position_increment_gap
DELETE groups
PUT groups
{
"mappings": {
"properties": {
"names":{
"type": "text",
"position_increment_gap": 0
}
}
}
}
GET groups/_mapping
POST groups/_doc
{
"names": [ "John Water", "Water Smith"]
}
POST groups/_search
{
"query": {
"match_phrase": {
"names": {
"query": "Water Water",
"slop": 100
}
}
}
}
POST groups/_search
{
"query": {
"match_phrase": {
"names": "Water Smith"
}
}
}
DELETE groups
```
## 2. 词项查询
**`Term`(词项)是表达语意的最小单位**。搜索和利用统计语言模型进行自然语言处理都需要处理 Term。
@ -266,7 +556,7 @@ GET books/_search
- **[`type` query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-type-query.html)**
- **[`wildcard` query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html)**
### exists query
### 2.1. exists query
[**`exists query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html) 会返回字段中至少有一个非空值的文档。
@ -305,7 +595,7 @@ GET kibana_sample_data_ecommerce/_search
- `{ "user" : [null] }` 虽然有 user 字段,但是值为空。
- `{ "foo" : "bar" }` 没有 user 字段。
### fuzzy query
### 2.2. fuzzy query
[**`fuzzy query`**(模糊查询)](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-fuzzy-query.html)返回包含与搜索词相似的词的文档。ES 使用 [Levenshtein edit distanceLevenshtein 编辑距离)](https://en.wikipedia.org/wiki/Levenshtein_distance)测量相似度或模糊度。
@ -338,7 +628,7 @@ GET books/_search
注意:如果配置了 [`search.allow_expensive_queries`](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html#query-dsl-allow-expensive-queries) ,则 fuzzy query 不能执行。
### ids query
### 2.3. ids query
[**`ids query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html) 根据 ID 返回文档。 此查询使用存储在 `_id` 字段中的文档 ID。
@ -353,7 +643,7 @@ GET /_search
}
```
### prefix query
### 2.4. prefix query
[**`prefix query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html#prefix-query-ex-request) 用于查询某个字段中包含指定前缀的文档。
@ -372,7 +662,7 @@ GET /_search
}
```
### range query
### 2.5. range query
[**`range query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html) 即范围查询,用于匹配在某一范围内的数值型、日期类型或者字符串型字段的文档。比如搜索哪些书籍的价格在 50 到 100 之间、哪些书籍的出版时间在 2015 年到 2019 年之间。**使用 range 查询只能查询一个字段,不能作用在多个字段上**。
@ -429,7 +719,7 @@ GET kibana_sample_data_ecommerce/_search
}
```
### regexp query
### 2.6. regexp query
[**`regexp query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html) 返回与正则表达式相匹配的 term 所属的文档。
@ -456,7 +746,7 @@ GET /_search
> 注意:如果配置了[`search.allow_expensive_queries`](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html#query-dsl-allow-expensive-queries) ,则 [**`regexp query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html) 会被禁用。
### term query
### 2.7. term query
[**`term query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html) 用来查找指定字段中包含给定单词的文档term 查询不被解析,只有查询词和文档中的词精确匹配才会被搜索到,应用场景为查询人名、地名等需要精准匹配的需求。
@ -510,7 +800,7 @@ DELETE my-index-000001
>
> 要搜索 text 字段值,需改用 match 查询。
### terms query
### 2.8. terms query
[**`terms query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html) 与 [**`term query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html) 相同,但可以搜索多个值。
@ -567,7 +857,7 @@ GET my-index-000001/_search?pretty
DELETE my-index-000001
```
### type query
### 2.9. type query
> 7.0.0 后废弃
@ -586,7 +876,7 @@ GET /_search
}
```
### wildcard query
### 2.10. wildcard query
[**`wildcard query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html) 即通配符查询,返回与通配符模式匹配的文档。
@ -611,11 +901,95 @@ GET /_search
> 注意:如果配置了[`search.allow_expensive_queries`](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html#query-dsl-allow-expensive-queries) ,则[**`wildcard query`**](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html) 会被禁用。
## 复合查询
### 2.11. 词项查询完整示例
```bash
DELETE products
PUT products
{
"settings": {
"number_of_shards": 1
}
}
POST /products/_bulk
{ "index": { "_id": 1 }}
{ "productID" : "XHDK-A-1293-#fJ3","desc":"iPhone" }
{ "index": { "_id": 2 }}
{ "productID" : "KDKE-B-9947-#kL5","desc":"iPad" }
{ "index": { "_id": 3 }}
{ "productID" : "JODL-X-1937-#pV7","desc":"MBP" }
GET /products
POST /products/_search
{
"query": {
"term": {
"desc": {
//"value": "iPhone"
"value":"iphone"
}
}
}
}
POST /products/_search
{
"query": {
"term": {
"desc.keyword": {
//"value": "iPhone"
//"value":"iphone"
}
}
}
}
POST /products/_search
{
"query": {
"term": {
"productID": {
"value": "XHDK-A-1293-#fJ3"
}
}
}
}
POST /products/_search
{
//"explain": true,
"query": {
"term": {
"productID.keyword": {
"value": "XHDK-A-1293-#fJ3"
}
}
}
}
POST /products/_search
{
"explain": true,
"query": {
"constant_score": {
"filter": {
"term": {
"productID.keyword": "XHDK-A-1293-#fJ3"
}
}
}
}
}
```
## 3. 复合查询
复合查询就是把一些简单查询组合在一起实现更复杂的查询需求,除此之外,复合查询还可以控制另外一个查询的行为。
### bool query
### 3.1. bool query
bool 查询可以把任意多个简单查询组合在一起,使用 must、should、must_not、filter 选项来表示简单查询之间的逻辑,每个选项都可以出现 0 次到多次,它们的含义如下:
@ -663,7 +1037,7 @@ GET books/_search
有关布尔查询更详细的信息参考 [bool query组合查询详解](https://www.knowledgedict.com/tutorial/elasticsearch-query-bool.html)。
### boosting query
### 3.2. boosting query
boosting 查询用于需要对两个查询的评分进行调整的场景boosting 查询会把两个查询封装在一起并降低其中一个查询的评分。
@ -694,7 +1068,7 @@ GET books/_search
boosting 查询中指定了抑制因子为 0.2publish_time 的值在 2015-01-01 之后的文档得分不变publish_time 的值在 2015-01-01 之前的文档得分为原得分的 0.2 倍。
### constant_score query
### 3.3. constant_score query
constant*score query 包装一个 filter query并返回匹配过滤器查询条件的文档且它们的相关性评分都等于 \_boost* 参数值(可以理解为原有的基于 tf-idf 或 bm25 的相关分固定为 1.0,所以最终评分为 _1.0 \* boost_,即等于 _boost_ 参数值)。下面的查询语句会返回 title 字段中含有关键词 _elasticsearch_ 的文档,所有文档的评分都是 1.8
@ -714,7 +1088,7 @@ GET books/_search
}
```
### dis_max query
### 3.4. dis_max query
dis_max query 与 bool query 有一定联系也有一定区别dis_max query 支持多并发查询,可返回与任意查询条件子句匹配的任何文档类型。与 bool 查询可以将所有匹配查询的分数相结合使用的方式不同dis_max 查询只使用最佳匹配查询条件的分数。请看下面的例子:
@ -741,7 +1115,7 @@ GET books/_search
}
```
### function_score query
### 3.5. function_score query
function_score query 可以修改查询的文档得分,这个查询在有些情况下非常有用,比如通过评分函数计算文档得分代价较高,可以改用过滤器加自定义评分函数的方式来取代传统的评分方式。
@ -787,7 +1161,7 @@ GET books/_search
关于 function_score 的更多详细内容请查看 [Elasticsearch function_score 查询最强详解](https://www.knowledgedict.com/tutorial/elasticsearch-function_score.html)。
### indices query
### 3.6. indices query
indices query 适用于需要在多个索引之间进行查询的场景它允许指定一个索引名字列表和内部查询。indices query 中有 query 和 no_match_query 两部分query 中用于搜索指定索引列表中的文档no_match_query 中的查询条件用于搜索指定索引列表之外的文档。下面的查询语句实现了搜索索引 books、books2 中 title 字段包含关键字 javascript其他索引中 title 字段包含 basketball 的文档,查询语句如下:
@ -812,7 +1186,7 @@ GET books/_search
}
```
## 嵌套查询
## 4. 嵌套查询
在 Elasticsearch 这样的分布式系统中执行全 SQL 风格的连接查询代价昂贵是不可行的。相应地为了实现水平规模地扩展Elasticsearch 提供了以下两种形式的 join
@ -824,7 +1198,7 @@ GET books/_search
父子关系可以存在单个的索引的两个类型的文档之间。has_child 查询将返回其子文档能满足特定查询的父文档,而 has_parent 则返回其父文档能满足特定查询的子文档。
### nested query
### 4.1. nested query
文档中可能包含嵌套类型的字段,这些字段用来索引一些数组对象,每个对象都可以作为一条独立的文档被查询出来(用嵌套查询)。
@ -843,7 +1217,7 @@ PUT /my_index
}
```
### has_child query
### 4.2. has_child query
文档的父子关系创建索引时在映射中声明这里以员工employee和工作城市branch为例它们属于不同的类型相当于数据库中的两张表如果想把员工和他们工作的城市关联起来需要告诉 Elasticsearch 文档之间的父子关系,这里 employee 是 child typebranch 是 parent type在映射中声明执行命令
@ -935,7 +1309,7 @@ GET company/branch/_search?pretty
}
```
### has_parent query
### 4.3. has_parent query
通过父文档查询子文档使用 has_parent 查询。比如,搜索哪些 employee 工作在 UK查询命令如下
@ -953,7 +1327,7 @@ GET company/employee/_search
}
```
## 位置查询
## 5. 位置查询
Elasticsearch 可以对地理位置点 geo_point 类型和地理位置形状 geo_shape 类型的数据进行搜索。为了学习方便,这里准备一些城市的地理坐标作为测试数据,每一条文档都包含城市名称和地理坐标这两个字段,这里的坐标点取的是各个城市中心的一个位置。首先把下面的内容保存到 geo.json 文件中:
@ -998,7 +1372,7 @@ PUT geo
curl -XPOST "http://localhost:9200/_bulk?pretty" --data-binary @geo.json
```
### geo_distance query
### 5.1. geo_distance query
geo_distance query 可以查找在一个中心点指定范围内的地理点文档。例如,查找距离天津 200km 以内的城市,搜索结果中会返回北京,命令如下:
@ -1045,7 +1419,7 @@ GET geo/_search
其中 location 对应的经纬度字段unit 为 `km` 表示将距离以 `km` 为单位写入到每个返回结果的 sort 键中distance_type 为 `plane` 表示使用快速但精度略差的 `plane` 计算方式。
### geo_bounding_box query
### 5.2. geo_bounding_box query
geo_bounding_box query 用于查找落入指定的矩形内的地理坐标。查询中由两个点确定一个矩形,然后在矩形区域内查询匹配的文档。
@ -1076,7 +1450,7 @@ GET geo/_search
}
```
### geo_polygon query
### 5.3. geo_polygon query
geo_polygon query 用于查找在指定**多边形**内的地理点。例如,呼和浩特、重庆、上海三地组成一个三角形,查询位置在该三角形区域内的城市,命令如下:
@ -1109,7 +1483,7 @@ GET geo/_search
}
```
### geo_shape query
### 5.4. geo_shape query
geo_shape query 用于查询 geo_shape 类型的地理数据,地理形状之间的关系有相交、包含、不相交三种。创建一个新的索引用于测试,其中 location 字段的类型设为 geo_shape 类型。
@ -1178,9 +1552,9 @@ GET geoshape/_search
}
```
## 特殊查询
## 6. 特殊查询
### more_like_this query
### 6.1. more_like_this query
more_like_this query 可以查询和提供文本类似的文档,通常用于近似文本的推荐等场景。查询命令如下:
@ -1215,7 +1589,7 @@ GET books/_search
- include 是否把输入文档作为结果返回。
- boost 整个 query 的权重,默认为 1.0。
### script query
### 6.2. script query
Elasticsearch 支持使用脚本进行查询。例如,查询价格大于 180 的文档,命令如下:
@ -1233,7 +1607,7 @@ GET books/_search
}
```
### percolate query
### 6.3. percolate query
一般情况下,我们是先把文档写入到 Elasticsearch 中通过查询语句对文档进行搜索。percolate query 则是反其道而行之的做法,它会先注册查询条件,根据文档来查询 query。例如在 my-index 索引中有一个 laptop 类型,文档有 price 和 name 两个字段,在映射中声明一个 percolator 类型的 query命令如下

View File

@ -0,0 +1,723 @@
# Elasticsearch 聚合
Elasticsearch 是一个分布式的全文搜索引擎,索引和搜索是 Elasticsearch 的基本功能。事实上Elasticsearch 的聚合Aggregations功能也十分强大允许在数据上做复杂的分析统计。Elasticsearch 提供的聚合分析功能主要有**指标聚合metrics aggregations**、**桶聚合bucket aggregations**、**管道聚合pipeline aggregations**和**矩阵聚合matrix aggregations**四大类,管道聚合和矩阵聚合官方说明是在试验阶段,后期会完全更改或者移除,这里不再对管道聚合和矩阵聚合进行讲解。
## 聚合的具体结构
所有的聚合,无论它们是什么类型,都遵从以下的规则。
- 使用查询中同样的 JSON 请求来定义它们,而且你是使用键 aggregations 或者是 aggs 来进行标记。需要给每个聚合起一个名字,指定它的类型以及和该类型相关的选项。
- 它们运行在查询的结果之上。和查询不匹配的文档不会计算在内,除非你使用 global 聚集将不匹配的文档囊括其中。
- 可以进一步过滤查询的结果,而不影响聚集。
以下是聚合的基本结构:
```json
"aggregations" : { <!-- 最外层的聚合键,也可以缩写为 aggs -->
"<aggregation_name>" : { <!-- 聚合的自定义名字 -->
"<aggregation_type>" : { <!-- 聚合的类型,指标相关的,如 max、min、avg、sum桶相关的 terms、filter 等 -->
<aggregation_body> <!-- 聚合体:对哪些字段进行聚合,可以取字段的值,也可以是脚本计算的结果 -->
}
[,"meta" : { [<meta_data_body>] } ]? <!---->
[,"aggregations" : { [<sub_aggregation>]+ } ]? <!-- 在聚合里面在定义子聚合 -->
}
[,"<aggregation_name_2>" : { ... } ]* <!-- 聚合的自定义名字 2 -->
}
```
- **在最上层有一个 aggregations 的键,可以缩写为 aggs**。
- 在下面一层,需要为聚合指定一个名字。可以在请求的返回中看到这个名字。在同一个请求中使用多个聚合时,这一点非常有用,它让你可以很容易地理解每组结果的含义。
- 最后,必须要指定聚合的类型。
> 关于聚合分析的值来源,可以**取字段的值**,也可以是**脚本计算的结果**。
>
> 但是用脚本计算的结果时,需要注意脚本的性能和安全性;尽管多数聚集类型允许使用脚本,但是脚本使得聚集变得缓慢,因为脚本必须在每篇文档上运行。为了避免脚本的运行,可以在索引阶段进行计算。
>
> 此外脚本也可以被人可能利用进行恶意代码攻击尽量使用沙盒sandbox内的脚本语言。
### 示例
查询所有球员的平均年龄是多少,并对球员的平均薪水加 188也可以理解为每名球员加 188 后的平均薪水)。
```bash
POST /player/_search?size=0
{
"aggs": {
"avg_age": {
"avg": {
"field": "age"
}
},
"avg_salary_188": {
"avg": {
"script": {
"source": "doc.salary.value + 188"
}
}
}
}
}
```
## 指标聚合
指标聚合(又称度量聚合)主要从不同文档的分组中提取统计数据,或者,从来自其他聚合的文档桶来提取统计数据。
这些统计数据通常来自数值型字段,如最小或者平均价格。用户可以单独获取每项统计数据,或者也可以使用 stats 聚合来同时获取它们。更高级的统计数据,如平方和或者是标准差,可以通过 extended stats 聚合来获取。
### Max Aggregation
Max Aggregation 用于最大值统计。例如,统计 sales 索引中价格最高的是哪本书,并且计算出对应的价格的 2 倍值,查询语句如下:
```
GET /sales/_search?size=0
{
"aggs" : {
"max_price" : {
"max" : {
"field" : "price"
}
},
"max_price_2" : {
"max" : {
"field" : "price",
"script": {
"source": "_value * 2.0"
}
}
}
}
}
```
**指定的 field在脚本中可以用 \_value 取字段的值**。
聚合结果如下:
```
{
...
"aggregations": {
"max_price": {
"value": 188.0
},
"max_price_2": {
"value": 376.0
}
}
}
```
### Min Aggregation
Min Aggregation 用于最小值统计。例如,统计 sales 索引中价格最低的是哪本书,查询语句如下:
```
GET /sales/_search?size=0
{
"aggs" : {
"min_price" : {
"min" : {
"field" : "price"
}
}
}
}
```
聚合结果如下:
```
{
...
"aggregations": {
"min_price": {
"value": 18.0
}
}
}
```
### Avg Aggregation
Avg Aggregation 用于计算平均值。例如,统计 exams 索引中考试的平均分数,如未存在分数,默认为 60 分,查询语句如下:
```
GET /exams/_search?size=0
{
"aggs" : {
"avg_grade" : {
"avg" : {
"field" : "grade",
"missing": 60
}
}
}
}
```
**如果指定字段没有值,可以通过 missing 指定默认值;若未指定默认值,缺失该字段值的文档将被忽略(计算)**。
聚合结果如下:
```
{
...
"aggregations": {
"avg_grade": {
"value": 78.0
}
}
}
```
除了常规的平均值聚合计算外elasticsearch 还提供了加权平均值的聚合计算,详情参见 [Elasticsearch 指标聚合之 Weighted Avg Aggregation](https://www.knowledgedict.com/tutorial/elasticsearch-aggregations-metrics-weighted-avg-aggregation.html)。
### Sum Aggregation
Sum Aggregation 用于计算总和。例如,统计 sales 索引中 type 字段中匹配 hat 的价格总和,查询语句如下:
```
GET /exams/_search?size=0
{
"query" : {
"constant_score" : {
"filter" : {
"match" : { "type" : "hat" }
}
}
},
"aggs" : {
"hat_prices" : {
"sum" : { "field" : "price" }
}
}
}
```
聚合结果如下:
```
{
...
"aggregations": {
"hat_prices": {
"value": 567.0
}
}
}
```
### Value Count Aggregation
Value Count Aggregation 可按字段统计文档数量。例如,统计 books 索引中包含 author 字段的文档数量,查询语句如下:
```
GET /books/_search?size=0
{
"aggs" : {
"doc_count" : {
"value_count" : { "field" : "author" }
}
}
}
```
聚合结果如下:
```
{
...
"aggregations": {
"doc_count": {
"value": 5
}
}
}
```
### Cardinality Aggregation
Cardinality Aggregation 用于基数统计,其作用是先执行类似 SQL 中的 distinct 操作,去掉集合中的重复项,然后统计排重后的集合长度。例如,在 books 索引中对 language 字段进行 cardinality 操作可以统计出编程语言的种类数,查询语句如下:
```
GET /books/_search?size=0
{
"aggs" : {
"all_lan" : {
"cardinality" : { "field" : "language" }
},
"title_cnt" : {
"cardinality" : { "field" : "title.keyword" }
}
}
}
```
**假设 title 字段为文本类型text去重时需要指定 keyword表示把 title 作为整体去重,即不分词统计**。
聚合结果如下:
```
{
...
"aggregations": {
"all_lan": {
"value": 8
},
"title_cnt": {
"value": 18
}
}
}
```
### Stats Aggregation
Stats Aggregation 用于基本统计,会一次返回 count、max、min、avg 和 sum 这 5 个指标。例如,在 exams 索引中对 grade 字段进行分数相关的基本统计,查询语句如下:
```
GET /exams/_search?size=0
{
"aggs" : {
"grades_stats" : {
"stats" : { "field" : "grade" }
}
}
}
```
聚合结果如下:
```
{
...
"aggregations": {
"grades_stats": {
"count": 2,
"min": 50.0,
"max": 100.0,
"avg": 75.0,
"sum": 150.0
}
}
}
```
### Extended Stats Aggregation
Extended Stats Aggregation 用于高级统计和基本统计功能类似但是会比基本统计多出以下几个统计结果sum_of_squares平方和、variance方差、std_deviation标准差、std_deviation_bounds平均值加/减两个标准差的区间)。在 exams 索引中对 grade 字段进行分数相关的高级统计,查询语句如下:
```
GET /exams/_search?size=0
{
"aggs" : {
"grades_stats" : {
"extended_stats" : { "field" : "grade" }
}
}
}
```
聚合结果如下:
```
{
...
"aggregations": {
"grades_stats": {
"count": 2,
"min": 50.0,
"max": 100.0,
"avg": 75.0,
"sum": 150.0,
"sum_of_squares": 12500.0,
"variance": 625.0,
"std_deviation": 25.0,
"std_deviation_bounds": {
"upper": 125.0,
"lower": 25.0
}
}
}
}
```
### Percentiles Aggregation
Percentiles Aggregation 用于百分位统计。百分位数是一个统计学术语,如果将一组数据从大到小排序,并计算相应的累计百分位,某一百分位所对应数据的值就称为这一百分位的百分位数。默认情况下,累计百分位为 [ 1, 5, 25, 50, 75, 95, 99 ]。以下例子给出了在 latency 索引中对 load_time 字段进行加载时间的百分位统计,查询语句如下:
```
GET latency/_search
{
"size": 0,
"aggs" : {
"load_time_outlier" : {
"percentiles" : {
"field" : "load_time"
}
}
}
}
```
**需要注意的是,如上的 `load_time` 字段必须是数字类型**。
聚合结果如下:
```
{
...
"aggregations": {
"load_time_outlier": {
"values" : {
"1.0": 5.0,
"5.0": 25.0,
"25.0": 165.0,
"50.0": 445.0,
"75.0": 725.0,
"95.0": 945.0,
"99.0": 985.0
}
}
}
}
```
百分位的统计也可以指定 percents 参数指定百分位,如下:
```
GET latency/_search
{
"size": 0,
"aggs" : {
"load_time_outlier" : {
"percentiles" : {
"field" : "load_time",
"percents": [60, 80, 95]
}
}
}
}
```
### Percentiles Ranks Aggregation
Percentiles Ranks Aggregation 与 Percentiles Aggregation 统计恰恰相反,就是想看当前数值处在什么范围内(百分位), 假如你查一下当前值 500 和 600 所处的百分位,发现是 90.01 和 100那么说明有 90.01 % 的数值都在 500 以内100 % 的数值在 600 以内。
```
GET latency/_search
{
"size": 0,
"aggs" : {
"load_time_ranks" : {
"percentile_ranks" : {
"field" : "load_time",
"values" : [500, 600]
}
}
}
}
```
**`同样 load_time` 字段必须是数字类型**。
返回结果大概类似如下:
```
{
...
"aggregations": {
"load_time_ranks": {
"values" : {
"500.0": 90.01,
"600.0": 100.0
}
}
}
}
```
可以设置 `keyed` 参数为 `true`,将对应的 values 作为桶 key 一起返回,默认是 `false`
```
GET latency/_search
{
"size": 0,
"aggs": {
"load_time_ranks": {
"percentile_ranks": {
"field": "load_time",
"values": [500, 600],
"keyed": true
}
}
}
}
```
返回结果如下:
```
{
...
"aggregations": {
"load_time_ranks": {
"values": [
{
"key": 500.0,
"value": 90.01
},
{
"key": 600.0,
"value": 100.0
}
]
}
}
}
```
## 桶聚合
bucket 可以理解为一个桶,它会遍历文档中的内容,凡是符合某一要求的就放入一个桶中,分桶相当于 SQL 中的 group by。从另外一个角度可以将指标聚合看成单桶聚合即把所有文档放到一个桶中而桶聚合是多桶型聚合它根据相应的条件进行分组。
| 种类 | 描述/场景 |
| :-------------------------------------------- | :--------------------------------------------------------------------------------------------- |
| 词项聚合Terms Aggregation | 用于分组聚合,让用户得知文档中每个词项的频率,它返回每个词项出现的次数。 |
| 差异词项聚合Significant Terms Aggregation | 它会返回某个词项在整个索引中和在查询结果中的词频差异,这有助于我们发现搜索场景中有意义的词。 |
| 过滤器聚合Filter Aggregation | 指定过滤器匹配的所有文档到单个桶bucket通常这将用于将当前聚合上下文缩小到一组特定的文档。 |
| 多过滤器聚合Filters Aggregation | 指定多个过滤器匹配所有文档到多个桶bucket。 |
| 范围聚合Range Aggregation | 范围聚合,用于反映数据的分布情况。 |
| 日期范围聚合Date Range Aggregation | 专门用于日期类型的范围聚合。 |
| IP 范围聚合IP Range Aggregation | 用于对 IP 类型数据范围聚合。 |
| 直方图聚合Histogram Aggregation | 可能是数值,或者日期型,和范围聚集类似。 |
| 时间直方图聚合Date Histogram Aggregation | 时间直方图聚合,常用于按照日期对文档进行统计并绘制条形图。 |
| 空值聚合Missing Aggregation | 空值聚合,可以把文档集中所有缺失字段的文档分到一个桶中。 |
| 地理点范围聚合Geo Distance Aggregation | 用于对地理点geo point做范围统计。 |
### Terms Aggregation
Terms Aggregation 用于词项的分组聚合。最为经典的用例是获取 X 中最频繁top frequent的项目其中 X 是文档中的某个字段,如用户的名称、标签或分类。由于 terms 聚集统计的是每个词条,而不是整个字段值,因此通常需要在一个非分析型的字段上运行这种聚集。原因是, 你期望“big data”作为词组统计而不是“big”单独统计一次“data”再单独统计一次。
用户可以使用 terms 聚集,从分析型字段(如内容)中抽取最为频繁的词条。还可以使用这种信息来生成一个单词云。
```
{
"aggs": {
"profit_terms": {
"terms": { // terms 聚合 关键字
"field": "profit",
......
}
}
}
}
```
在 terms 分桶的基础上,还可以对每个桶进行指标统计,也可以基于一些指标或字段值进行排序。示例如下:
```
{
"aggs": {
"item_terms": {
"terms": {
"field": "item_id",
"size": 1000,
"order":[{
"gmv_stat": "desc"
},{
"gmv_180d": "desc"
}]
},
"aggs": {
"gmv_stat": {
"sum": {
"field": "gmv"
}
},
"gmv_180d": {
"sum": {
"script": "doc['gmv_90d'].value*2"
}
}
}
}
}
}
```
返回的结果如下:
```
{
...
"aggregations": {
"hospital_id_agg": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 260,
"buckets": [
{
"key": 23388,
"doc_count": 18,
"gmv_stat": {
"value": 176220
},
"gmv_180d": {
"value": 89732
}
},
{
"key": 96117,
"doc_count": 16,
"gmv_stat": {
"value": 129306
},
"gmv_180d": {
"value": 56988
}
},
...
]
}
}
}
```
默认情况下返回按文档计数从高到低的前 10 个分组,可以通过 size 参数指定返回的分组数。
### Filter Aggregation
Filter Aggregation 是过滤器聚合,可以把符合过滤器中的条件的文档分到一个桶中,即是单分组聚合。
```
{
"aggs": {
"age_terms": {
"filter": {"match":{"gender":"F"}},
"aggs": {
"avg_age": {
"avg": {
"field": "age"
}
}
}
}
}
}
```
### Filters Aggregation
Filters Aggregation 是多过滤器聚合,可以把符合多个过滤条件的文档分到不同的桶中,即每个分组关联一个过滤条件,并收集所有满足自身过滤条件的文档。
```
{
"size": 0,
"aggs": {
"messages": {
"filters": {
"filters": {
"errors": { "match": { "body": "error" } },
"warnings": { "match": { "body": "warning" } }
}
}
}
}
}
```
在这个例子里,我们分析日志信息。聚合会创建两个关于日志数据的分组,一个收集包含错误信息的文档,另一个收集包含告警信息的文档。而且每个分组会按月份划分。
```
{
...
"aggregations": {
"messages": {
"buckets": {
"errors": {
"doc_count": 1
},
"warnings": {
"doc_count": 2
}
}
}
}
}
```
### Range Aggregation
Range Aggregation 范围聚合是一个基于多组值来源的聚合,可以让用户定义一系列范围,每个范围代表一个分组。在聚合执行的过程中,从每个文档提取出来的值都会检查每个分组的范围,并且使相关的文档落入分组中。注意,范围聚合的每个范围内包含 from 值但是排除 to 值。
```
{
"aggs": {
"age_range": {
"range": {
"field": "age",
"ranges": [{
"to": 25
},
{
"from": 25,
"to": 35
},
{
"from": 35
}]
},
"aggs": {
"bmax": {
"max": {
"field": "balance"
}
}
}
}
}
}
}
```
返回结果如下:
```
{
...
"aggregations": {
"age_range": {
"buckets": [{
"key": "*-25.0",
"to": 25,
"doc_count": 225,
"bmax": {
"value": 49587
}
},
{
"key": "25.0-35.0",
"from": 25,
"to": 35,
"doc_count": 485,
"bmax": {
"value": 49795
}
},
{
"key": "35.0-*",
"from": 35,
"doc_count": 290,
"bmax": {
"value": 49989
}
}]
}
}
}
```
## 参考资料
- [Elasticsearch 教程](https://www.knowledgedict.com/tutorial/elasticsearch-intro.html)

View File

@ -12,7 +12,8 @@
- [Elasticsearch 基本概念](Elasticsearch基本概念.md)
- [Elasticsearch Rest API](ElasticsearchRestApi.md)
- [Elasticsearch 查询](Elasticsearch查询.md)
- Elasticsearch 聚合
- [Elasticsearch 排序](Elasticsearch排序.md)
- [Elasticsearch 聚合](Elasticsearch聚合.md)
- Elasticsearch 分词
- [Elasticsearch 运维](Elasticsearch运维.md)