Elasticsearch的入门使用

part 1

前言
emmmmm….我一个前端学习es我也很为难啊。elasticsearch涉及的内容非常多,分布式相关的章节我都是跳过的。因为我真的看不懂????
参考文章以及相关资料
Elastic Stack and Product DocumentationElasticsearch: 权威指南Elastic Stack从入门到实践
安装,启动,汉化
首先你的电脑需要拥有Java8的环境
// 使用Homebrew一键安装

brew update

brew install elasticsearch

// kibana是一个可视化工具
brew install kibana
????️kibana的汉化, 可以使用GitHub上的提供的包(需要安装python环境)
RESTful API
可以使用RESTful API通过9200端口与Elasticsearch进行交互
基本概念
Index
索引类似于数据库中表,是用来存储文档的地方。将数据存储到es的行为也可以叫做索引
type
???? Mapping types will be completely removed in Elasticsearch 7.0.0. (type的概念将在7.0中被删除)
???? The first alternative is to have an index per document type (更好的做法是, 每一种type将会有单独的Index, 不同的type存储到不同的索引中)
Document
Index(索引)中的每一条记录被称为文档, 许多的Document组成了Index
搜索
空搜索
返回所有索引下的所有文档

GET /_search

# 等同于,匹配所有的文档
GET /_search
{
“query”: {
“match_all”: {}
}
}
简单搜索
通过查询字符串query-string搜索, 通过URL参数的形式, 传递查询参数

# 查询test_index索引中, name字段包含lihang的文档
GET test_index/_search?q=name:lihang

# 查询test_index索引中, name字段包含zhangyue或者liyubo
GET test_index/_search?q=name:(zhangyue OR liyubo)
QueryDSL
Query DSL指定了一个JSON进行检索, 它支持构建更加复杂和健壮的查询

# match查询, 会将查询语句进行分词处理, 查询name字段中包含lihang的文档

GET test_index/_search
{
“query”: {
“match”: {
“name”: “lihang”
}
}
}
全文搜索
使用match查询全文字段,可以对查询语句进行分词操作,返回所有的相关的文档,查询结果按照相关度算分排序。如果查询的是数字,日期,Boolean,match则会进行精确匹配

# 查询job字段中和engineer相关的文档

GET test_index/_search
{
“query”: {
“match”: {
“job”: “engineer”
}
}
}
短语搜索
使用match_phrase可以查询job字段中包含查询短语的文档

GET test_index/_search
{
“query”: {
“match_phrase”: {
“job”: “node engineer”
}
}
}

# 通过设置slop相似度, 可以允许查询文档与差异语句有一些差异
# 设置slop为2, java engineer 和 java web engineer 可以匹配

GET test_index/_search
{
“query”: {
“match_phrase”: {
“job”: {
“query”: “java engineer”,
“slop”: 2
}
}
}
}
高亮搜索
会对检索的匹配的结果中,匹配的部分做出高亮的展示, 使用标签em包裹

GET test_index/_search
{
“query”: {
“match”: {
“job”: “engineer”
}
},
“highlight”: {
“fields”: {
“job”: {}
}
}
}
// 返回的部分结果
{
“_index”: “test_index”,
“_type”: “doc”,
“_id”: “3”,
“_score”: 0.2876821,
“_source”: {
“name”: “houjiaying”,
“job”: “java engineer”,
“age”: 22
},
“highlight”: {
“job”: [
“java <em>engineer</em>”
]
}
}
多索引搜索
GET /test_index, test2_index/_search
???? 针对多个索引进行搜索操作, 文档中也是类似的语法。但是我不太清楚为什么返回错误给我,如果有好心人请告诉我
???? Multi-Index search (autocomplete)(折中的解决方案)

# 使用_msearch方法多索引搜索

GET _msearch
{“index”:”test_index”}
{“query”:{“term”:{“age”:{“value”:23}}}}
{“index”:”test2_index”}
{“query”:{“term”:{“_id”:{“value”:1}}}}
分页
使用form指定查询的起始位置, size指定查询的数量

GET _all/_search?size=5&from=1

GET _all/_search
{
“from”: 0,
“size”: 1
}

聚合

# 统计索引中全部文档的age,并会返回聚合的结果

GET /test_index/doc/_search
{
“aggs”: {
// 返回聚合结果到all_age字段中, 聚合terms匹配的age字段
“all_age”: {
“terms”: { “field”: “age” }
}
}
}

// 返回的聚合结果
“aggregations”: {
// all_age是自己定义的
“all_age”: {
“doc_count_error_upper_bound”: 0,
“sum_other_doc_count”: 0,
“buckets”: [
{
“key”: 24,
“doc_count”: 2
},
{
“key”: 22,
“doc_count”: 1
},
{
“key”: 23,
“doc_count”: 1
},
{
“key”: 30,
“doc_count”: 1
}
]
}
}
聚合分级汇总

# 添加测试用数据

DELETE test_index
PUT test_index
POST test_index/doc/_bulk
{“index”:{“_id”:1}}
{“name”:”zhangyue”,”age”:23,”job”:”web”}
{“index”:{“_id”:2}}
{“name”:”lihange”,”age”:23,”job”:”web”}
{“index”:{“_id”:3}}
{“name”:”liyubo”,”age”:22,”job”:”web”}
{“index”:{“_id”:4}}
{“name”:”houjiaying”,”age”:22,”job”:”java”}
{“index”:{“_id”:5}}
{“name”:”xiaodong”,”age”:26,”job”:”java”}

# 聚合查询分级汇总
# 汇总所有的职业并计算职业的评价年龄

GET test_index/doc/_search
{
“aggs”: {
“job_info”: {
“terms”: {
“field”: “job”
},
“aggs”: {
“avg_age”: {
“avg”: {
“field”: “age”
}
}
}
}
}
}
???? 解决方案
???? Fielddata is disabled on text fields by default. Set fielddata=true
???? 在text字段中聚合是聚合是禁用的,需要设置索引的mapping, 设置字段的fielddata为true

# 设置job字段的fielddata为true

PUT test_index/_mapping/doc
{
“doc”: {
“properties”: {
“job”: {
“type”: “text”,
“fielddata”: true
}
}
}
}
Document
元数据

_index 文档存放的索引
_type 文档的类型
_id 文档的唯一标识

