Elasticsearch原理概念及各种查询语句

es的官方中文文档
https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
概念
es是基于Lucene,纯java语言编写的分布式,可扩展,近实时性的高性能搜索引擎和数据分析引擎

es基础构成

  • doc
    es中数据存储的最小单元,对应数据库的一行数据
  • Index
    有具有相同字段的文档列表组成,对应数据库的一个表,一个索引由一个或者多个分片组成
  • type
    文档类型,这个我们可以不用记,es后面的版本要把type去掉。之前的版本中,索引和文档中间还有个类型的概念,每个索引下可以建立多个类型,文档存储时需要指定index和type。从6.0.0开始单个索引中只能有一个类型,7.0.0以后将将不建议使用,8.0.0 以后完全不支持。在7.0开始,一个索引只能建一个Type为_doc。
  • shards
    分片。当索引数据太大时,受限于单个节点的磁盘,内存,处理能力等资源,需要将索引的数据水平拆分,拆分后形成的每一个分片回落到不一样的服务节点上,这样显著提升了es的性能,索引创建时需要指定分片,一旦分片被指定就无法更改
  • replicas
    副本。是主分片的备份分片,副本主要是用于主分片的数据备份,同时也对外提供数据查询服务。副本分片提升了es的高可用性
分片shard和es集群的高可用高性能

分片的概念和kafka的分区很像,既有副本又各自拥有不同的数据并且分散在不同的节点,index就是这些分片的topic。

一个索引中的数据保存通过hash取余决定保存在哪分片中,相当于水平分表也类似于kafka的分区,分片有主分片和副本分片,一个主分片可以设置多个副本分片,在es集群中每个主分片存储了es的部分数据,副本分片主要是用于备份主分片的数据,主分片分布在es的各个节点上,而各个主分片的副本分片也会分布到和主分片不同的节点上,当集群中某个节点宕机时,分布在其他节点的副本分片就会顶替原来的主分片,这个体现了es的高可用性。

由于分片分散在各个不同的节点上,每个节点都有能力处理任意请求, 每个节点都知道集群中任一文档位置,所以可以直接将请求转发到需要的节点上,所以其请求压力和数据分析压力也会分散到集群的各个节点上,实现了es的高性能。我们最好通过轮询的方式访问集群的节点

分片的原理就和数据库的水平分表和kafka的分区是一个道理的,既能保证高新南

下图的流程展示es集群的高可用

图一:es集群中有三个节点,三个主分片,三个副本分片,也就是每个分片拥有一个副本分片

图一

图二:主节点宕机,node2通过选举称为新主节点

图二

图三:挂掉的node1的副本分片存储在node3上,集群将副本分片P0调整为主分片,这样node1的数据就恢复回来了

图三

图四:es集群将为创建P0的副本分片,和重新创建和node1一起挂掉的R1副本分片,并让它们保存在和自己主分片不一样的节点上,也就是P0副本分片保存在node2上,R1副本分片保存在node3上,下次就算是在宕机,其中的一个节点存在有其他备份分片,保证了数据的不丢失,这就是es的高可用性

图四

数据被存储到哪个分片是由公式决定的:
shard = hash(routing) % number_of_primary_shards
routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值

分片的实时性和查询性能
image.png

refresh

当我们向ES发送请求的时候,es貌似可以在我们发请求的同时进行搜索。而这个实时建索引被搜索的过程实际上是一次es 索引提交(commit)的过程,如果这个提交的过程直接将数据写入磁盘(fsync)必然会影响性能,所以es中设计了一种机制,即:先将jvm中的文档解析完写到文件缓存系统之中形成段,这样避免了比较损耗性能io操作,又可以使段可以被搜索。以上从jvm中取数据到文件缓存系统中的过程叫做refresh。

refresh:在 Elasticsearch 中,写入和打开一个新段的轻量的过程叫做 refresh,也就是数据在jvm内存写入文件系统缓存中并形成段的过程。 在Elasticsearch的jvm内和磁盘之间是文件系统缓存,写入的数据会先落入jvm内存中,在jvm内存中的数据是没有进行分段的无法提供搜索,当内存的数据到达一定量或者时间就进行一次refresh,然后缓存数据到文件系统缓存中形成段,在文件系统缓存中形成段之后Lucene才能搜索得到,然后将jvm内存清理,此时数据才可以提供搜索。es默认每秒中执行一次refresh

默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是 近 实时搜索: 文档的变化并不是立即对搜索可见,但会在一秒之内变为可见可搜索。

flush

如果数据在文件系统缓存之中是很有可能在意外的故障中丢失。这个时候就需要一种机制,可以将对es的操作记录下来,来确保当出现故障的时候,保留在文件系统缓存的数据不会丢失,并在重启的时候可以从这个记录中将数据恢复过来。elasticsearch提供了translog来记录这些操作。就是和数据库wal思想很像(日志先行)

当向elasticsearch发送创建文档请求的时候,数据会先进入到jvm之后,与此同时会将操作记录在translog之中,当发生refresh时translog中的操作记录并不会被清除,而当数据从文件缓存系统中被写入磁盘之后才会将translog中清空。而从文件缓存系统写入磁盘的过程就是flush。

flush:这种缓存的机制给es带来了性能上的提升,但是也带来了丢失数据的风险,所以es添加了事务日志,事务日志主要记录还未持久化到硬盘的数据,当日志文件大小达到一定量时(默认512MB),或者超过固定时间(默认5秒)会检查一次日志是否到达限制,默认每30分钟强制flush一次,将jvm内存和文件系统缓存的数据持久化,然后删除日志文件,并创建新的日志文件。

fsync

fsync:每个新段在文件系统缓存被持久化到磁盘的过程叫做fsync

有时候我们创建了一个文档然后尝试搜索它,但却没有搜到。这个问题的解决办法是用 refresh API 执行一次手动刷新:

POST /_refresh  //刷新所有的索引
POST /index_name/_refresh //只刷新(Refresh) 特定索引

es写性能优化

降低刷新频率(会影响实时性)
    1. 提高写性能,我们可以启动多线程去进行写操作
    1. 除了启动多线程外还可以通过调整刷新频率来提升性能。

虽然刷新(refresh)是比提交轻量很多的操作,但它还是会有性能开销,并不是所有的情况都需要每秒刷新。如果你想优化读写速度而不是近实时搜索,可以通过设置refresh_interval, 降低每个索引的刷新频率:

PUT /my_logs
{
    "settings": {
        "refresh_interval": "30s"  //每30秒刷新 my_logs 索引,默认是每秒刷新
    }
}

refresh_interval 是可以进行动态更新的,就是说在生产环境中,当你正在建立一个大的新索引时,可以先关闭自动刷新,待开始使用该索引时,再把它们调回来:

PUT /my_logs/_settings
{ "refresh_interval": -1 } //关闭实时更新

PUT /my_logs/_settings
{ "refresh_interval": "1s" }//开启每秒更新

refresh_interval 需要一个 持续时间 值, 例如 1s (1 秒) 或 2m (2 分钟)。 一个绝对值 1 表示的是 1毫秒 (会使你的集群陷入瘫痪)。

    1. 修改内存缓存大小(indices.memory.index_buffer_size)。

