search的timeout
- 设置:默认没有timeout,如果设置了timeout,那么会执行timeout机制。
- Timeout机制:假设用户查询结果有1W条数据,但是需要10s才能查询完毕,但是用户设置了1s的timeout,那么不管当前一共查询到了多少数据,都会在1″后ES讲停止查询,并返回当前数据。
- 用法:GET /_search?timeout=1s/ms/m
在返回值中, 如果是 "timed_out" : false, 说明没有超时, 返回的是全量数据
Query_string 一般不用于生产环境
- 查询所有:GET /product/_search
- 带参数:GET /product/_search?q=name:xiaomi
- 分页:GET /product/_search?from=0&size=2&sort=price:asc
Query DSL
match_all:匹配所有
GET /product/_search
{
"query":{
"match_all": {}
}
}
match:会分词, 各个词之间是or的关系 -> name中包含“nfc” 或者 包含"phone"
GET /product/_search
{
"query": {
"match": {
"name": "nfc phone"
}
}
}
sort:按照价格倒序排序 一旦有了sort, es为了提升性能, 就不会去算score, 因为没有必要
GET /product/_search
{
"query": {
"multi_match": {
"query": "nfc",
"fields": ["name","desc"]
}
},
"sort": [
{
"price": "desc"
}
]
}
multi_match:根据多个字段查询一个关键词,name和desc中包含“nfc”的doc
GET /product/_search
{
"query": {
"multi_match": {
"query": "nfc",
"fields": ["name","desc"]
}
},
"sort": [
{
"price": "desc"
}
]
}
_source 元数据:想要让返回的字段少一些, 可以用这个
GET /product/_search
{
"query":{
"match": {
"name": "nfc"
}
},
"_source": ["name","price"]
}
分页:查询第一页(每页两条数据), 但是要注意deep-paging问题
GET /product/_search
{
"query":{
"match_all": {}
},
"sort": [
{
"price": "asc"
}
],
"from": 0,
"size": 2
}
Full-text queries:全文检索
term:不会被分词
GET /product/_search
{
"query": {
"term": {
"name": "nfc"
}
}
}
"hits" : [ {
"_score" : 0.90928507,
"_source" : {
"name" : "nfc phone"
}
}, {
"_score" : 0.76209855,
"_source" : {
"name" : "xiaomi nfc phone"
}
}
]
match和term区别:
# 这里因为没有分词,所以从倒排索引中查询 "nfc phone" 没有结果
GET /product/_search
{
"query": {
"term": {
"name": "nfc phone"
}
}
}
# name中既要有nfc, 又必须有phone
GET /product/_search
{
"query": {
"bool": {
"must": [
{"term":{"name":"nfc"}},
{"term":{"name":"phone"}}
]
}
}
}
{
"_score" : 1.4691012,
"_source" : {
"name" : "nfc phone"
}
}, {
"_score" : 1.2312969,
"_source" : {
"name" : "xiaomi nfc phone"
}
}
# name中要有nfc 或者 要有phone
GET /product/_search
{
"query": {
"terms": {
"name":["nfc","phone"]
}
}
}
{
"_score" : 1.0,
"_source" : {
"name" : "xiaomi phone"
}
}, {
"_score" : 1.0,
"_source" : {
"name" : "xiaomi nfc phone"
}
}, {
"_score" : 1.0,
"_source" : {
"name" : "nfc phone"
}
}
# match会分词, 词与词之间的关系是or
GET /product/_search
{
"query": {
"match": {
"name": "nfc phone"
}
}
}
{
"_score" : 1.4691012,
"_source" : {
"name" : "nfc phone"
}
}, {
"_score" : 1.2312969,
"_source" : {
"name" : "xiaomi nfc phone"
}
}, {
"_score" : 0.5598161,
"_source" : {
"name" : "xiaomi phone"
}
}
☆全文检索
GET /product/_search
{
"query": {
"match": {
"name": "xiaomi nfc zhineng phone"
}
}
}
#验证分词
GET /_analyze
{
"analyzer": "standard"
,"text": "xiaomi nfc zhineng phone"
}
返回
"tokens" : [
{
"token" : "xiaomi",
"start_offset" : 0,
"end_offset" : 6,
"type" : "<ALPHANUM>",
"position" : 0
}, {
"token" : "nfc",
"start_offset" : 7,
"end_offset" : 10,
"type" : "<ALPHANUM>",
"position" : 1
}, {
"token" : "zhineng",
"start_offset" : 11,
"end_offset" : 18,
"type" : "<ALPHANUM>",
"position" : 2
}, {
"token" : "phone",
"start_offset" : 19,
"end_offset" : 24,
"type" : "<ALPHANUM>",
"position" : 3
}
]
phrase search:短语搜索,和全文检索相反,“nfc phone”会作为一个短语去检索
# nfc和phone必须同时包含
GET /product/_search
{
"query": {
"match_phrase": {
"name": "nfc phone"
}
}
}
Query and filter:查询和过滤
bool:可以组合多个查询条件,bool查询也是采用more_matches_is_better的机制,因此满足must和should子句的文档将会合并起来计算分值
bool下的多个查询条件, 是AND的关系
score | cache | ||
---|---|---|---|
must 必须满足 | 计算 | 子句(查询)必须出现在匹配的文档中, AND: 子句全都要满足 | |
filter 过滤器 | 不计算 | 缓存 | 子句(查询)必须出现在匹配的文档中。但是不像 |
should 或 | 计算 | 子句(查询)应出现在匹配的文档中 minimum_should_match: 1 OR: 子句至少满足一个 | |
must_not 必须不满足 | 不计算 | 缓存 | 子句(查询)不得出现在匹配的文档中。子句在过滤器上下文中执行,这意味着计分被忽略,并且子句被视为用于缓存。由于忽略计分, |
# 首先筛选name包含“xiaomi phone”, 并且价格大于1999的数据(不排序)
GET /product/_search
{
"query": {
"bool":{
"must": [
{ "match": { "name": "xiaomi"}},
{ "match": { "desc": "shouji"}}
],
"filter": [
{ "match_phrase": { "name":"xiaomi phone"}},
{ "range": {
"price": {
"gt": 1999
}
}}
]
}
}
}
# bool多条件 name包含xiaomi 不包含erji 描述里包不包含nfc都可以,价钱要大于等于4999
GET /product/_search
{
"query": {
"bool": {
"must": [ # name中必须包含“xiaomi”
{"match": { "name": "xiaomi"}}
],
"must_not": [ # name中必须不能包含“erji”
{"match": { "name": "erji"}}
],
"should": [ #should中至少满足0个条件,参见下面的minimum_should_match的解释
{"match": {
"desc": "nfc"
}}
],
"filter": [
{"range": {
"price": { # 筛选价格大于4999的doc
"gt": 4999
}
}}
]
}
}
}
嵌套查询:
minimum_should_match:参数指定should返回的文档必须匹配的子句的数量或百分比。如果bool查询包含至少一个should子句,而没有must或 filter子句,则默认值为1。否则,默认值为0
GET /product/_search
{
"query": {
"bool":{
"should": [
{"range": {
"price": {"gt":1999}
}},
{"range": {
"price": {"gt":3999}
}}
],
"minimum_should_match": 1
}
}
}
Compound queries:组合查询
想要一台带NFC功能的 或者 小米的手机 但是不要耳机
SELECT * from product
where (`name` like "%xiaomi%" or `name` like '%nfc%')
AND `name` not LIKE '%erji%'
GET /product/_search
{
"query": {
"constant_score":{
"filter": {
"bool": {
"should":[
{"term":{"name":"xiaomi"}},
{"term":{"name":"nfc"}}
],
"must_not":[
{"term":{"name":"erji"}}
]
}
},
"boost": 1.2
}
}
}
搜索一台"xiaomi nfc phone" 或者 "满足 是phone 并且 price <= 2999"
GET /product/_search
{
"query": {
"constant_score": {
"filter": {
"bool":{
"should":[
{"match_phrase":{"name":"xiaomi nfc phone"}},
{
"bool":{
"must":[
{"term":{"name":"phone"}},
{"range":{"price":{"lte":"2999"}}}
]
}
}
]
}
}
}
}
}
高亮搜索 Highlight search
GET /product/_search
{
"query" : {
"match_phrase" : {
"name" : "nfc phone"
}
},
"highlight":{
"fields":{
"name":{}
}
}
}
返回
"highlight" : {
"name" : [
"xiaomi <em>nfc</em> <em>phone</em>"
]
}
Deep paging图解
- 解释:当你的数据超过1W,不要使用
- 返回结果不要超过1000个,500以下为宜
- 解决办法:
- 尽量避免深度分页查询
- 使用Scroll search(只能下一页,没办法上一页,不适合实时查询)
Scroll search:图解
解决 deep paging问题
GET /product/_search?scroll=1m
{
"query": {
"match_all": {}
}
,"size": 2
}
返回
{
"_scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFGtzWmRxM1VCY1BvN0psOXRPSXNZAAAAAAAARj0WZlhVLUJScjdTS2FkdGN4ZzY4MlA0QQ==",
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "product",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "xiaomi phone",
"desc" : "shouji zhong de zhandouji",
"price" : 3999,
"tags" : [
"xingjiabi",
"fashao",
"buka"
]
}
},
{
"_index" : "product",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"name" : "xiaomi nfc phone",
"desc" : "zhichi quangongneng nfc,shouji zhong de jianjiji",
"price" : 4999,
"tags" : [
"xingjiabi",
"fashao",
"gongjiaoka"
]
}
}
]
}
}
得到scroll_id之后, 再次请求可以拿下一页的数据, scroll不能拿上一页的数据
GET /_search/scroll
{
"scroll":"1m" # 每次查询再次续命1分钟, 不加这个参数, 只能请求一次, 没等过期就清理了
,"scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFGhjWmNxM1VCY1BvN0psOXRsSXUxAAAAAAAARjAWZlhVLUJScjdTS2FkdGN4ZzY4MlA0QQ=="
}
返回
{
"took" : 1,
"timed_out" : false,
"terminated_early" : true,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "product",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.0,
"_source" : {
"name" : "nfc phone",
"desc" : "shouji zhong de hongzhaji",
"price" : 2999,
"tags" : [
"xingjiabi",
"fashao",
"menjinka"
]
}
},
{
"_index" : "product",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.0,
"_source" : {
"name" : "xiaomi erji",
"desc" : "erji zhong de huangmenji",
"price" : 999,
"tags" : [
"low",
"bufangshui",
"yinzhicha"
]
}
}
]
}
}
filter缓存原理:图解
Mapping:
mapping就是ES数据字段field的type元数据,ES在创建索引的时候,dynamic mapping会自动为不同的数据指定相应mapping,mapping中包含了字段的类型、搜索方式(exact value或者full text)、分词器等。
# 查看mapping
GET /product/_mappings
Dynamic mapping
- “Elasticsearch”:text/keyword
- 123456 => long ?为什么不是integer
- 123.123 => double
- true false => boolean
- 2020-05-20 => date
为啥price是long类型而不是integer?
因为es的mapping_type是由JSON分析器检测数据类型,而Json没有隐式类型转换(integer=>long or float=> double),所以dynamic mapping会选择一个比较宽的数据类型。
搜索方式
- exact value 精确匹配:在倒排索引过程中,分词器会将field作为一个整体创建到索引中
- full text全文检索:分词、近义词同义词、混淆词、大小写、词性、过滤、时态转换等(normaliztion)
ES数据类型:
核心类型
- 数字类型:
long
,integer
,short
,byte
,double
,float
,half_float
,scaled_float
- 在满足需求的情况下,尽可能选择范围小的数据类型。
- 字符串:string:
- keyword:不会被分词, 建倒排索引的时候, 用的是整体值. 适用于索引结构化的字段,可以用于过滤、排序、聚合。keyword类型的字段只能通过精确值(exact value)搜索到。Id应该用keyword
- text:当一个字段是要被全文搜索的,比如Email内容、产品描述,这些字段应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text类型的字段不用于排序,很少用于聚合。(解释一下为啥不会为text创建索引:字段数据会占用大量堆空间,尤其是在加载高基数
text
字段时。字段数据一旦加载到堆中,就在该段的生命周期内保持在那里。同样,加载字段数据是一个昂贵的过程,可能导致用户遇到延迟问题。这就是默认情况下禁用字段数据的原因) - 有时,在同一字段中同时具有全文本(
text
)和关键字(keyword
)版本会很有用:一个用于全文本搜索,另一个用于聚合和排序。
- date(时间类型):exact value
- 布尔类型:boolean
- binary(二进制):binary
- range(区间类型):integer_range、float_range、long_range、double_range、date_range
- 复杂类型:
- Object:用于单个JSON对象
- Nested:用于JSON对象数组
- 地理位置:
- Geo-point:纬度/经度积分
- Geo-shape:用于多边形等复杂形状
- 特有类型:
- IP地址:
ip
用于IPv4和IPv6地址 - Completion:提供自动完成建议
- Tocken_count:计算字符串中令牌的数量
- Murmur3:在索引时计算值的哈希并将其存储在索引中
- Annotated-text:索引包含特殊标记的文本(通常用于标识命名实体)
- Percolator:接受来自query-dsl的查询
- Join:为同一索引内的文档定义父/子关系
- Rank features:记录数字功能以提高查询时的点击率。
- Dense vector:记录浮点值的密集向量。
- Sparse vector:记录浮点值的稀疏向量。
- Search-as-you-type:针对查询优化的文本字段,以实现按需输入的完成
- Alias:为现有字段定义别名。
- Flattened:允许将整个JSON对象索引为单个字段。
- Shape:
shape
对于任意笛卡尔几何。 - Histogram:
histogram
用于百分位数聚合的预聚合数值。 - Constant keyword:
keyword
当所有文档都具有相同值时的情况的 专业化。
- IP地址:
- Array(数组):在Elasticsearch中,数组不需要专用的字段数据类型。默认情况下,任何字段都可以包含零个或多个值,但是,数组中的所有值都必须具有相同的数据类型。
- ES 7新增:
- Date_nanos:date plus 纳秒
- Features:
- Vector:as
- 手工创建mapping
- 复杂类型:
PUT /product
{
"mappings": {
"properties": {
"field": {
"mapping_parameter": "parameter_value"
}
}
}
}
Mapping parameters
- index:是否对当前字段创建索引,默认true,如果不创建索引, 该字段不会通过索引被搜索到, 但是仍然会在source元数据中展示
- analyzer:指定分析器(character filter、tokenizer、Token filters)。
- boost:对当前字段相关度的评分权重,默认1, es5废弃
- coerce:是否允许强制类型转换 对于类型为int, 值为1的doc, true的话, “1”和1都能搜到, false的话 “1”不会转换成1, 也就搜不到
- copy_to:可以把单个/多个字段, copy到一个字段里, 然后搜索的时候, 只搜这一个字段就行
# 定义好表结构, field1, field2的内容会映射到field_all
PUT copy_to
{
"mappings": {
"properties": {
"field1": {
"type": "text"
,"copy_to": "field_all"
}
,"field2": {
"type": "text"
,"copy_to": "field_all"
}
,"field_all": {
"type": "text"
}
}
}
}
往copy_to索引里插入一行, field1和field2带值, field_all不用给值
PUT copy_to/_doc/1
{
"field1":"xiaomi"
,"field2":"nfc"
,"field_all":""
}
然后对field_all字段进行搜索
GET copy_to/_search
{
"query": {
"match": {
"field_all": "nfc"
}
}
}
返回
"hits" : [
{
"_index" : "copy_to",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"field1" : "xiaomi",
"field2" : "nfc",
"field_all" : ""
}
}
]
由此可见, field_all在doc里是没有值的, 但是field_all字段对应的倒排索引里是存了field1和field2的分词的
doc_values
正排索引, 类似于mysql索引
为了提升排序和聚合效率,默认true,如果确定不需要对字段进行排序或聚合,也不需要通过脚本访问字段值,则可以禁用doc值以节省磁盘空间
不支持text
和annotated_text, 太过于消耗磁盘和内存
如果一定要根据text字段做聚合操作, 那么就把这个字段设置为 "fielddata":true
dynamic
控制是否可以动态添加新字段 线上索引一般设为strict, 禁止太灵活的用法
- true 新检测到的字段将添加到映射中。(默认)
- false 新检测到的字段将被忽略。这些字段将不会被索引,因此将无法搜索,但仍会出现在_source返回的匹配项中。这些字段不会添加到映射中,必须显式添加新字段。
- strict 如果检测到新字段,则会引发异常并拒绝文档。必须将新字段显式添加到映射中
eager_global_ordinals
用于聚合的字段上, 优化聚合性能 , 用于热数据
eager_global_ordinals不适用于Frozen indices
什么是 " Frozen indices " :
- Frozen indices(冻结索引):有些索引使用率很高,会被保存在内存中,有些使用率特别低,宁愿在使用的时候重新创建,在使用完毕后丢弃数据
- Frozen indices的数据命中频率小,是绝对的冷数据,不会被保存在内存中,堆空间占用比普通索引少得多
- Frozen indices是只读的,请求可能是秒级或者分钟级。
enable 是否创建倒排索引
可以对字段操作,也可以对索引操作,如果不创建索引,仍然可以检索并在_source元数据中展示,谨慎使用,该状态无法修改。
enable:false 和 index: false的意思差不多
# enable用于整个索引
PUT my_index {
"mappings": {
"enabled": false
}
}
# enable用于单个字段
PUT my_index{
"mappings": {
"properties": {
"session_data": {
"type": "object",
"enabled": false
}
}
}
}
fielddata
查询时内存数据结构,在首次用当前字段聚合、排序或者在脚本中使用时,需要字段为fielddata数据结构,并且创建倒排索引保存到堆中
一般来说, 聚合是不支持text
和annotated_text, 太过于消耗磁盘和内存
但如果一定要根据text字段做聚合操作, 那么就把这个字段设置为 "fielddata":true
但是这种方式性能很低, 建议再创建一个keyword嵌套的子字段
fields
给field创建多字段,用于不同目的(全文检索text或者聚合分析排序keyword )
format:格式化
"date": {
"type": "date",
"format": "yyyy-MM-dd"
}
ignore_above
修饰keyword类型的字段, 超过长度将被忽略
ignore_malformed
忽略类型错误
PUT my_index{
"mappings": {
"properties": {
"number_one": {
"type": "integer",
"ignore_malformed": true
},
"number_two": {
"type": "integer"
}
}
}
}
// 虽然有异常 但是不抛出
PUT my_index/_doc/1
{
"text": "Some text value",
"number_one": "foo"
}
// 数据格式不对
PUT my_index/_doc/2
{
"text": "Some text value",
"number_two": "foo"
}
index_options:控制将哪些信息添加到反向索引中以进行搜索和突出显示。仅用于text字段
Index_phrases:提升exact_value查询速度,但是要消耗更多磁盘空间
Index_prefixes:前缀搜索
- min_chars:前缀最小长度,>0,默认2(包含)
- max_chars:前缀最大长度,<20,默认5(包含)
"index_prefixes": {
"min_chars" : 1,
"max_chars" : 10
}
meta:附加元数据
normalizer:
norms:是否禁用评分(在filter和聚合字段上应该禁用)。
null_value:为null值设置默认值
如果doc的field1字段是null, 就把"0"赋值给该doc的field1字段
PUT my_index
{
"mappings": {
"properties": {
"field1": {
"type": "text"
"null_value": "0"
}
}
}
}
position_increment_gap:?
proterties:除了mapping还可用于object的属性设置
search_analyzer:设置单独的查询时分析器:
PUT my_index{
"settings": {
"analysis": {
"filter": {
"autocomplete_filter": {
"type": "edge_ngram",
"min_gram": 1,
"max_gram": 20
}
},
"analyzer": {
"autocomplete": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"autocomplete_filter"
]
}
}
}
},
"mappings": {
"properties": {
"text": {
"type": "text",
"analyzer": "autocomplete", // 建索引的时候, 用的分词器
"search_analyzer": "standard" // search的时候用的分词器
}
}
}
}
PUT my_index/_doc/1
{
"text": "Quick Brown Fox"
}
GET my_index/_search
{
"query": {
"match": {
"text": {
"query": "Quick Br",
"operator": "and"
}
}
}
}
similarity:为字段设置相关度算法,支持BM25、claassic(TF-IDF)、boolean
store:设置字段是否仅查询
term_vector:
聚合查询
demo1: group by
以tag维度每个产品的数量,即每个标签, 在的基础上增加筛选条件:统计价格大于1999的数据
GET /product/_search
{
"query": {
"bool": {
"filter": [
{
"range": {
"price": {
"gt": 1999
}
}
}
]
}
},
"aggs": {
"aggName": {
"terms": {
"field": "tags.keyword"
}
}
},
"size": 0
}
返回
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"aggName" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [ {
"key" : "fashao",
"doc_count" : 3
}, {
"key" : "xingjiabi",
"doc_count" : 3
}, {
"key" : "buka",
"doc_count" : 1
}, {
"key" : "gongjiaoka",
"doc_count" : 1
}, {
"key" : "menjinka",
"doc_count" : 1
}
]
}
}
}
demo2: avg
基于tags中的每个值, 求出平均价格
GET /product/_search
{
"aggs": {
"myAVG": {
"terms": {
"field": "tags.keyword", // 相当于mysql中的GROUP BY tags.keyword
"order": {
"avg_price": "desc"
}
},
"aggs": {
"avg_price": {
"avg": {
"field": "price" // 相当于mysql中的SELECT AVG(price) FROM product
}
}
}
}
},
"size": 0
}
返回
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"myAVG" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 1,
"buckets" : [
{
"key" : "gongjiaoka",
"doc_count" : 1,
"avg_price" : {
"value" : 4999.0
}
},
{
"key" : "buka",
"doc_count" : 1,
"avg_price" : {
"value" : 3999.0
}
},
{
"key" : "fashao",
"doc_count" : 3,
"avg_price" : {
"value" : 3999.0 // ( 2999 + 3999 + 4999 ) / 3 = 3999
}
},
{
"key" : "xingjiabi",
"doc_count" : 3,
"avg_price" : {
"value" : 3999.0
}
},
{
"key" : "menjinka",
"doc_count" : 1,
"avg_price" : {
"value" : 2999.0
}
},
{
"key" : "bufangshui",
"doc_count" : 1,
"avg_price" : {
"value" : 999.0
}
},
{
"key" : "low",
"doc_count" : 1,
"avg_price" : {
"value" : 999.0
}
},
{
"key" : "yinzhicha",
"doc_count" : 1,
"avg_price" : {
"value" : 999.0
}
},
{
"key" : "lowbee",
"doc_count" : 1,
"avg_price" : {
"value" : 399.0
}
},
{
"key" : "xuhangduan",
"doc_count" : 1,
"avg_price" : {
"value" : 399.0
}
}
]
}
}
}
分组聚合
按照千元机:1000以下 中端机:2000-3000 高端机:3000以上分组聚合,分别计算数量
GET /product/_search
{
"aggs": {
"aggTags": {
"range": {
"field": "price",
"ranges": [
{
"from": 100,
"to": 1000
},{
"from": 1000,
"to": 2000
},{
"from": 3000
}
]
},
"aggs": {
"priceAgg": {
"avg": {
"field": "price" // SELECT AVG(price)
}
}
}
}
},
"size": 0
}
返回
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"aggTags" : {
"buckets" : [
{
"key" : "100.0-1000.0",
"from" : 100.0,
"to" : 1000.0,
"doc_count" : 2,
"priceAgg" : {
"value" : 699.0
}
},
{
"key" : "1000.0-2000.0",
"from" : 1000.0,
"to" : 2000.0,
"doc_count" : 0,
"priceAgg" : {
"value" : null
}
},
{
"key" : "3000.0-*",
"from" : 3000.0,
"doc_count" : 2,
"priceAgg" : {
"value" : 4499.0
}
}
]
}
}
}