创建文档
可以分为指定ID创建, 和不指定ID创建(Elasticsearch会自动创建一个唯一标示)。指定ID使用PUT请求, 不指定ID使用POST请求
查询指定ID文档
GET /you_index/you_type/you_document_id
指定返回的字段

# 只返回文档的name字段

GET test_index/doc/1?_source=name

# 只返回文档的age字段

GET test_index/doc/_search
{
“query”: {
“range”: {
“age”: {
“gt”: 23
}
}
},
“_source”: {
// 返回的字段
“includes”: [“age”],
// 不返回的字段
“excludes”: []
}
}
检查文档是否存在
使用HEAD方法,HEAD不返回响应体

# 检查ID为1的文档是否存在

HEAD test_index/doc/1
更新文档

POST test_index/doc/1/_update
{
“doc”: {
“name”: “zhang yue”
}
}
???? 更新文档后的返回结果, 可以看的_version变为了2,_version字段的含义是文档更新了几次, _version可以实现乐观锁的功能

{
“_index”: “test_index”,
“_type”: “doc”,
“_id”: “1”,
“_version”: 2,
“found”: true,
“_source”: {
“name”: “zhangyueHI”,
“age”: 23,
“job”: “web”
}
}
删除文档

# 删除ID为2的文档

DELETE test_index/doc/2
乐观锁
更新的时候,指定_version的大小,当更新文档的时候_version必须等于我们指定的大小,更新操作才会成功

# version为2时更新操作才会成功
POST test_index/doc/1/_update?version=2
{
“doc”: {
“name”: “zhangyue”
}
}
批量检索

# 检索同一个索引下的多个的文档

GET /test_index/doc/_mget
{
“docs”: [
{
“_id”: 1
},
{
“_id”: 3
}
]
}

# 直接通过不同的id, 检索同一个索引下的多个的文档

GET /test_index/doc/_mget
{
“ids”: [1, 3, 4]
}

# 检索不同索引下的多个文档

GET /_mget
{
“docs”: [
{
“_index”: “test_index”,
“_type”: “doc”,
“_id”: 1
},
{
“_index”: “test2_index”,
“_type”: “doc”,
“_id”: 1
}
]
}
批量创建
批量创建的JSON中, 不能包含未转义的换行符,因为他们将会对解析造成干扰。必须使用Kibana自动格式化JSON,才可以正确的执行_bulk操作
批量操作关键字, index(创建, id重复时覆盖), delete(删除), create(创建, id重复时报错), update(更新)

# 批量操作
POST /test_index/doc/_bulk
{“index”:{“_index”:”test_index”,”_type”:”doc”,”_id”:2}}
{“name”:”songmin”,”age”:20}
{“delete”:{“_index”:”test_index”,”_type”:”doc”,”_id”:2}}
{“create”:{“_index”:”test_index”,”_type”:”doc”,”_id”:2}}
{“name”:”songmin”,”age”:18}
{“update”:{“_index”:”test_index”,”_type”:”doc”,”_id”:2}}
{“doc”:{“age”:22}}
Mapping与分析
精确值与全文
精确值,通常指的是日期, 用户ID, 邮箱地址。对于精确值, java 与 java web是不同的。精确值,要么匹配查询,要么不匹配。
全文, 通常指的是文本数据, 匹配时是查询的匹配的程度
倒排索引
Elasticsearch中使用倒排索引的方式,实现快速的全文搜索
倒排索引是由文档中, 是所有可以被分词的字段的复词列表组成的。将所有文档的复词列表,用来创建一个没有重复分词的复词列表。并且记录了,每一个分词出现在那一个文档中。
例如搜索短语”dog over”, 在倒排索引中在Doc_1, Doc_2都会匹配, 但Doc_1文档的匹配度会更高

Term Doc_1 Doc_2
————————-
Quick | | X
The | X |
brown | X | X
dog | X |
dogs | | X
fox | X |
foxes | | X
in | | X
jumped | X |
lazy | X | X
leap | | X
over | X | X
quick | X |
summer | | X
the | X |
————————
分析器
分析器由以下三种功能组成:

字符过滤器, 例如过滤文本中HTML标签
分词器, 将文本拆分成单独的词条
Token过滤器, 过滤分词, 例如转化大小写, 删除语气组词

Elasticsearch内置了多种的分析器, 例如空格分析器, 可以按照空格分词。语言分析器, 可以删除多余的语气助词
如果希望指定索引中字段的分析器,则需要我手动的指定索引的Mapping
analyze API

# 测试standard分析器
GET /_analyze
{
“analyzer”: “standard”,
“text”: “Text to analyze”
}
Mapping
Mapping的定义可以类比为Mongo中Schema, 在Mapping中定义了索引里每个字段的类型以及分析器等

# 查看索引的Mapping

GET test_index/doc/_mapping
自定义Mapping
???? Elasticsearch中, 已经不存在string, object类型, 使用text类型。
???? 字段的type被设置为”text”类型, 字段通常会被全文检索。如果设置为”keyword”类型, 字段会则需要精确查找。
???? 当字段的type被设置为”text”类型, 可以另外设置index(是否可以被搜索)和analyzer(分析器)

# 自定义索引的Mapping

PUT m2y_index
{
“mappings”: {
“doc”: {
“properties”: {
“info”: {
type: “text”
}
}
}
}
}
更新Mapping
不能直接更新索引的Mapping, 只能在创建索引的时候指定Mapping, 以及添加新的字段的Mapping
复杂类型

数组类型, 数组的内容必须类型一致, 检索时, 所有包含在数组中的内容都可以被检索
null, 空值不会被索引
Object, 可以通过以下的方式定义Object类型的Mapping(通过嵌套properties)

# 定义Object类型的Mapping

POST test3_index/doc
{
“mappings”: {
“doc”: {
“properties”: {
“info”: {
“properties”: {
“name”: {
“type”: “text”
},
“age”: {
“type”: “text”
},
“hobbies”: {
“properties”: {
“one”: {
“type”: “text”
},
“two”: {
“type”: “text”
}
}
}
}
}
}
}
}
}
查询
match查询
match查询时,如果查询是全文字段,会对查询内容分词后进行全文搜索。如果指定的是数字, 日期, 布尔字段, match查询则会进行精准匹配
multi_match查询
对多个字段(fields数组中的字段), 执行相同的match查询
GET test_index/doc/_search
{
“query”: {
“multi_match”: {
“query”: “web”,
“fields”: [“job”, “name”]
}
}
}
range查询
进行范围查询操作, 关键字gt(大于), gte(大于等于), lt(小于), lte(小于等于)