jvm内存缓存的数据满了或者是超过固定时间就会进行刷新操作,调整内存缓存大小可以有效的降低刷新频率
在elasticsearch.yml中可以这样设置:

indices.memory.index_buffer_size: 20%(默认是堆内存的10%)
indices.memory.min_index_buffer_size: 96mb(默认是48mb)

已经索引好的文档会先存放在内存缓存中,等待被写到到段(segment)中。缓存满的时候会触发段刷盘(吃i/o和cpu的操作)。默认最小缓存大小为48m,不太够,最大为堆内存的10%。对于大量写入的场景也显得有点小。

    1. 修改事务日志(translog)的刷新频率(fsync)(index.translog.sync_interval)和大小(index.translog.flush_threshold_size)

日志中记录了还在缓存中并未形成段的数据,会定时或者超过一定量后进行刷新
在elasticsearch.yml中可以这样设置:

index.translog.sync_interval:30s(默认5s)。
index.translog.flush_threshold_size:700mb(默认512mb)
index.translog.durability:async(默认request) //通过异步提交日志,不过可以会在宕机时丢失数据
    1. _id字段的使用,应尽可能避免自定义_id, 以避免针对ID的版本管理;建议使用ES的默认ID生成策略或使用数字类型ID做为主键。

es读性能优化

  • 1.合理的分片的数量,分片数量越多每个分片的数据范围就越小,合理的分片数量能有效的提升每个分片的查询性能

  • 2. 遵循通用的原则, 4~32G的内存给ES即可,其余留给lucene。内存对于 Elasticsearch 来说绝对是重要的,它可以被许多内存数据结构使用来提供更快的操作。但是另外一个内存消耗大户 非堆内存 (off-heap)的Lucene是用于索引的关键

  • 关闭交换分区,防止内存发生交换导致性能下降 通过执行swapoff -a或者通过: 在elasticsearch.yml 中 bootstrap.memory_lock: true, 以保持JVM锁定内存,保证ES的性能。

es的锁机制

由于es需要处理一定的并发量的写操作,es是使用的乐观锁,主要是使用java的CAS技术实现乐观锁

正排索引

就是利用文档id查询文档内容,也就是通过key去查value

倒排索引

就是通过value去查key,关于倒排索引这里有一篇不错的文章可以供大家参考https://blog.csdn.net/qq_21312297/article/details/102496833

es索引的过程

es是先通过term Dictionary将每个单词出现在文档的位置地址这个过程是倒排索引,然后通过地址去查询文档,这个是正排索引,es就是倒排索引和正排索引的结合

term Dictionary(单词字典):记录了所有文档的单词,es储存的文档内容越大词典也就越大,还记录了单词是放在哪些文档上的关联信息,通常term Dictionary会被拆分成单词的前缀组成一颗B+树,每个叶子节点的单词会记录着单词所在文档的位置地址

Posting List:记录了单词对应文档的集合,由Posting组成,而Posting中包含了文档id,单词出现频率,文档中单词的位置,单词在文档开始和结束的位置

以下是倒排索引的过程
文档字段类型
核心类型 字符串类型 string,text,keyword
整数类型 integer,long,short,byte
浮点类型 double,float,half_float,scaled_float
逻辑类型 boolean
日期类型 date
范围类型 range
二进制类型 binary
复合类型 数组类型 array
对象类型 object
嵌套类型 nested
地理类型 地理坐标类型 geo_point
地理地图 geo_shape
特殊类型 IP类型 ip
范围类型 completion
令牌计数类型 token_count
附件类型 attachment
抽取类型 percolator

基础语句

以下省略 http://localhost:9200

index操作

创建index:

put  /index_name
{
   "settings" : {
      "number_of_shards" : 3,
      "number_of_replicas" : 1
   }
}

查看index:

get  /_cat/indices

删除index:

delete /index_name
document操作

创建id为2的文档:

DELETE /index_name/doc/2

创建id为1的文档:

put /index_name/_doc/1
{
"name":"es",
"user":"test"
}

创建自带id的文档:

post /index_name/_doc/
{
"name":"es",
"user":"test"
}

_routing:
如果在创建mapping时设置了_routing为true,那么创建文档的时候必须带上routing,否则出错:

post /index_name/_doc?routing=xxxxx
{
"name":"es",
"user":"test"
}

post /index_name/_doc/1?routing=xxxxx
{
"name":"es",
"user":"test"
}

批量创建文档:

put /u/_bulk
{"index":{"_id":3}}
{"username":"james","code":23,"age":32,"country":"usa","job":"basketball"}
{"index":{"_id":4}}
{"username":"haden","code":15,"age":30,"country":"usa","job":"basketball"}
{"index":{"_id":5}}
{"username":"bingbing","code":999,"age":35,"country":"chn","job":"act"}
{"index":{"_id":6}}
{"username":"susu","code":999,"age":25,"country":"chn","job":"great"}
{"index":{"_id":7}}
{"username":"hu","code":999,"age":36,"country":"chn","job":"act"}

批量修改文档:

POST _bulk
{"update":{"_index":"test","_type":"product","_id":1}}
{"doc":{ "price" : 5200, "productName" : "苹果11","memory":"128G" }}
{"update":{"_index":"test","_type":"product","_id": 2 }}
{"doc":{ "price" : 3100, "productName" : "小米10","memory":"268G" }}
{"update":{"_index":"test","_type":"product", "_id": 3 }}
{"doc":{ "price" : 1300, "productName" : "酷派大神","memory":"16G" }}
{"update":{"_index":"test","_type":"product", "_id": 4 }}
{"doc":{ "price" : 730, "productName" : "魅蓝note3","memory":"32G" }}
{"update":{"_index":"test","_type":"product", "_id": 6 }}
{"doc":{ "price" : 10000, "productName" : "macBook Pro","memory":"521G" }}
{"update":{"_index":"test","_type":"product", "_id": 7 }}
{"doc":{ "price" : 6500, "productName" : "华为P40","memory":"128G" }}
{"update":{"_index":"test","_type":"product","_id": 8 }}
{"doc":{ "price" : 3100, "productName" : "Ipad Air3","memory":"64G" }}

批量查询:

post /_mget
{
    "docs": [
        {
            "_index": "test_index",
            "_type": "doc",
            "_id": "1"
        },
        {
            "_index": "test_index",
            "_type": "doc",
            "_id": "Ai9cM3IBEyMN0HxifBpI"
        }
    ]

修改文档:

POST /u/_doc/5/_update
{
   "doc":{
    "age":41,
    "username":"kate"
   }
}

根据查询的结果更改文档字段:

POST /u/_doc/_update_by_query
{
    "script":{
    "source":"ctx._source['brith']='1990-11-11 12:00:00'"
    },
   "query":{
    "match_all":{
    }
   }
}

新增文档字段:

PUT /u/_mapping
{
   "properties":{
    "brith":{
        "type":"date",
        "format": "yyyy-MM-dd HH:mm:ss"
    }
   }
}
分词器

分词就是将文本转化为一系列单词的过程,也叫做文本分析,在es中称为Analysis,es默认的Analysis是standard
Analysis由三部分组成:
Character Filters:对原始文本进行处理,去掉一些特殊的符号标签,例如去除html的特殊标记符
Tokenizer:将原始文本按照一定的规则切分成单词
Toker Filters:对Tokenizer处理的单词进一步加工,例如大小写转换,删除没有意义的词等

分词器选择并测试:

post /_analyze
{
   "analyzer":"simple",//选择simple分词器
   "text":"elasticsearch是世界最好的搜索引擎"
    
}

es内置分词器:
Standard - 默认分词器,按词切分,小写处理
Simple - 按照非字母切分(符号被过滤), 小写处理
Stop - 小写处理,停用词过滤(the,a,is)
Whitespace - 按照空格切分,不转小写
Keyword - 不分词,直接将输入当作输出
Patter - 正则表达式,默认\W+(非字符分割)
Language - 提供了30多种常见语言的分词器
Customer 自定义分词器

中文分词器:
IK - 支持中英文单词分词,支持ik_smart,ik_maxword的模式,支持自定义词库、支持热更新单词词典
jieba - python最流行的分词器,支持繁体分词,自定义词典等

Mapping

Mapping类似数据库表数据类型定义,Mapping可以定义index下的字段名,字段类型。mapping创建后不支持修改和删除字段,只支持添加新字段

动态mapping

在mapping中有dynamic属性,默认是true,代表着动态mapping,在动态mapping下我们插入的文档,es会为我们自动识别文档中的字段类型,然后为我们创建相应的字段类型,下面是es自动识别后为我们创建的字段类型

动态mapping可以降低用户的使用es的成本

静态mapping

当我们创建mapping时并指定dynamic属性为false,代表着静态mapping,在静态mapping下如果我们插入了mapping中没有定义的字段就会自动的进行忽略,忽略的意思就是插入没有定义的字段可以正常插入,但是搜索的时候会把字段给忽略了,查出来的结果不会包含mapping中不存在的字段并且这些字段也不支持索引

strict mapping

当我们把mapping设置为strict时,如果我们插入了mapping中没有定义的字段就会直接报错

index设置

mapping字段中的index字段代表着是否可以用来做搜索,默认是true

null_values

mapping字段中的null_values字段代表着字段遇到null时做怎么样的处理,es默认字段遇到null时会自动忽略

doc_values

字段的 doc_values 属性有两个值, true、false。默认为 true ,即开启。
当 doc_values 为 fasle 时,无法基于该字段排序、聚合、在脚本中访问字段值。
当 doc_values 为 true 时,ES 会增加一个相应的正排索引,这增加的磁盘占用,也会导致索引数据速度慢一些。

查看mapping

GET /index_name/_mapping

创建索引同时定义mapping

PUT /index_name
{
  "settings": {
    "number_of_shards": 4,
    "number_of_replicas": 1
  },
  "mappings": {
      "dynamic": "false",//定义mapping是否允许动态生成,默认是true,还有一个strict,strict下插入没有定义的字段会直接报错
      "_routing": {
        "required": true  
      },
      "properties": {
        "account": {
          "type": "keyword",
          "null_values":"暂无"  //遇到null时显示为暂无,es默认遇到null会自动忽略
        },
        "firstname": {
          "type": "keyword"
        },
        "nikename": {
          "type": "keyword"
        },
        "create_time":{
        "type":"date",
        "format":"MM/dd/yyyy"  
        },
        "obj_id": {
          "type": "keyword",
          "index": false, //是否支持索引,默认是true
          "doc_values": false //false时不支持排序聚合
        },
        "bypass": {
          "properties": {
            "id": {
              "type": "keyword"
            },
            "vpnmtype": {
              "type": "keyword"
            },
            "vpnstype": {
              "type": "keyword"
            }
          }
        },
        "caller_type": {
          "type": "keyword"
        },
       "contend": {
          "type": "text",
          "fields": {       //子字段类型,索引时可以使用contend.keyword
            "keyword": {
              "type": "keyword"
            }
          },
          "analyzer": "ik_smart"
        },
      
.......

Search API

URI Search

q:指定URL查询条件
df(default field):指定查询的字段,如果不写,es 会查询所有字段或者是q中指定的字段
sort:排序
timeout:指定超时时间,默认不超时
from,size:用于分页

GET /u/_search?q=basketball
GET /u/_search?q=job:basketball mvp//查询出所有job是basketball和mvp的文档
GET /u/_search?q=job:"basketball mvp"//查询出所有job是basketball mvp的文档
GET /u/_search?q=job:(basketball mvp)//查询job:basketball或者job:mvp
GET /u/_search?q=user.id:8a4f500d
GET /u/_search?q=basketball&df=job&sort=age:asc&from=1&size=3&timeout=1s//df指定q的值basketball从job字段查,分页从第一页开始,每页3条记录,查询时间不能超过1秒,超过一秒就退出查询
布尔操作:

要大写,不能小写
AND:&&
OR:||
NOT:!

GET /u/_search?q=basketball AND mvp //查询出所有包含basketball 并且同时有mvp 的字段
GET /u/_search?q=job:(basketball AND mvp)//查询出所有job是basketball并且有mvp的文档
GET /u/_search?q=job:(basketball NOT mvp)//查询出所有job是basketball并且没有mvp的文档
GET /u/_search?q=job:(basketball || mvp)//查询出所有job是basketball或者有mvp的文档
{
    "profile":true"//查看es查询的过程
}
加减操作

+:在url写成%2B必须有 must
-:必须没有 must_not

GET /u/_search?q=basketball  %2Bmvp//查询出所有是basketball 并且一定包含mvp的文档
GET /u/_search?q=(basketball  %2Bmvp)//查询出所有是basketball 并且一定包含mvp的文档
GET /u/_search?q=basketball -2Bmvp//查询出所有是basketball 并且一定不包含mvp的文档
GET /u/_search?q=job:(basketball -2Bmvp)//查询出所有job是basketball 并且一定不包含mvp的文档
范围查询

闭区间 [ ] 开区间{ }
age:[1 TO 10]相当于1<=age<=10
age:[1 TO 10}相当于1<=age<10
age:[1 TO ]相当于age>=1
age:[* TO 10]相当于age<=10

GET /u/_search?q=basketball AND mvp age:>31 //查询出所有包含basketball 并且同时有mvp 的字段或者age大于31
GET /u/_search?q=basketball AND mvp AND age:>31//查询出所有包含basketball 并且同时有mvp 的字段并且age大于31
通配符查询

username:j?mes:匹配任意一个字符
username:jam*:匹配任意多个字符
username:j*s:匹配任意多个字符

GET /u/_search?q=j*s
GET /u/_search?q=username:j*s
GET /u/_search?q=j?mes

wildcard

wildcard类似上的模糊查询,相应于GET /u/_search?q=j*s的 DSL写法

post /u/_search
{
    "query": {
        "wildcard": {
            "username.keyword":"j*s" 
        }
    }
}
正则表达式查询

这个需要对正则表达的掌握能力,举两个例子

GET /u/_search?q=username:/j.{1,}/
GET /u/_search?q=username:/[张李].*亭{1,}.*/

query DSL 的写法

post /u/_search
{
    "query": {
        "regexp": {
            "username":"j.*" 
        }
    }
    
}
模糊匹配查询
GET /u/_search?q=job:basketball~1 //查询job中与basketball相差1个char值的文档,例如basketball 、basketball mvp
近似度查询
GET /u/_search?q=job:“basketball mvp“~1 //匹配到basketball mvp 前后中间可以允许插入1个词 basketball xxxx mvp\basketball mvp xxxx\xxxx basketball mvp都会匹配到,

Request Body Search

query DSL

字段查询

1、全文匹配

对text类型的字段查询时,会先分词

  • match:
    分词后词语没有先后顺序,随意组合,这个适合非常适用于关键词全文检索
select * from u where job like '%basketball%' or job like '%mvp%'

post /u/_search
{
    "profile":true,//查看es查询的过程
    "query":{
        "match":{
            "job":"basketball mvp"//job字段查询即包含basketball 或者包含mvp的文档
        }
    }
}
select * from u where job like '%basketball%' and job like '%mvp%'

post /u/_search
{
    "query": {
        "match":{
            "job":{
                "query":"basketball mvp",//job必须同时包含basketball和mvp
                "operator":"and"//默认是or
            }
        }
    }
}
post /u/_search
{
    "query": {
        "match":{
            "job":{
                "query":"basketball mvp act",
                "minimum_should_match":"2"//搜索出job字段中至少包含关键词其中两个才会匹配上
            }
            
        }
    }
}
  • match_all:
select * from u

post /u/_search
{
  "query": {
    "match_all": {}
  }
}
  • match_phrase:
    分词后词语存在先后顺序
    1. match_phrase还是分词后去搜的
    2. 目标文档需要包含分词后的所有词
    3. 目标文档还要保持这些词的相对顺序和文档中的一致
    4. match_phrase的缺点就是性能比较差

以"hello world"为例,要求结果中必须包含hello和world,而且还要求他们是连着的,顺序也是固定的,hello that word不满足,world hello也不满足条件。

post /u/_search
{
    "query": {
        "match_phrase":{
            "job":"basketball mvp"//查询包含basketball mvp的文档,
//与term不同的是term是从索引的单词找,match_phrase从文档的单词找
        }
    }
}
post /u/_search
{
    "query": {
        "match_phrase":{
            "job":{
                "query":"basketball act",
                "slop":"1"//允许文档出现和搜索条件相差一个距离的文档
       // 例如这里会匹配到 basketball xxxx act/basketball act xxxx/xxxx basketball act
            }
        }
    }
}
  • query_string:
    这个关键词和match类似,只是query_string更加暴力是所有字段中搜索范围更广泛。match则是需要指定字段的搜索的。但是query_string也可以指定字段并且可以使用and or等关键词,不指定字段默认全字段搜索,性能会很差
post /u/_search
{
    "query": {
        "query_string":{
            "query":"basketball AND act"//匹配所有的字段中即有basketball又有act的文档
        }
    }
}
post /u/_search
{
    "query": {
        "query_string":{
                "default_field":"job",//匹配job字段中即有basketball又有act的文档
            "query":"basketball AND act"
        }
    }
}
post /u/_search
{
    "query": {
        "query_string":{
                "fields":["job","username"],//只匹配job和username字段,并且每个字段都必须包含james 和 act
                "query":"james and act"
        }
    }
}

2、精确查询

  • term、terms:将查询语句作为一个单词查询,不做分词处理,查询时字段必须完全匹配包括长度顺序内容。使用这类关键词时字段的类型不要使用text,应当使用keyword类型,如果字段是text类型的话,我们查询时需要这样写: xxxx.keyword
select * from u where job="basketball mvp"

post /u/_search
{
    "query": {
        "term":{
            "job.keyword":"basketball mvp"//这里在倒排索引中匹配basketball mvp
//最终的结果是匹配不到任何文档,因为索引中都是一个个被切分了的单词不存在“basketball mvp”
        }
    }
}
select * from u where job in ('basketball', 'mvp')

post /u/_search
{
    "query": {
        "terms":{
            "job.keyword":["basketball","mvp"]
        }
    }
}

3、范围、排序、分页

  • range: 范围查询 lt:小于、lte:小于等于、gt:大于、gte大于等于
select * from u where age between 30 and 40;

post /u/_search
{
  "query" : {  
    "range" : {
      "age" : { 
        "gte" : 30,
        "lte" : 40
      }
    }
  }
}
  • sort,from,size:
POST /test/product/_search
{
  "query":{
    "match": {
      "productName":"苹果小米华为"
    }
    
  },
  "sort":{"price":"desc"},
  "from":2,
  "size":3
}

scroll:深分页,对于上面介绍的浅分页,如果请求的页数较少(假设每页20个docs), Elasticsearch不会有什么问题,但是如果页数较大时,比如请求第1000页,Elasticsearch不得不取出第1页到第1000页的所有docs,再去除第1页到第999页的docs,得到第1000页的docs。解决的方式就是使用scroll,scroll就是维护了当前索引段的一份快照信息--缓存

初始化的时候就像是普通的search一样 其中的scroll=3m代表当前查询的数据缓存3分钟

POST test/_search?scroll=3m
{
  "query":{
    "match_all": {}
  }
}

在遍历时候,拿到上一次遍历中的_scroll_id,然后带scroll参数,3m代表重置过期时间

POST /_search/scroll
{
  "scroll" : "3m",
  "scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFjlxTWE1RTZwUmdpd3FZSkpsYm5kYXcAAAAAAAA-vxZBRWtUWDAyalM5YTZvbmx0YTJxQjZR"
}
相关性得分(_score)

依据:

  • 词频:单词在该文档出现的频率越高,相关性越高
  • 文档长度:文档越短,相关性越高
  • 包含单词文档数量:文档包含某个单词的数量越少,相关性越高

复合查询

constant_score:

默认将其查询结果的文档得分都设置为1(如果不指定boost的话)或者指定boost的值,这个是当我们不关心检索词频率TF(Term Frequency)对搜索结果排序的影响时使用(简单了说就是不在乎得分)

POST /test/product/_search
{
  "query":{
    "constant_score": {
      "filter": {
        "match":{
          "productName":"华为"
        }
      },
      "boost": 1
    }
  }
}
GET test_index/_search
{
    "query": {
        "constant_score": {
            "boost": 1.0,
            "filter": {
                "bool": {
                    "must": [
                        {
                            "terms": {
                                "qq": [
                                  "7823709637249",
                                  "7828688362980"
                                    ]
                            }
                        }
                    ]
                }
            }
        }
    }
}

bool:

  • filter:使用filter查询时会有缓存,所以其效率很高,如果不使用相关性得分的排排序,推荐使用filter
 post /u/_search
{
    "query": {
        "bool": {
            "filter": {
                "term": {
                    "job.keyword": "basketball"
                }
            }
        }
    }
}
 post /u/_search
{
    "query": {
        "bool": {
            "filter": [
                {
                    "term": {
                        "job": "basketball"
                    }
                },
                {
                    "match": {
                        "job": "act"
                    }
                }
            ]
        }
    }
}
  • must:
 post /u/_search
//查询文档中的job字段必须同时包含basketball和act
{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "job": "basketball"
                    }
                },
                {
                    
                    "match": {
                        "job": "act"
                    }
                }
            ]
        }
    }
}
  • must_not:
 post /u/_search
