Elasticsearch学习(一)

2020-05-25  本文已影响0人  笔记本一号

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

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 ,也可以设置成一个自定义的值

分片的实时性和查询性能

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

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

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

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

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

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

es写性能优化

降低刷新频率(会影响实时性)

虽然刷新(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毫秒 (会使你的集群陷入瘫痪)。

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

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

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

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

index.translog.sync_interval:30s(默认5s)。
index.translog.flush_threshold_size:700mb(默认512mb)
index.translog.durability:async(默认request) //通过异步提交日志,不过可以会在宕机时丢失数据

es读性能优化

内存对于 Elasticsearch 来说绝对是重要的,它可以被许多内存数据结构使用来提供更快的操作。但是说到这里, 还有另外一个内存消耗大户 非堆内存 (off-heap):Lucene。

Lucene 被设计为可以利用操作系统底层机制来缓存内存数据结构。 Lucene 的段是分别存储到单个文件中的。因为段是不可变的,这些文件也都不会变化,这是对缓存友好的,同时操作系统也会把这些段文件缓存起来,以便更快的访问。

Lucene 的性能取决于和操作系统的相互作用。如果你把所有的内存都分配给 Elasticsearch 的堆内存,那将不会有剩余的内存交给 Lucene。 这将严重地影响全文检索的性能。

标准的建议是把 50% 的可用内存作为 Elasticsearch 的堆内存,保留剩下的 50%。

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"
}

批量创建文档:

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 自定义分词器

自定义分词器:

put /index_name_2
{
"settings":{
    "analysis":{
            "analyzer":{
                "my_analysis":{
                          "type":"custom",
                           "tokenizer":"standard",
                           "char_filter":["html_strip","to_and"],
                            "filter":["lowercase","my_stopwords"]
                    }
                },
                "char_filter": {
            "to_and": {
                "type": "mapping",
                "mappings": ["& => and"]
            }
        },
        "filter": {
            "my_stopwords": {
                "type": "stop",
                "stopwords": ["the", "a"]
                        }
                }
            }
    }
}  

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

Mapping

Mapping类似数据库表数据类型定义,Mapping可以定义index下的字段名,字段类型

这里不写了,属性太多,到官方网站看文档去吧
https://www.elastic.co/guide/en/elasticsearch/reference/master/mapping.html

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

query 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类型的字段查询时,会先分词

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字段中至少包含关键词其中两个才会匹配上
            }
            
        }
    }
}
select * from u

post /u/_search
{
  "query": {
    "match_all": {}
  }
}
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
            }
        }
    }
}
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字段
                "query":"james act"
        }
    }
}

2、精确查询

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、范围、排序、分页

select * from u where age between 30 and 40;

post /u/_search
{
  "query" : {  
    "range" : {
      "age" : { 
        "gte" : 30,
        "lte" : 40
      }
    }
  }
}
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的值,这个是在当我们不关心检索词频率TF(Term Frequency)对搜索结果排序的影响时使用

POST /test/product/_search
{
  "query":{
    "constant_score": {
      "filter": {
        "match":{
          "productName":"华为"
        }
      },
      "boost": 1
    }
  }
}
post /u/_search
{   
    "query": {
        "constant_score":{
            "filter":{
                "match":{
                    "job":{
                        "query":"basketball mvp",
                        "operator":"and"
                    }
                }
            }
        }
    }
}

bool:

 post /u/_search
{
    "query": {
        "bool": {
            "filter": {
                "term": {
                    "job.keyword": "basketball"
                }
            }
        }
    }
}
 post /u/_search
{
    "query": {
        "bool": {
            "filter": [
                {
                    "term": {
                        "job": "basketball"
                    }
                },
                {
                    "match": {
                        "job": "act"
                    }
                }
            ]
        }
    }
}
 post /u/_search
//查询文档中的job字段必须同时包含basketball和act
{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "job": "basketball"
                    }
                },
                {
                    
                    "match": {
                        "job": "act"
                    }
                }
            ]
        }
    }
}
 post /u/_search
//查询文档中的job字段必须同时包含basketball和act,而要求必须不能有mvp
{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "job": "basketball"
                    }
                },
                {
                    "match": {
                        "job": "act"
                    }
                }
            ],
            "must_not": [
                {
                    "match": {
                        "job": "mvp"
                    }
                }
            ]
        }
    }
}
 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就能查询出来都
        }
    }
}
 post /u/_search
{
    "query": {
        "bool": {
            "should": [
                {
                    "match": {
                        "job": "act"
                    }
                }
            ],
            "must": [
                {
                    "match":{
                        "job":"mvp"
                    }
                }
            ]
        }
    }
}
//只希望查询时返回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"
        }
    ]
}
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"
    }
}
post /u/_search
{
   "from":9996,
   "size":4//from或者size再设置大一点就会报错
}
//创建一个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"
}
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
                },
                {
                    "key": "basketball mvp",
                    "doc_count": 2
                },
                {
                    "key": "basketball mvp act",
                    "doc_count": 2
                },
                {
                    "key": "basketball act",
                    "doc_count": 1
                },
                {
                    "key": "cartoonman hai",
                    "doc_count": 1
                },
                {
                    "key": "cartoonman hot",
                    "doc_count": 1
                },
                {
                    "key": "cartoonman qun",
                    "doc_count": 1
                },
                {
                    "key": "cartoonman seven",
                    "doc_count": 1
                }
            ]
        }
    }

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