GET test_index/doc/_search
{
“query”: {
“range”: {
“age”: {
“gte”: 22,
“lte”: 30
}
}
}
}
# 日期字段进行range查询

# 添加测试数据
PUT range_index
POST range_index/doc
{
“mappings”: {
“doc”: {
“date”: {
“type”: “date”
}
}
}
}
POST range_index/doc/_bulk
{“index”:{“_id”:1}}
{“name”:”zhangyue”,”date”:”1994-06-07″}
{“index”:{“_id”:2}}
{“name”:”lihang”,”date”:”1994-10-22″}
{“index”:{“_id”:3}}
{“name”:”zhaochen”,”date”:”1994-07-01″}

# 查询日期范围, 日期小于1994年7月

GET range_index/doc/_search
{
“query”: {
“range”: {
“date”: {
“lt”: “1994-07”
}
}
}
}
term查询
term查询用于精准匹配, 对查询的内容, 不进行分词处理
terms查询
与term查询一致,区别在于terms提供了一个数组, 可以允许多值匹配
组合多查询(bool)
bool支持多种条件的查询和过滤
bool支持多种参数, must(必须包含的条件), must_no(必须不包含的条件), should(满足should中的内容可以增加匹配得分),filter(必须匹配, 但是不影响匹配得分)

# bool查询中, 文档必须满足must中的全部条件,并进行相关性算分。filter会过滤不符合条件的文档, 但不进行相关性算分。

GET test_index/_search
{
“query”: {
“bool”: {
“must”: [
{
“match”: {
“name”: “lihang”
}
}
],
“filter”: {
“range”: {
“age”: {
“gt”: 20
}
}
}
}
}
}
验证查询
验证查询语句是否合法

GET zc_index/doc/_validate/query
{
“query”: {
“range”: {
“age”: {
“gt1e”: 2
}
}
}
}

// 当查询非法的时候,valid会返回false
{
“valid”: false
}
排序

desc 降序
asc 升序

// 查询job中包含web的,并不进行相关性算分, 按照age的升序排序
GET zc_index/doc/_search
{
“query”: {
“bool”: {
“filter”: {
“match”: {
“job”: “web”
}
}
}
},
“sort”: [
{
“age”: {
“order”: “asc”
}
}
]
}
多值字段(不是多字段)排序。当字段内拥有多个值的时候,可以使用mode,对这些值进行min,max,sum,avg等操作。然后,对计算后的结果进行排序

“sort”: {
“dates”: {
“order”: “asc”,
“mode”: “min”
}
}
字符串排序
有时候,我们希望对字符串进行排序(例如: 通过首字母的方式排序字符串), 但是对于text类型, elasticsearch会进行分词处理。如果需要对字符串进行排序,我们不能进行分词处理。但是如果需要全文检索,我们又需要对字符串进行分词处理。
我们可以通过fields对相同的字段,以不同的目的,设置不同的type类型

// job字段设置为text类型,进行全文检索
// job.row 设置为keyword类型, 可以进行排序,精确匹配
PUT zy_index
{
“mappings”: {
“doc”: {
“properties”: {
“job”: {
“type”: “text”,
“fields”: {
“raw”: {
“type”: “keyword”
}
}
}
}
}
}
}

// 添加一些测试数据
POST zy_index/doc/_bulk
{“index”:{“_id”:1}}
{“name”:”zhangyue”,”job”:”web node”}
{“index”:{“_id”:2}}
{“name”:”lihang”,”job”:”node java”}
{“index”:{“_id”:3}}
{“name”:”liyubo”,”job”:”web”}
{“index”:{“_id”:4}}
{“name”:”houjiaying”,”job”:”java”}

// 全文检索job含有node
// 通过job.row进行首字母排序
GET zy_index/doc/_search
{
“query”: {
“match”: {
“job”: “node”
}
},
“sort”: [
{
“job.raw”: {
“order”: “asc”
}
}
]
}
文档的相关性
_score表示文档的相关性,_score越高文档与查询的条件匹配程度越高。
_score的评分标准:

检索词频率,检索词在字段出现的频率越高,文档的相关性越高
反向文档频率,检索词在索引中出现的越高,文档的相关性越低(因为大多数文档都出现了该检索词)
字段长度准则, 检索词出现的字段越长, 相关性越低

索引

# 创建索引
PUT test_index

# 查看索引
GET test_index

# 删除索引
DELETE test_index
创建索引
通过索引一篇文档可以自动创建索引, 索引采用默认的配置。字段会通过动态映射添加类型,当然我们可以指定索引的mapping
删除索引