//查询文档中的job字段必须同时包含basketball和act,而要求必须不能有mvp
{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "job": "basketball"
                    }
                },
                {
                    "match": {
                        "job": "act"
                    }
                }
            ],
            "must_not": [
                {
                    "match": {
                        "job": "mvp"
                    }
                }
            ]
        }
    }
}
  • should:默认至少满足一个条件,可以通过minimum_should_match控制满足个数
 post /u/_search
//查询满足其中之一的查询即可,也就是job中包含basketball或者act或者mvp其中一个就能查询出来
{
    "query": {
        "bool": {
            "should": [
                {
                    "term": {
                        "job": "basketball"
                    }
                },
                {
                    "match": {
                        "job": "act"
                    }
                },
                {
                    "match_phrase": {
                        "job": "basketball mvp"
                    }
                }
            ]
        }
    }
}
 post /u/_search
{
    "query": {
        "bool": {
            "should": [
                {
                    "term": {
                        "job": "basketball"
                    }
                },
                {
                    "match": {
                        "job": "act"
                    }
                },
                {
                    "match_phrase": {
                        "job": "basketball mvp"
                    }
                }
            ],
 "minimum_should_match":3//设置了满足条件为3
//查询结果同时满足其中三个也就job中包含basketball并且包含act和mvp就能查询出来都
        }
    }
}
  • should与must\must_not:查询时必须满足或者必须不满足must/must_not,可以不满足should,如果可以满足should也一并查出
 post /u/_search
{
    "query": {
        "bool": {
            "should": [
                {
                    "match": {
                        "job": "act"
                    }
                }
            ],
            "must": [
                {
                    "match":{
                        "job":"mvp"
                    }
                }
            ]
        }
    }
}