Bucket

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

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
                }
            ]
        }
    }
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
                }
            ]
        }
    }
GET /u/_search
{
    "aggs": {
        "aggs_range": {
            "date_range": {
                "field": "brith",
                "format":"yyyy-MM-dd HH:mm:ss",
                "ranges": [
                    {
                        "from":"1990-01-01 00:00:00",
                        "to": "2000-12-12 12:00:00"
                    }
                ]
            }
        }
    }
}

返回结果

"aggregations": {
        "aggs_range": {
            "buckets": [
                {
                    "key": "1990-01-01 00:00:00-2000-12-12 12:00:00",
                    "from": 6.31152E11,
                    "from_as_string": "1990-01-01 00:00:00",
                    "to": 9.766224E11,
                    "to_as_string": "2000-12-12 12:00:00",
                    "doc_count": 8
                }
            ]
        }
    }
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
                }
            ]
        }
    }
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
                },
                {
                    "key_as_string": "1970-01-01 00:00:00",
                    "key": 0,
                    "doc_count": 0
                },
                {
                    "key_as_string": "1971-01-01 00:00:00",
                    "key": 31536000000,
                    "doc_count": 0
                },
                {
                    "key_as_string": "1972-01-01 00:00:00",
                    "key": 63072000000,
                    "doc_count": 0
                },
                {
                    "key_as_string": "1973-01-01 00:00:00",
                    "key": 94694400000,
                    "doc_count": 0
                },
                {
                    "key_as_string": "1974-01-01 00:00:00",
                    "key": 126230400000,
                    "doc_count": 0
                },
                {
                    "key_as_string": "1975-01-01 00:00:00",
                    "key": 157766400000,
                    "doc_count": 1
                },
                {
                    "key_as_string": "1976-01-01 00:00:00",
                    "key": 189302400000,
                    "doc_count": 0
                },
                {
                    "key_as_string": "1977-01-01 00:00:00",
                    "key": 220924800000,
                    "doc_count": 0
                },
                {
                    "key_as_string": "1982-01-01 00:00:00",
                    "key": 378691200000,
                    "doc_count": 1
                },
                {
                    "key_as_string": "1983-01-01 00:00:00",
                    "key": 410227200000,
                    "doc_count": 1
                },
                {
                    "key_as_string": "1984-01-01 00:00:00",
                    "key": 441763200000,
                    "doc_count": 0
                },
              .................

Metric

- 单值分析

分析只输出一个结果

//查询age的最小值
GET /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_name": {
            "min": {
                "field": "age"
            }
        }
    }
}
//查询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 /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_avg": {
            "avg": {
                "field": "age"
            }
        },
        "aggs_sum": {
            "sum": {
                "field": "age"
            }
        },
        "aggs_max": {
            "max": {
                "field": "age"
            }
        },
        "aggs_min": {
            "min": {
                "field": "age"
            }
        }
    }
}
GET /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_cardinality": {
            "cardinality": {
                "field": "job.keyword"//统计工作字段不同的值有多少个
            }
        }
    }
}
- 多值分析

分析可以输出多个结果

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

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
            }
        }
    }

我们可以指定某个数值范围内是在数据中是处于哪个百分位

GET /u/_search
{
    "size": 0,
    "aggs": {
        "aggs_percentile": {
            "percentile_ranks": {
                "field": "age",
                "values":[56]//查询数据中在56岁范围内的有百分之多少
            }
        }
    }
}

输出结果

    "aggregations": {
        "aggs_percentile": {
            "values": {
                "56.0": 100.0//百分之100
            }
        }
    }

我们希望能从分组统计中同时获取到详情可以使用top_hits

GET /u/_search
{
    "size": 0,
    "aggs": {
        "tj": {
            "terms": {
                "field": "job.keyword"
            },
            "aggs": {
                "my_top": {
                    "top_hits": {
                        "size": 10,
                        "sort": [
                            {
                                "age": {
                                    "order": "desc"
                                }
                            }
                        ]
                    }
                }
            }
        }
    }
}

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

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
                        }
                    }
                },
                {
                    "key": "cartoonman hot",
                    "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
                        }
                    }
                },
                {
                    "key": "cartoonman qun",
                    "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
                        }
                    }
                },
                {
                    "key": "cartoonman seven",
                    "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
                        }
                    }
                }
            ]
        }

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

//计算每一类职业的平均收入,然后找出平均收入最低的职业
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
                    }
                },
                  ..........................
上一篇下一篇

猜你喜欢

热点阅读