// 删除全部的索引
DELETE /_all
DELETE /*
动态映射 dynamic mapping
Elasticsearch会将mapping中没有定义的字段,通过dynamic mapping确定字段的数据类型,这是默认的行为。如果对没有出现的未定义字段作出其他的操作,可以通过定义mapping的dynamic配置项目

dynamic: true 会自动为新增的字段添加类型
dynamic: false 忽略新增的字段
dynamic: strict 会抛出异常

PUT hello_index
{
“mappings”: {
“doc”: {
“dynamic”: true
}
}
}
重新索引数据
在es中mapping定义后是无法修改的,如果想要修改mapping只能创建新的索引。更多内容Reindex API

POST _reindex
{
“source”: {
“index”: “zc_index”
},
“dest”: {
“index”: “zc2_index”
}
}
part2

<!–more–>
导入
使用elasticsearch-dump导入文件数据到Es中

// dump的使用方法
elasticdump \
// JSON文件路径
–input=/Users/zhangyue/Documents/swmgame-activity-2018.06/swmgame-activity-2018.06.mapping.json \
// 导入的路径
–output=http://127.0.0.1:9200/my_index_type \
–type=mapping
elasticdump \
–input=/Users/zhangyue/Documents/swmgame-activity-2018.06/swmgame-activity-2018.06.data.json \
–output=http://127.0.0.1:9200/my_index_type \
–type=data
搜索
精确值搜索
term查询数字
term查询会查找指定的精确值, 如果不想计算相关度算分, 可以使用filter可以更快的执行操作

// 检索passStatus为2的文档

GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“bool”: {
“must”: [
{
“term”: {
“passStatus”: {
“value”: 2
}
}
}
]
}
}
}

// 检索passStatus等于2并且gameId等于G09, 并且查询不计算相关度算分

GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“bool”: {
// 不计算相关度算分
“filter”: {
“bool”: {
“must”: [
{
“term”: {
“passStatus”: {
“value”: 2
}
}
},
{
“term”: {
“gameId.keyword”: {
“value”: “G09”
}
}
}
]
}
}
}
}
}
term查询文本
???? 使用term检索文本的时候, 检索的结果可能与我们预期的结果并不一致, 这是什么原因导致的呢?
???? 我们通过analyzeAPI可以看到, 文档中的text类型的字段, 已经被分词。如果使用term精确查找全文, 是不会匹配到数据的。因为这些全文并没有被存储在倒排索引中。
???? 有两种解决的办法, 解决办法1, 在es中es默认会为字段创建名为keyword的keyword类型的fields字段, 于字段一致但是类型并不一致。可以使用keyword的fields字段进行term查询。解决办法2, 创建新的索引使用新的mapping, 指定字段为keyword类型

// 解决办法1
GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“bool”: {
“must”: [
{
“term”: {
“gameId.keyword”: {
“value”: “G09”
}
}
}
]
}
}
}

// 解决办法2
DELETE test5_index
PUT test5_index
{
“mappings”: {
“doc”: {
“properties”: {
“gameId”: {
“type”: “keyword”
}
}
}
}
}
term查询范围类型

DELETE test_index
PUT test_index
{
“mappings”: {
“doc”: {
“properties”: {
// 定义age字段为范围类型
“age”: {
“type”: “integer_range”
}
}
}
}
}

// 添加测试数据
POST test_index/doc/_bulk
{“index”:{“_id”:1}}
{“age”:{“gte”:10,”lte”:20}}
{“index”:{“_id”:2}}
{“age”:{“gte”:21,”lte”:30}}

// 查询文档
GET test_index/doc/_search
{
“query”: {
“term”: {
“age”: {
“value”: 11
}
}
}
}
组合过滤器
组件过滤器的组成:

must 必须满足的一组条件
must_not 必须不满足的一组条件
should 可以满足的一组的条件, 如果满足可以增加相关性算分(如果组合过滤器中只有should, 则文档必须满足should中的一项条件)

// 嵌套的bool查询
// 检索gameId等于G09, 或者passStatus等于2并且source等于ios
GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“bool”: {
“should”: [
{
“term”: {
“gameId.keyword”: {
“value”: “G09”
}
}
},
{
“bool”: {
“must”: [
{
“term”: {
“passStatus”: {
“value”: “2”
}
}
},
{
“term”: {
“source.keyword”: {
“value”: “ios”
}
}
}
]
}
}
]
}
}
}
terms
terms查询与term查询类似,terms匹配的是一组精确值, 是一个精确值数组

// terms匹配的是一组数组
// 检索passStatus为1或者2的文档

GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“bool”: {
“filter”: {
“terms”: {
“passStatus”: [
1,2
]
}
}
}
}
}
range

gt 大于
gte 大于等于
lt 小于
lte 小于等于

数字范围查询 ????

// passStatus大于等于1并且小于2的文档

GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“bool”: {
“filter”: {
“range”: {
“passStatus”: {
“gte”: 1,
“lt”: 2
}
}
}
}
}
}
日期范围查询 ????
在使用日期范围查询的时候,需要预先将日期的字段的mapping的type类型设置为date

DELETE test_index
PUT test_index
{
“mappings”: {
“doc”: {
“properties”: {
// 设置为time类型
“time”: {
“type”: “date”
}
}
}
}
}

// 添加测试数据
POST test_index/doc/_bulk
{“index”:{“_id”:1}}
{“time”:”1994-06-07″}
{“index”:{“_id”:2}}
{“time”:”1994-10-22″}
{“index”:{“_id”:3}}
{“time”:”1993-07-01″}
{“index”:{“_id”:4}}
{“time”:”2005-01-01″}

// 查询文档的time字段的日期范围是大于1994-10-22, 小于等于2005-01-01
GET test6_index/doc/_search
{
“query”: {
“bool”: {
“filter”: {
“range”: {
“time”: {
“gt”: “1994-10-22”,
“lte”: “2005-01-01”
}
}
}
}
}
}
字符串范围查询 ????
字符串范围使用的是字典顺序(lexicographically)的排序方式。
???? 什么是字典序?
比如说有一个随机变量X包含1, 2, 3三个数值。
其字典排序就是123 132 213 231 312 321

DELETE test_index
// 添加测试数据
POST test_index/doc/_bulk
{“index”:{“_id”:1}}
{“name”:”abce fg”}
{“index”:{“_id”:2}}
{“name”:”cba twa”}
{“index”:{“_id”:3}}
{“name”:”a cb”}
{“index”:{“_id”:4}}
{“name”:”gfw wfw”}
{“index”:{“_id”:5}}
{“name”:”bgfw wfw”}

GET test_index/doc/_search
{
“query”: {
“bool”: {
“filter”: {
“range”: {
“name”: {
“gte”: “a”,
“lt”: “c”
}
}
}
}
}
}
处理Null值
存在查询
检索文档中至少包含一个非空的文档。(????全部为空或者没有该字段的除外)

// 查找game字段至少包含一个非空文档的文档
GET test_index/doc/_search
{
“query”: {
“exists”: {
“field”: “game”
}
}
}
缺失查询
查询文档中为null, 或者没有该字段的文档
???? 缺失查询已经在ElasticSearch2.2.0中废弃。可以使用以下的方法代替

GET test_index/doc/_search
{
“query”: {
“bool”: {
“must_not”: {
“exists”: {
“field”: “game”
}
}
}
}
}
全文搜索
基本概念
基于词项
如term查询不会经过分析阶段,只会在倒排索引中查找精确的词项,并用TF/DF算法为文档进行相关性评分_score。term查询只对倒排索引的词项精确匹配,而不会对查询词进行多样性处理。
基于全文
如match查询和query_string查询。对于日期和整数会将查询字符串当作整数对待。如果查询的是keyword类型的字段,会将查询字符串当作单个单词对待。如果是全文字段,会将查询字符串使用合适的分析器,作出处理,生成一个查询词项的列表,查询会对词项列表中的每一项进行查询,再将结果进行合并。
匹配查询
match查询即可以进行精确检索也可以进行全文检索,以下是match查询的具体的过程:

检查字段类型, 如果检索的字段是text类型, 那么查询字符串也应当被分析
分析查询字符串, 将查询字符串经过默认的分析器的处理, match执行的是当个底层的term查询
term查询会在倒排索引中对分析后的查询字符串进行检索
为匹配的文档评分(检索词频率, 反向文档频率, 字段长度准则)
为什么在这里测试只创建一个分片, 后面会有介绍

// 只创建一个主分片
PUT /swmgame-activity-2018.06
{ “settings”: { “number_of_shards”: 1 }}

GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“bool”: {
“filter”: {
“match”: {
“ipInfo.city”: “蚌埠”
}
}
}
}
}
多词查询
match查询如果查询的是text类型的全文字段, 那么也会对查询字符串进行分析

// match查询会分别查询蚌埠和龙子湖区两个字段
GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“bool”: {
“filter”: {
“match”: {
“ipInfo.city”: “蚌埠 龙子湖区”
}
}
}
}
}
如果希望查询的文档, 同时包含所有的关键词, 则可以使用operator使用and操作符

// 查询包含蚌埠并且包含龙子湖区两个字段
GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“bool”: {
“filter”: {
“match”: {
“ipInfo.city”: “蚌埠 龙子湖区”,
“operator”: “and”
}
}
}
}
}
最小匹配数
match查询可以设置minimum_should_match参数,即最小匹配数,如果match查询有四个词项,如果minimum_should_match设置为50%,那么最少匹配2个词项
组合查询
组合查询接受must, must_not, should。如果当DSL中只包含should的时候, should至少有一个必须匹配。同时可以指定should的minimum_should_match参数, 控制查询的精度。控制必须匹配的数量。
多词查询中, 使用or操作符号, 和使用should查询是等价的

// 两条查询是等价的
GET test_index/doc/_search
{
“query”: {
“match”: {
“title”: “fox dog”
}
}
}

GET test_index/doc/_search
{
“query”: {
“bool”: {
“should”: [
{
“term”: {
“title”: {
“value”: “fox”
}
}
},
{
“term”: {
“title”: {
“value”: “dog”
}
}
}
]
}
}
}
多词查询中, 使用and操作符, 和使用must查询是等价的

// 两条查询是等价的

GET test_index/doc/_search
{
“query”: {
“match”: {
“title”: {
“query”: “fox dog”,
“operator”: “and”
}
}
}
}
GET test_index/doc/_search
{
“query”: {
“bool”: {
“must”: [
{
“term”: {
“title”: {
“value”: “fox”
}
}
},
{
“term”: {
“title”: {
“value”: “dog”
}
}
}
]
}
}
}
权重
设置boost可以设置查询语句的权重, 大于1权重增大, 0到1之间权重逐渐降低。匹配到权重越高的查询语句, 相关性算分越高

// 安徽的查询语句的权重为3, 匹配到的文档的得分更高

GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“bool”: {
“should”: [
{
“term”: {
“passStatus”: {
“value”: 2,
“boost”: 2
}
}
},
{
“match”: {
“ipInfo.province.keyword”: {
“query”: “安徽”,
“boost”: 3
}
}
}
]
}
}
}
默认的分析器
索引时的分析器:

首先使用字段映射的分析器
其次是index默认的分析器
最后是默认为standard分析器

搜索时的分析器:

优先查找定义的分析器
其次是字段映射的分析器
最后是索引默认的default的分析器, 默认为standard分析器

相关度被破坏
Q: 为什么在之前的测试索引时,需要指定只为这个索引创建一个主分片?
A: 为了避免相关度被破坏。在elasticsearch中计算相关度使用TF/IDF算法,词频/逆向文档词频的算法。如果有5个包含”fox”的文档位于分片1,一个包含“fox”的文档位于分片2。就会导致一个问题, fox在分片1的相关度会降低, 而在分片2的相关度就会非常高。但是在实际的场景中这并不是一个问题,因为在真实的环境中,数据量通常是非常大的,分片之间的差异会被迅速均化,以上的问题只是因为数据量太少了。
最佳字段
什么是最佳字段,我们需要首先了解什么是竞争关系。
下面是两条文档, 假设我们需要搜索”Brown fox”两个关键词并且需要同时检索”title”和”body”两个字段的时候。文档2的body字段虽然同时匹配了两个关键词, 但是文档2的title没有匹配到任何的关键词。所以相关性算分, 文档2是低于文档1的。
但是如果取最佳字段的评分,文档2的body字段为最佳字段, 文档2的评分是高于文档1的评分的

{
“title”: “Quick brown rabbits”,
“body”: “Brown rabbits are commonly seen.”
}
{
“title”: “Keeping pets healthy”,
“body”: “My quick brown fox eats rabbits on a regular basis.”
}
dis_max

// 在最后计算文档的相关性算分的时候, 只会取queries中的相关性的最大值

GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“dis_max”: {
“queries”: [
{
“match”: {
“FIELD1”: “TEXT1”
}
},
{
“match”: {
“FIELD2”: “TEXT2”
}
}
]
}
}
}
tie_breaker
使用dis_max最佳字段可能存在另外的问题就是。如果同时查询多个字段, 如果一个文档同时匹配了多个字段,但是由于文档的相关性算分取的是最佳字段, 可能导致该文档的相关性算分并不是最高的。
使用tie_breaker参数,可以将其他匹配语句的评分也计算在内。将其他匹配语句的评分结果与tie_breaker相乘, 最后与最佳字段的评分求和得出文档的算分。

GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“dis_max”: {
“tie_breaker”: 0.3,
“queries”: [
{
“match”: {
“FIELD1”: “TEXT1”
}
},
{
“match”: {
“FIELD2”: “TEXT2”
}
}
]
}
}
}
multi_match
多字段的match查询, 为多个字段执行相同的match查询。multi_match查询默认取最佳字段的相关性算分

// 下面两种查询是等同的
GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“dis_max”: {
“queries”: [
{
“match”: {
“FIELD1”: “TEXT1”
}
},
{
“match”: {
“FIELD2”: “TEXT1”
}
}
]
}
}
}

GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“multi_match”: {
“query”: “TEXT1”,
“type”: “best_fields”, // 取最佳字段的相关性算分
“fields”: [
“FIELD1”,
“FIELD2”,
“FIELD3^2” // 可以指定的查询字段的权重, 如果匹配FIELD3字段得分将会更高
]
}
}
}
fields
fields是对同一个字段索引多次, 每一个字段不同的fields可以定义不同的type以及分析器,用做不同的用途

// title为text类型
// title.keyword为keyword类型
// title.english使用english的分析器

PUT test3_index
{
“mappings”: {
“doc”: {
“properties”: {
“title”: {
“type”: “text”,
“fields”: {
“keyword”: {
“type”: “keyword”
},
“english”: {
“type”: “text”,
“analyzer”: “english”
}
}
}
}
}
}
}
跨字段实体搜索
比如一个人的信息,包含姓名,电话号码,家庭住址等多个字段。如果想要搜索人的信息,可能需要检索多个字段。
// 姓名, 手机号, 家庭住址字段都包含了一个人的信息
{
“name”: “Frank”,
“mobi”: “13053127868”,
“hours”: “bengbu”
}
最直接的检索的方式是通过multi_match或者bool的should实现对多个字段的检索

GET test_index/doc/_search
{
“query”: {
“bool”: {
“should”: [
{
“match”: {
“name”: “Frank 1305312786”
}
},
{
“mathch”: {
“mobi”: “Frank 13053127868”
}
},
{
“mathch”: {
“hours”: “Frank 13053127868”
}
}
]
}
}
}

{
“query”: {
“multi_match”: {
“query”: “Frank 1305312786”,
“type”: “most_fields”, // 合并匹配字段的评分, 不使用最佳字段的评分
“fields”: [ “name”, “mobi”, “hours” ]
}
}
}
跨字段检索的问题

在同一个字段匹配到多个关键词的相关性算分,要小于多个字段匹配同一个关键词的算分。
使用and操作符, 会导致所有查询变为所有关键词都必须要在同一个字段匹配。
逆向文档频率的问题, 当一个查询具有较低的逆向文档频率(相关度较高)。可能会削弱较高的逆向文档频率(相关度较低)的作用。

_all
使用copy_to的功能,将多个字段内容拷贝到文档的一个字段中。检索时使用合并的字段进行检索。

PUT test3_index
{
“mappings”: {
“doc”: {
“properties”: {
“name”: {
“type”: “text”,
“copy_to”: “info”
},
“mobi”: {
“type”: “text”,
“copy_to”: “info”
},
“hours”: {
“type”: “text”,
“copy_to”: “info”
},
“info”: {
“type”: “text”
}
}
}
}
}

// 查询时可以直接通过info字段查询
GET test3_index/doc/_search
{
“query”: {
“match”: {
“info”: “Frank 1305312786”
}
}
}
cross-fields
当multi_match的type等于cross-fields时, 它将所有fields中的字段当成一个大字段,并在这个大字段中进行检索。
同时也会解决逆向文档频率的问题, 因为cross-fields会取不同字段中最高的逆向文档频率(相关度最低的)的值。
cross-fields时,所有字段必须为同一种分析器。如果包括了不同分析器的字段,它们会以best_fields的相同方式被加入到查询结果中

// abc efg必须同时出现在FIELD1或者FIELD2文档中
GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“multi_match”: {
“query”: “abc efg”,
“fields”: [“FIELD1”, “FIELD2”],
“type”: “most_fields”,
“operator”: “and”
}
}
}

// abc efg必须出现但是可以在FIELD1或者FIELD2不同的字段中
GET swmgame-activity-2018.06/my_index/_search
{
“query”: {
“multi_match”: {
“query”: “abc efg”,
“fields”: [“FIELD1^2”, “FIELD2”], // 可以提高字段的权重
“type”: “cross_fields”,
“operator”: “and”
}
}
}
part3

<!–more–>
聚合
基本概念

桶指的是满足特定条件的文档的集合, (比如李航属于陕西桶), 聚合开始执行, 符合条件的文档会放入对应的桶。
指标
对桶内的文档进行统计计算, 例如:最小值, 平均值, 汇总等
指标与桶
桶是可以被嵌套的, 可以实现非常复杂的组合。
国家桶 -> 性别桶 -> 年龄段桶 -> 不同国家不同性别不同年龄段的平均工资
初步聚合
简单的聚合

// 对每一个省份的数据进行聚合
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“province_info”: {
“terms”: {
“field”: “ipInfo.province.keyword”,
“size”: 10
}
}
}
}
简单的指标

// 聚合每一个省份的文档, 并对每一个省份的得分求平均值
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“province_info”: {
“terms”: {
“field”: “ipInfo.province.keyword”,
“size”: 100
},
“aggs”: {
“avg_score”: {
“avg”: {
“field”: “score”
}
}
}
}
}
}
嵌套桶
对聚合的结果进一步聚合。每一层的聚合都可以添加单独的指标, 每一层聚合的指标之间相互独立。

// 首先对每一个国家进行聚合, 并计算每一个国家的平均得分
// 其次对每一个省份进行聚合, 并计算每一个省份的平均得分
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“country_info”: {
“terms”: {
“field”: “ipInfo.country.keyword”,
“size”: 10
},
“aggs”: {
“avg_score”: {
“avg”: {
“field”: “score”
}
},
“province_info”: {
“terms”: {
“field”: “ipInfo.province.keyword”,
“size”: 100
},
“aggs”: {
“avg_score”: {
“avg”: {
“field”: “score”
}
}
}
}
}
}
}
}
直方图
什么是直方图
直方图就是柱状图, 创建直方图需要指定一个区间, elasticsearch可以对每一个区间进行聚合操作

// 根据durationCallAll字段, 从最小值开始, 每10000为1个区间进行聚合
GET crm_statistics-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“day_duration_call_all”: {
“histogram”: {
“field”: “durationCallAll”,
“interval”: 10000,
“min_doc_count”: 0
}
}
}
}

// 返回的部分结果
// ……
{
“key”: 20000,
“doc_count”: 3
},
{
“key”: 30000,
“doc_count”: 3
},
{
“key”: 40000,
“doc_count”: 9
}
// ……
按时间统计
根据时间统计, 可以根据时间类型的字段进行聚合, 区间可以是每一日, 每一周, 每一月, 每一季度等等

GET crm_statistics-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“at”: {
“date_histogram”: {
“field”: “at”, // 根据时间类型的字段at进行聚合
“interval”: “day”, // 区间是每一天
“min_doc_count”: 0, // 可以强制返回空的桶
“extended_bounds”: { // 时间区间
“min”: “2018-05-30”,
“max”: “2018-06-22”
}
}
}
}
}
返回空的桶

min_doc_count, 可以强制返回长度为空的桶
extended_boundss, 可以设置返回的时间区间(因为elasticsearch默认只返回最小值到最大值之间的桶)

扩展例子
???? 按时间统计的直方图上进行聚合操作, 并计算度量指标的例子。
下面的DSL, 按时间进行统计直方图, 以每一天作为区间, 并且计算区间内, 每一个省份的平均分数, 以及每一个省份下每一个城市的平均得分
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“at_date_histogram”: {
“date_histogram”: {
“field”: “at”,
“interval”: “day”,
“min_doc_count”: 0,
“extended_bounds”: {
“min”: “2018-05-01”,
“max”: “2018-06-22”
}
},
“aggs”: {
“province_info”: {
“terms”: {
“field”: “ipInfo.province.keyword”,
“size”: 50
},
“aggs”: {
“avg_score”: {
“avg”: {
“field”: “score”
}
},
“city_info”: {
“terms”: {
“field”: “ipInfo.city.keyword”,
“size”: 100
},
“aggs”: {
“avg_score”: {
“avg”: {
“field”: “score”
}
}
}
}
}
}
}
}
}
}
限定范围聚合
没有指定query的情况下, 聚合操作针对的是整个索引

// 限定安徽和福建两个省份进行聚合操作
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“query”: {
“bool”: {
“should”: [
{
“term”: {
“ipInfo.province.keyword”: {
“value”: “安徽”
}
}
},
{
“term”: {
“ipInfo.province.keyword”: {
“value”: “福建”
}
}
}
]
}
},
“aggs”: {
“city_info”: {
“terms”: {
“field”: “ipInfo.city.keyword”,
“size”: 100
},
“aggs”: {
“avg_socre”: {
“avg”: {
“field”: “score”
}
}
}
}
}
}
全局桶
使用全局桶(global)可以在查询范围内聚合, 也可以全局文档上聚合

GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“query”: {
“bool”: {
“filter”: {
“term”: {
“ipInfo.province.keyword”: “安徽”
}
}
}
},
“aggs”: {
// 查询限定的范围内聚合
“city_info”: {
“terms”: {
“field”: “ipInfo.city.keyword”,
“size”: 100
}
},
“all”: {
“global”: {},
// 在全局范围内聚合
“aggs”: {
“city”: {
“terms”: {
“field”: “ipInfo.city.keyword”,
“size”: 1000
},
“aggs”: {
“all_avg_score”: {
“avg”: {
“field”: “score”
}
}
}
}
}
}
}
}
过滤和聚合
过滤
参考限定范围的聚合 ????️ ✈️
过滤桶
对聚合的结果进行过滤
为什么使用过滤桶?
我们可能遇到这种情况, 我们想把查询条件a查询到数据显示到前端页面上, 但同时又想把查询条件a+b的聚合结果显示到页面上。所以在过滤的时候,我们并不能直接使用过滤条件a+b。而聚合桶就可以对聚合的结果进行过滤

// 查询显示的结果的过滤条件是 “安徽”
// 聚合显示的结果的过滤条件是 “安徽” + “蚌埠”
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 20,
“query”: {
“bool”: {
“filter”: {
“term”: {
“ipInfo.province.keyword”: “安徽”
}
}
}
},
“aggs”: {
“city_info”: {
“filter”: {
“term”: {
“ipInfo.city.keyword”: “阜阳”
}
},
“aggs”: {
“city_info”: {
“terms”: {
“field”: “ipInfo.city.keyword”,
“size”: 20
}
}
}
}
}
}
后过滤器
对查询的结果进行过滤
为什么需要后过滤器?
我们可能遇到这种情况, 我们想在查询a条件的情况下对结果作出聚合, 但是又想在查询a+b条件下下显示结果。这种情况下可以使用后过滤器, 对查询的结果进行过滤。

// 查询的条件是 福建 + 厦门
// 聚合的过滤条件是厦门
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 5,
“query”: {
“bool”: {
“filter”: {
“term”: {
“ipInfo.province.keyword”: “福建”
}
}
}
},
“post_filter”: {
“term”: {
“ipInfo.city.keyword”: “厦门”
}
},
“aggs”: {
“city_info”: {
“terms”: {
“field”: “ipInfo.city.keyword”,
“size”: 20
}
}
}
}
聚合排序
内置排序

_count 按照文档的数量排序
_term 按词项的字符串值的字母顺序排序
_key 按每个桶的键值数值排序。只在histogram和date_histogram内使用
desc 降序
asc 升序

// 文档的内容升序进行排序
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“province”: {
“terms”: {
“field”: “ipInfo.province.keyword”,
“size”: 50,
“order”: {
“_count”: “asc”
}
}
}
}
}

// 按照字符串的顺序进行排序, 只能用在term
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“game_id_info”: {
“terms”: {
“field”: “gameId.keyword”,
“size”: 50,
“order”: {
“_term”: “asc”
}
}
}
}
}

// 按照date_histogram或者histogram的key排序
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“date”: {
“date_histogram”: {
“field”: “at”,
“interval”: “day”,
“min_doc_count”: 0,
// 时间区间按照降序排序
“order”: {
“_key”: “desc”
}
}
}
}
}
度量排序
直接使用度量的key作为排序的字段
单度量值排序

GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“province_info”: {
“terms”: {
“field”: “ipInfo.province.keyword”,
“size”: 50,
“order”: {
“avg_score”: “asc”
}
},
“aggs”: {
“avg_score”: {
“avg”: {
“field”: “score”
}
}
}
}
}
}
多度量值排序
使用点操作符号, 选择单个度量值进行排序

GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“province_info”: {
“terms”: {
“field”: “ipInfo.province.keyword”,
“size”: 50,
“order”: {
“info.avg”: “asc”
}
},
“aggs”: {
“info”: {
“extended_stats”: {
“field”: “score”
}
}
}
}
}
}
近似聚合
对于一些复杂的操作,需要在精准性和实时性上作出权衡
近似聚合 —— 去重
cardinality可以实现去重操作, 但是数据量巨大的情况下精确性上可能存在误差, 但是可以设置更大的内存提供去重的精确性

// 查看有多少个城市
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“city_count”: {
“cardinality”: {
“field”: “ipInfo.city.keyword”
}
}
}
}

// 统计每一个省份的城市数量
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“country_info”: {
“terms”: {
“field”: “ipInfo.country.keyword”,
“size”: 10
},
“aggs”: {
“province_info”: {
“terms”: {
“field”: “ipInfo.province.keyword”,
“size”: 50
},
“aggs”: {
“city”: {
“terms”: {
“field”: “ipInfo.city.keyword”,
“size”: 50
}
},
“city_count”: {
“cardinality”: {
“field”: “ipInfo.city.keyword”
}
}
}
}
}
}
}
}
precision_threshold
cardinality精确性与内存的使用量有关,通过配置precision_threshold参数,设置去重需要的固定内存使用量。内存使用量只与你配置的精确度相关。
precision_threshold 设置为100的时候,去重的需要的内存是 100 * 8 的字节。precision_threshold 接受的范围在0–40,000之间

// 统计每一个国家的数量
GET swmgame-activity-2018.06/my_index/_search
{
“size”: 0,
“aggs”: {
“country_count”: {
“cardinality”: {
“field”: “ipInfo.country.keyword”
}
}
}
}
近似聚合 —— 百分位
什么是百分位
以下是百度百科的内容
统计学术语,如果将一组数据从小到大排序,并计算相应的累计百分位,则某一百分位所对应数据的值就称为这一百分位的百分位数。可表示为:一组n个观测值按数值大小排列。如,处于p%位置的值称第p百分位数。
百分位通常用第几百分位来表示,如第五百分位,它表示在所有测量数据中,测量值的累计频次达5%。以身高为例,身高分布的第五百分位表示有5%的人的身高小于此测量值,95%的身高大于此测量值。
高等院校的入学考试成绩经常以百分位数的形式报告。比如,假设某个考生在入学考试中的语文部分的原始分数为54分。相对于参加同一考试的其他学生来说,他的成绩如何并不容易知道。但是如果原始分数54分恰好对应的是第70百分位数,我们就能知道大约70%的学生的考分比他低,而约30%的学生考分比他高。
百分位计算

// 添加测试数据, 网络延迟数据
PUT test9_index
POST /test9_index/doc/_bulk
{ “index”: {}}
{ “latency” : 100, “zone” : “US”, “timestamp” : “2014-10-28” }
{ “index”: {}}
{ “latency” : 80, “zone” : “US”, “timestamp” : “2014-10-29” }
{ “index”: {}}
{ “latency” : 99, “zone” : “US”, “timestamp” : “2014-10-29” }
{ “index”: {}}
{ “latency” : 102, “zone” : “US”, “timestamp” : “2014-10-28” }
{ “index”: {}}
{ “latency” : 75, “zone” : “US”, “timestamp” : “2014-10-28” }
{ “index”: {}}
{ “latency” : 82, “zone” : “US”, “timestamp” : “2014-10-29” }
{ “index”: {}}
{ “latency” : 100, “zone” : “EU”, “timestamp” : “2014-10-28” }
{ “index”: {}}
{ “latency” : 280, “zone” : “EU”, “timestamp” : “2014-10-29” }
{ “index”: {}}
{ “latency” : 155, “zone” : “EU”, “timestamp” : “2014-10-29” }
{ “index”: {}}
{ “latency” : 623, “zone” : “EU”, “timestamp” : “2014-10-28” }
{ “index”: {}}
{ “latency” : 380, “zone” : “EU”, “timestamp” : “2014-10-28” }
{ “index”: {}}
{ “latency” : 319, “zone” : “EU”, “timestamp” : “2014-10-29” }
计算网络延迟的百分位和网络延迟的平均数

GET test9_index/doc/_search
{
“size”: 0,
“aggs”: {
// 计算网络延迟的平均数
“avg_ping”: {
“avg”: {
“field”: “latency”
}
},
// 计算网络延迟的百分位
“percentiles_ping”: {
“percentiles”: {
“field”: “latency”
}
}
}
}
下面是返回的聚合结果,可以看到平均数有时并不能体现异常的数据。约有25%的用户的网络延迟是大于289的
“aggregations”: {
“avg_ping”: {
“value”: 199.58333333333334
},
“percentiles_ping”: {
“values”: {
“1.0”: 75.55,
“5.0”: 77.75,
“25.0”: 94.75,
“50.0”: 101,
“75.0”: 289.75,
“95.0”: 489.34999999999985,
“99.0”: 596.2700000000002
}
}
}
查看网络的延迟是否和地区有关,在聚合的基础上进行百分位计算。根据结果可以得知, 欧洲用户(EU)的网络延迟更高

GET test9_index/doc/_search
{
“size”: 0,
“aggs”: {
“zone_info”: {
“terms”: {
“field”: “zone.keyword”,
“size”: 10
},
“aggs”: {
“zone_ping”: {
“percentiles”: {
“field”: “latency”
}
}
}
}
}
}
百分位等级
得知具体的数值所占的百分位。以下是查看ping为75, 623的用户所占的百分位。

GET test9_index/doc/_search
{
“size”: 0,
“aggs”: {
“ping”: {
“percentile_ranks”: {
“field”: “latency”,
“values”: [
75,
623
]
}
}
}
}
可以看到如下的结果, ping小于等于75的用户占到了4.16%, 有22.5%的用户ping是大于623的

“aggregations”: {
“ping”: {
“values”: {
“75.0”: 4.166666666666666,
“623.0”: 87.5
}
}
}
Elasticsearch会暂停更新, 未来有时间了还会继续更新, 目前为止我个人工作所需的知识已经足够了….

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理