should+must+filter

{
    "query": {
        "bool": {
            "filter": [
                {
                    "bool": {
                        "must": [
                            {
                                "terms": {
                                    "boost": 1.0,
                                    "msisdn": [
                                        "7823709637249",
                                        "7828603061831",
                                        "7827817096436"
                                    ]
                                }
                            },
                            {
                                "range": {
                                    "ts_m": {
                                        "from": 1583622000017,
                                        "to": 1618902000017
                                    }
                                }
                            },
                            {
                                "bool": {
                                    "should": [
                                        {
                                            "terms": {
                                                "app_id": [
                                                    "0"
                                                ],
                                                "boost": 1.0
                                            }
                                        },
                                        {
                                            "terms": {
                                                "host": [
                                                    "res.wx.qq.com",
                                                    "bluedot.is.autonavi.com.gds.alibabadns.com"
                                                ]
                                            }
                                        },
                                        {
                                            "match": {
                                                "col10": {
                                                    "query": "品种猫 部门 蛾子 刘微球"
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        ]
                    }
                }
            ]
        }
    }
}
  • source:只希望返回个别字段即可
//只希望查询时返回username字段
GET /u/_search?_source=username

Count API

获取符合查询条件的文档数量
查询语句和上面的一样只是把URL修改了

post /u/_count
{
    "query": {
        "bool": {
            "should": [
                {
                    "match": {
                        "job": "act"
                    }
                }
            ],
            "must": [
                {
                    "match":{
                        "job":"mvp"
                    }
                }
            ]
        }
    }
}

排序、分页滚动

sort

  • 数字类型排序遍历
    单字段排序
 post /u/_search
{
    "query": {
        "bool": {
            "should": [
                {
                    "match": {
                        "job": "act"
                    }
                }
            ],
            "must": [
                {
                    "match": {
                        "job": "mvp"
                    }
                }
            ]
        }
    },
    "sort": {
        "age": "desc"//按照年龄倒叙排序
    }
}

多字段排序

 post /u/_search
{
    "query": {
        "match": {
            "job": "basketball"
        }
    },
    "sort": [
        {
            "age": "desc"
        },
        {
            "_score": "desc"
        }
    ]
}
  • 字符串类型排序
    按照字符串类型排序时不能排序text类型的,只能排序keyword的类型,所以在排序text类型时可以使用text.keyword的方式或者使用设置fielddata的属性,例如如下面的查询
post /u/_search
//text.keyword的方式
{
    "query": {
        "match": {
            "job": "basketball"
        }
    },
    "sort": {
        "username.keyword":"asc"
    }
}

设置fielddata为true

post /u/_mapping
{
   "properties":{
    "job":{
        "type":"text",
        "fielddata": true
    }
   }
}

然后直接进行text排序

POST /u/_search
{
    "query": {
        "match": {
            "job": "basketball"
        }
    },
    "sort": {
        "job":"asc"
    }
}
  • 分页
    from:开始位置 es默认不超过过
    size:获取的总数
    es默认不支持深分页换种说法就是es不支持大容量的分页,默认from+size不能超过10000
post /u/_search
{
   "from":9996,
   "size":4//from或者size再设置大一点就会报错
}
  • Scroll 分页滚动、遍历
    利用Scroll可以改变分页查询中不能做深分页的缺点,Scroll查询方式的原理就是通过每次查询后,返回一个scroll_id。根据这个scroll_id 进行下一页的查询。可以把这个scroll_id理解为通常关系型数据库中的游标。scroll查询的数据是当前索引段的一份快照信息–缓存,所以scroll没有实时性
//创建一个scroll设置,并且设置存活时间是两分钟,也就是快照存活2分钟
GET /u/_search?scroll=2m    
{
  "query": {"match_all": {}},
   "size": 1//设置每次滚动取1条数据,结果会返回
}
image.png

拿着scroll_id可以进行滚动

//滚动scroll
POST /_search?scroll
{
    "scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAANAWb1IxVjQ0cFBUMy1jb1dFZUdRbDNKdw==",
    "scroll":"5m"
}
  • Search After分页滚动、遍历
    利用Search After可以解决Scroll不能实时滚动的缺点,但是Search After只能往下滚动,只支持向下滚动,不支持向上滚动,并且创建Search After必须要给文档排序
post /u/_search
{
    "size":1,
   "sort":{
    "age":"desc"
   }
}
image.png

将返回结果的sort中的值设置到滚动语句中,上图是56,设置search_after为56

GET /u/_search
{
    "size":1,
    "search_after":[56],
   "sort":{
    "age":"desc"
   }
}

总结分页的使用场景


Aggregation 聚合查询

格式:

多用于统计使用的,举个例子
例如统计从事各类职业的人数有多少

GET /u/_search
{
    "size": 0,
    "aggs": {
        "tj": {
            "terms": {
                "field": "job.keyword"
            }
        }
    }
}

返回结果

    "aggregations": {
        "tj": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 2,
            "buckets": [
                {
                    "key": "act",
                    "doc_count": 2
                },
                {
                    "key": "act av",
                    "doc_count": 2
                },
                {
                    "key": "basketball",
                    "doc_count": 2
                },
               ........
            ]
        }
    }

聚合查询做的就是类似上面的事情,聚合查询分为4大类分别为:

  • Bucket:分析统计类型,类似数据库的group by
  • Metric:指标类型,统计如最大值,最小值,平均值等
  • Pipeline:管道分析类型,基于上一级分析的结果进行再次分析
  • Matrix:矩阵分析类型,是es的多维度分析

Bucket

bucket的作用类似数据库的分组,把不同的分析结果装到几个桶里

  • terms:按照词语分桶,分桶字段如果是keyword不会进行分词,直接按照整个单词分桶,如果是text则会先分词在分桶,不过使用text进行聚合需要设置fielddata为true
GET /u/_search
{
    "aggs": {
        "aggs_bulk": {
            "terms": {
                "field": "job.keyword",
                "size":3//指定返回的个数
            }
        }
    }
}

返回结果

 "aggregations": {
        "aggs_bulk": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 11,
            "buckets": [
                {
                    "key": "act",
                    "doc_count": 2
                },
                {
                    "key": "act av",
                    "doc_count": 2
                },
                {
                    "key": "basketball",
                    "doc_count": 2
                }
            ]
        }
    }
  • range
    范围聚合,统计数据指定范围的数量
GET /u/_search
{
    "aggs": {
        "aggs_range": {
            "range": {
                "field": "age",
                "ranges": [
                    {
                        "to": 36//统计年龄小于36的人数
                    },
                    {
                        "from": 35,
                        "to": 41
                    }//统计年龄35.0-41.0之间的人数
                ]
            }
        }
    }
}

返回结果

 "aggregations": {
        "aggs_range": {
            "buckets": [
                {
                    "key": "*-36.0",
                    "to": 36.0,
                    "doc_count": 9
                },
                {
                    "key": "35.0-41.0",
                    "from": 35.0,
                    "to": 41.0,
                    "doc_count": 7
                }
            ]
        }
    }
  • date range
    指定日期范围的分桶
GET monitor_temp/_search
{
    "aggs": {
        "aggs_range": {
            "date_range": {
                "field": "ts_m",
                "format":"yyyy-MM-dd HH:mm:ss",
                "ranges": [
                    {
                        "from":"2020-04-01 00:00:00",
                        "to": "2020-04-30 12:00:00"
                    },
                    {
                      "from":"2020-05-01 00:00:00",
                        "to": "2020-05-30 12:00:00"
                    }
                ]
            }
        }
    }
}

返回部分结果

 "aggregations" : {
    "aggs_range" : {
      "buckets" : [
        {
          "key" : "2020-04-01 00:00:00-2020-04-30 12:00:00",
          "from" : 1.5856992E12,
          "from_as_string" : "2020-04-01 00:00:00",
          "to" : 1.588248E12,
          "to_as_string" : "2020-04-30 12:00:00",
          "doc_count" : 3
        },
        {
          "key" : "2020-05-01 00:00:00-2020-05-30 12:00:00",
          "from" : 1.5882912E12,
          "from_as_string" : "2020-05-01 00:00:00",
          "to" : 1.59084E12,
          "to_as_string" : "2020-05-30 12:00:00",
          "doc_count" : 3
        }
      ]
    }
  }

  • histogram
    统计固定间隔的数据数量。类似一个树形柱状图
GET /u/_search
{
    "aggs": {
        "aggs_his": {
            "histogram": {
                "field": "age",
                "interval":5,//统计年龄间隔5岁的各个阶段的人数
                "extended_bounds": //查询范围
                    {
                        "min":30,
                        "max": 56
                    }
            }
        }
    }
}

返回结果

 "aggregations": {
        "aggs_his": {
            "buckets": [
                {
                    "key": 25.0,
                    "doc_count": 2
                },
                {
                    "key": 30.0,
                    "doc_count": 6
                },
                {
                    "key": 35.0,
                    "doc_count": 7
                },
                {
                    "key": 40.0,
                    "doc_count": 1
                },
                {
                    "key": 45.0,
                    "doc_count": 0
                },
                {
                    "key": 50.0,
                    "doc_count": 0
                },
                {
                    "key": 55.0,
                    "doc_count": 1
                }
            ]
        }
    }

从query的结果集中,以ts_m字段指定的范围,取每隔1小时取一次数据量统计

GET monitor_temp/_search
{
    "query": {
      "range": {
        "ts_m": {
          "gte": 1617273000000,
          "lte": 1617359400000
        }
      }
    },   
    "aggs": {
        "aggs_his": {
            "histogram": {
                "field": "ts_m",
                "format":"yyyy-MM-dd HH:mm",
                "interval":3600000,
                "extended_bounds": 
                    {
                        "max":1617359400000,
                        "min":1617273000000
                    }
            }
        }
    }
}

返回的部分结果

"aggregations" : {
    "aggs_his" : {
      "buckets" : [
        {
          "key_as_string" : "2021-04-01 10:00",
          "key" : 1.6172712E12,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2021-04-01 11:00",
          "key" : 1.6172748E12,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2021-04-01 12:00",
          "key" : 1.6172784E12,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2021-04-01 13:00",
          "key" : 1.617282E12,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2021-04-01 14:00",
          "key" : 1.6172856E12,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2021-04-01 15:00",
          "key" : 1.6172892E12,
          "doc_count" : 0
        },
      
        .......
      ]
    }
  }
  • date histogram
    用于日期的histogram
GET /u/_search
{
    "aggs": {
        "aggs_his": {
            "date_histogram": {
                "field": "brith",
                "interval":"year",//出生日期以每一年为间隔
                "format": "yyyy-MM-dd HH:mm:ss"
            }
        }
    }
}

输出结果

"aggregations": {
        "aggs_his": {
            "buckets": [
                {
                    "key_as_string": "1954-01-01 00:00:00",
                    "key": -504921600000,
                    "doc_count": 1
                },
                {
                    "key_as_string": "1959-01-01 00:00:00",
                    "key": -347155200000,
                    "doc_count": 0
                },
                {
                    "key_as_string": "1967-01-01 00:00:00",
                    "key": -94694400000,
                    "doc_count": 0
                },
                {
                    "key_as_string": "1968-01-01 00:00:00",
                    "key": -63158400000,
                    "doc_count": 0
                },
                {
                    "key_as_string": "1969-01-01 00:00:00",
                    "key": -31536000000,
                    "doc_count": 0
                },
              .................

从query的结果集中,以ts_m字段指定的范围,取每隔1小时取一次数据量统计,返回的结果是上海时间

GET monitor_temp/_search
{
    "aggregations": {
        "aggs_his": {
            "date_histogram": {
                "extended_bounds": {
                    "max":1617359400000,
                      "min":1617273000000
                },
                "field": "ts_m",
                "interval": "1h",
                "offset": 0,
                "format":"MM-dd HH:mm",
                "order": {
                    "_key": "asc"
                },
                "time_zone": "Asia/Shanghai"
            }
        }
    },
    "query": {
        "range": {
            "ts_m": {
                "from": 1617273000000,
                "to": 1617359400000
            }
        }
    }
}

部分返回结果

 "aggregations" : {
    "aggs_his" : {
      "buckets" : [
        {
          "key_as_string" : "04-01 18:00",
          "key" : 1617271200000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "04-01 19:00",
          "key" : 1617274800000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "04-01 20:00",
          "key" : 1617278400000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "04-01 21:00",
          "key" : 1617282000000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "04-01 22:00",
          "key" : 1617285600000,
          "doc_count" : 0
        },

Metric

- 单值分析

分析只输出一个结果

  • min、max、avg、sum
//查询age的最小值
GET test/_search
{
  "aggs": {
    "max": {
      "min": {
        "field": "price"
      }
    }
  }
}

输出部分结果

"aggregations" : {
    "max" : {
      "value" : 130.0
    }

//查询age的最大值
GET /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_name": {
            "max": {
                "field": "age"
            }
        }
    }
}
//查询age的总值
GET /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_name": {
            "sum": {
                "field": "age"
            }
        }
    }
}
//查询age的平均值
GET /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_name": {
            "avg": {
                "field": "age"
            }
        }
    }
}

可以将他们组合在一起

GET test/_search
{
    "size": 0,
    "aggs": {
        "aggs_avg": {
            "avg": {
                "field": "price"
            }
        },
        "aggs_sum": {
            "sum": {
                "field": "price"
            }
        },
        "aggs_max": {
            "max": {
                "field": "price"
            }
        },
        "aggs_min": {
            "min": {
                "field": "price"
            }
        }
    }
}

输出部分结果

"aggregations" : {
    "aggs_sum" : {
      "value" : 134633.0
    },
    "aggs_min" : {
      "value" : 130.0
    },
    "aggs_avg" : {
      "value" : 5853.608695652174
    },
    "aggs_max" : {
      "value" : 22788.0
    }
  }

  • cardinality:统计某个字段有多少种类
GET test/_search
{
    "size": 0,
    "aggs": {
        "aggs_cardinality": {
            "cardinality": {
                "field": "productName.keyword" //统计productName的不同种类
            }
        }
    }
}

部分输出结果

"aggregations" : {
    "aggs_cardinality" : {
      "value" : 23
    }
  }

- 多值分析

分析可以输出多个结果

stats、extended_stats、percentiles:
  • stats:返回一系列统计类型,包括min,max,avg,sum,count
GET /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_stats": {
            "stats": {
                "field": "age"
            }
        }
    }
}

输出的结果

  "aggregations": {
        "aggs_count": {
            "count": 17,
            "min": 25.0,
            "max": 56.0,
            "avg": 34.64705882352941,
            "sum": 589.0
        }
    }

  • extended_stats:计算方差、标准差等使用extended_stats,是对stats功能的扩展
GET /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_estats": {
            "extended_stats": {
                "field": "age"
            }
        }
    }
}

输出结果

    "aggregations": {
        "aggs_estats": {
            "count": 17,
            "min": 25.0,
            "max": 56.0,
            "avg": 34.64705882352941,
            "sum": 589.0,
            "sum_of_squares": 21175.0,
            "variance": 45.16955017301028,
            "std_deviation": 6.720829574763094,
            "std_deviation_bounds": {
                "upper": 48.0887179730556,
                "lower": 21.205399674003225
            }
        }
    }

  • percentiles:统计数据的所占百分位比重,例如统计数据中百分之多少的人是在哪个年龄段
GET /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_percentile": {
            "percentiles": {
                "field": "age"
            }
        }
    }
}

返回结果

   "aggregations": {
       "aggs_percentile": {
           "values": {
               "1.0": 24.999999999999996,//24岁年龄段的有百分之1
               "5.0": 25.0,//25岁年龄段的有百分之5
               "25.0": 31.0,//31岁年龄段的有百分之25
               "50.0": 35.0,//35岁年龄段的有百分之50
               "75.0": 36.0,//36岁年龄段的有百分之75
               "95.0": 50.74999999999998,//51岁年龄段的有百分之95
               "99.0": 56.0//56岁年龄段的有百分之99
           }
       }
}

我们可以指定某个百分数范围内对应的数值是哪些

GET /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_percentile": {
            "percentiles": {
                "field": "age",
                "percents":[50,75]
            }
        }
    }
}

返回结果

 "aggregations": {
        "aggs_percentile": {
            "values": {
                "50.0": 35.0,
                "75.0": 36.0
            }
        }
    }

  • aggs_percentile:我们查某些数据范围中是处于哪个百分位
GET test/_search
{
  "aggs": {
    "p_r": {
      "percentile_ranks": {
        "field": "price",
        "values": [
          19988,
          5800
        ]
      }
    }
  }
}

输出结果

 "aggregations" : {
    "p_r" : {
      "values" : {
        "5800.0" : 63.47826086956522,
        "19988.0" : 94.54434671825976
      }
    }
  }

  • top_hits:我们希望能从分组统计的基础上再获取统计信息

下面是按照职业进行分组,但是我们要取每个分组中前十名

GET /u/_search
{
    "size": 0,
    "aggs": {
        "tj": {
            "terms": {
                "field": "job.keyword"
            },
            "aggs": {
                "my_top": {
                    "top_hits": {
                        "size": 10,
                        "sort": [
                            {
                                "age": {
                                    "order": "desc"
                                }
                            }
                        ]
                    }
                }
            }
        }
    }
}
  • 桶中桶 bucket+Metric的组合拳

在分组后,对每个组在进行统计

GET /u/_search
//统计在职业分组后,再统计每组职业的年龄段占比多少
{
    "aggs": {
        "aggs_term": {
            "terms": {
                "field": "job.keyword",
                "size": 10
            },
            "aggs": {
                "aggs_percentile": {
                    "percentiles": {
                        "field": "age"
                    }
                }
            }
        }
    }
}

返回结果

"aggregations": {
        "aggs_term": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 2,
            "buckets": [
                {
                    "key": "act",
                    "doc_count": 2,
                    "aggs_percentile": {
                        "values": {
                            "1.0": 36.0,
                            "5.0": 36.0,
                            "25.0": 36.0,
                            "50.0": 38.5,
                            "75.0": 41.0,
                            "95.0": 41.0,
                            "99.0": 41.0
                        }
                    }
                },
                {
                    "key": "act av",
                    "doc_count": 2,
                    "aggs_percentile": {
                        "values": {
                            "1.0": 25.0,
                            "5.0": 25.0,
                            "25.0": 25.0,
                            "50.0": 30.0,
                            "75.0": 35.0,
                            "95.0": 35.0,
                            "99.0": 35.0
                        }
                    }
                },
                {
                    "key": "basketball",
                    "doc_count": 2,
                    "aggs_percentile": {
                        "values": {
                            "1.0": 30.999999999999996,
                            "5.0": 31.0,
                            "25.0": 31.0,
                            "50.0": 31.5,
                            "75.0": 32.0,
                            "95.0": 32.0,
                            "99.0": 32.0
                        }
                    }
                },
                {
                    "key": "basketball mvp",
                    "doc_count": 2,
                    "aggs_percentile": {
                        "values": {
                            "1.0": 29.999999999999996,
                            "5.0": 30.0,
                            "25.0": 30.0,
                            "50.0": 31.0,
                            "75.0": 32.0,
                            "95.0": 32.0,
                            "99.0": 32.0
                        }
                    }
                },
                {
                    "key": "basketball mvp act",
                    "doc_count": 2,
                    "aggs_percentile": {
                        "values": {
                            "1.0": 30.999999999999996,
                            "5.0": 31.0,
                            "25.0": 31.0,
                            "50.0": 43.5,
                            "75.0": 56.0,
                            "95.0": 56.0,
                            "99.0": 56.0
                        }
                    }
                },
                {
                    "key": "basketball act",
                    "doc_count": 1,
                    "aggs_percentile": {
                        "values": {
                            "1.0": 33.0,
                            "5.0": 33.0,
                            "25.0": 33.0,
                            "50.0": 33.0,
                            "75.0": 33.0,
                            "95.0": 33.0,
                            "99.0": 33.0
                        }
                    }
                },
                {
                    "key": "cartoonman hai",
                    "doc_count": 1,
                    "aggs_percentile": {
                        "values": {
                            "1.0": 36.0,
                            "5.0": 36.0,
                            "25.0": 36.0,
                            "50.0": 36.0,
                            "75.0": 36.0,
                            "95.0": 36.0,
                            "99.0": 36.0
                        }
                    }
                }, 
            .............
            ]
        }
  • Pipeline管道聚合分析

针对上层分析的结果进行再次分析,其分析的结果会输出到上层的结果中,根据输出的位置不同分为两类:

  • 内嵌到上层的结果中
    min、max、avg、stats、percentiles
    min_bucket\max_bucket\avg_bucket\stats_bucket\percentiles_bucket
    用法差不多,举一个例子,
//计算每一类职业的平均收入,然后找出平均收入最低的职业
GET /u/_search
{
    "aggs": {
        "aggs_term": {
            "terms": {
                "field": "job.keyword"
            },
            "aggs": {
                "aggs_avg": {
                    "avg": {
                        "field": "income"
                    }
                }
            }
        },
        "min_pipeline": {//给pipeline起名字,pipeline与aggs的子项aggs_term同级,导致后面的buckets_path要写成aggs_term>aggs_avg
//分析谁就与谁同级
            "min_bucket": {//min_bucket是关键词,如果是算最大值换成max_bucket,平均值换成avg_bucket、同时获取多个指标则用stats_bucket
                "buckets_path": "aggs_term>aggs_avg"//aggs的所属结构
            }
        }
    }
}

输出结果

  "min_pipeline": {
            "value": 1000.0,//平均收入最低是1000
            "keys": [//这几个职业都是收入最低的
                "cartoonman hai",
                "cartoonman hot",
                "cartoonman qun",
                "cartoonman seven"
            ]
        }
  • 结果与上层的结果同级

  • 聚合分析的范围

aggs与query关键字同级,在query执行后,aggs针对query执行的结果进行分析,也就是说query查出来结果就是aggs的分析范围
也可以在aggs内部使用filter关键词限定范围

GET /u/_search
{
    "aggs": {
        "aggs_filter": {
            "filter": {//利用filter限定aggs范围
                "match": {
                    "job":"basketball"
                }
            },
            "aggs":{
                "job_aggs":{
                    "terms":{
                        "field":"job.keyword"
                    }
                }
            }
        }
       
    }
}

还要一种限定范围的方法是post_filter在aggs分析之后在进行筛选

{
    "aggs": {
        "job_aggs": {
            "terms": {
                "field": "job.keyword"
            }
        }
    },
    "post_filter":{
        "match":{
            "job.keyword":"mvp"
        }
    }
}

聚合排序sort

GET /u/_search
{
    "aggs": {
        "aggs_term": {
            "terms": {
                "field": "job.keyword",
                 "order":{
                    "aggs_avg":"desc"//以子聚合分析的结果排序
                }  
            },
            "aggs": {
                "aggs_avg": {
                    "avg": {
                        "field": "income"
                    }
                }
            }
            
        }
       
    }
}

返回结果

 "buckets": [
                {
                    "key": "soccerball mvp",
                    "doc_count": 1,
                    "aggs_avg": {
                        "value": 5.0E8
                    }
                },
                {
                    "key": "basketball mvp",
                    "doc_count": 2,
                    "aggs_avg": {
                        "value": 1.3E8
                    }
                },
                {
                    "key": "basketball",
                    "doc_count": 2,
                    "aggs_avg": {
                        "value": 8.5E7
                    }
                },
                {
                    "key": "act",
                    "doc_count": 2,
                    "aggs_avg": {
                        "value": 1.01E7
                    }
                },
                {
                    "key": "basketball mvp act",
                    "doc_count": 2,
                    "aggs_avg": {
                        "value": 750000.0
                    }
                },
                {
                    "key": "basketball act",
                    "doc_count": 1,
                    "aggs_avg": {
                        "value": 600000.0
                    }
                },
                {
                    "key": "act av",
                    "doc_count": 2,
                    "aggs_avg": {
                        "value": 40000.0
                    }
                },
                {
                    "key": "great",
                    "doc_count": 1,
                    "aggs_avg": {
                        "value": 8000.0
                    }
                },
                  .........................

以外层的key或者聚合分析数排序

GET /u/_search
{
    "aggs": {
        "aggs_term": {
            "terms": {
                "field": "job.keyword",
                "order": [
                    {
                        "_key": "desc"//聚合结果的key排序
                    },
                    {
                        "_count": "desc"//聚合数量排序
                    }
                ]
            },
            "aggs": {
                "aggs_avg": {
                    "avg": {
                        "field": "income"
                    }
                }
            }   
        }  
    }
}

返回结果

"buckets": [
                {
                    "key": "soccerball mvp",
                    "doc_count": 1,
                    "aggs_avg": {
                        "value": 5.0E8
                    }
                },
                {
                    "key": "great",
                    "doc_count": 1,
                    "aggs_avg": {
                        "value": 8000.0
                    }
                },
                {
                    "key": "cartoonman seven",
                    "doc_count": 1,
                    "aggs_avg": {
                        "value": 1000.0
                    }
                },
                {
                    "key": "cartoonman qun",
                    "doc_count": 1,
                    "aggs_avg": {
                        "value": 1000.0
                    }
                },
                {
                    "key": "cartoonman hot",
                    "doc_count": 1,
                    "aggs_avg": {
                        "value": 1000.0
                    }
                },
                {
                    "key": "cartoonman hai",
                    "doc_count": 1,
                    "aggs_avg": {
                        "value": 1000.0
                    }
                },
                  ..........................
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335