2.2.创建索引

2.2.1.语法

创建索引的请求格式:

  • 请求方式:PUT

  • 请求路径:/索引库名

  • 请求参数:json格式:

    {
    "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
    }
    }
    • settings:索引库的设置

      • number_of_shards:分片数量
      • number_of_replicas:副本数量

2.3.查看索引设置

语法

Get请求可以帮我们查看索引信息,格式:

GET /索引库名

2.4.删除索引

删除索引使用DELETE请求

语法

DELETE /索引库名

2.5.映射配置

索引有了,接下来肯定是添加数据。但是,在添加数据之前必须定义映射。

映射是定义文档的过程,文档包含哪些字段,这些字段是否保存,是否索引,是否分词等

2.5.1.创建映射字段

语法

请求方式依然是PUT

PUT /索引库名/_mapping/类型名称
{
"properties": {
"字段名": {
"type": "类型",
"index": true,
"store": true,
"analyzer": "分词器"
}
}
}
  • 类型名称:就是前面将的type的概念,类似于数据库中的不同表

    字段名:任意填写 ,可以指定许多属性,例如:
  • type:类型,可以是text、long、short、date、integer、object等
  • index:是否索引,默认为true
  • store:是否存储,默认为false
  • analyzer:分词器,这里的ik_max_word即使用ik分词器

示例

发起请求:

PUT flytest/_mapping/goods
{
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"images": {
"type": "keyword",
"index": "false"
},
"price": {
"type": "float"
}
}
}

响应结果:

{
"acknowledged": true
}

2.5.2.查看映射关系

语法:

GET /索引库名/_mapping

示例:

GET /flytest/_mapping

响应:

{
"flytest": {
"mappings": {
"goods": {
"properties": {
"images": {
"type": "keyword",
"index": false
},
"price": {
"type": "float"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
}
}

2.5.3.字段属性详解

2.5.3.1.type

Elasticsearch中支持的数据类型非常丰富:

  • String类型,又分两种:

    • text:可分词,不可参与聚合
    • keyword:不可分词,数据会作为完整字段进行匹配,可以参与聚合
  • Numerical:数值类型,分两类

    • 基本数据类型:long、interger、short、byte、double、float、half_float
    • 浮点数的高精度类型:scaled_float
      • 需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。
  • Date:日期类型

    elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间。

2.5.3.2.index

index影响字段的索引情况。

  • true:字段会被索引,则可以用来进行搜索。默认值就是true
  • false:字段不会被索引,不能用来搜索

index的默认值就是true,也就是说你不进行任何配置,所有字段都会被索引。

但是有些字段是我们不希望被索引的,比如商品的图片信息,就需要手动设置index为false。

2.5.3.3.store

是否将数据进行额外存储。

在学习lucene和solr时,我们知道如果一个字段的store设置为false,那么在文档列表中就不会有这个字段的值,用户的搜索结果中不会显示出来。

但是在Elasticsearch中,即便store设置为false,也可以搜索到结果。

原因是Elasticsearch在创建文档索引时,会将文档中的原始数据备份,保存到一个叫做_source的属性中。而且我们可以通过过滤_source来选择哪些要显示,哪些不显示。

而如果设置store为true,就会在_source以外额外存储一份数据,多余,因此一般我们都会将store设置为false,事实上,store的默认值就是false。

2.5.3.4.boost

激励因子,这个与lucene中一样

2.6.新增数据

2.6.1.随机生成id

通过POST请求,可以向一个已经存在的索引库中添加数据。

语法:

POST /索引库名/类型名
{
"key":"value"
}

示例:

POST /flytest/goods/
{
"title":"小米手机",
"images":"1.jpg",
"price":999.00
}

响应:

{
"_index": "flytest",
"_type": "goods",
"_id": "AWhK-5sLs9MXwc4ybvd6",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}

通过kibana查看数据:

get _search
{
"query":{
"match_all":{}
}
}
{
"took": 10,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": ".kibana",
"_type": "config",
"_id": "5.6.12",
"_score": 1,
"_source": {
"buildNum": 15653
}
},
{
"_index": "flytest",
"_type": "goods",
"_id": "AWhK-5sLs9MXwc4ybvd6",
"_score": 1,
"_source": {
"title": "小米手机",
"images": "1.jpg",
"price": 999
}
}
]
}
}
  • _source:源文档信息,所有的数据都在里面。
  • _id:这条文档的唯一标示,与文档自己的id字段没有关联

2.6.2.自定义id

如果我们想要自己新增的时候指定id,可以这么做:

POST /索引库名/类型/id值
{
...
}

示例:

POST /flytest/goods/2
{
"title":"大米手机",
"images":"2.jpg",
"price":2899.00
}

得到的数据:

{
"_index": "flytest",
"_type": "goods",
"_id": "2",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}

2.6.3.智能判断

在学习Solr时,在新增数据时,只能使用提前配置好映射属性的字段,否则就会报错。

在Elasticsearch中不需要给索引库设置任何mapping映射,它也可以根据你输入的数据来判断类型,动态添加数据映射。

测试一下:

POST /flytest/goods/3
{
"title":"超米手机",
"images":"3.jpg",
"price":2899.00,
"stock": 200,
"saleable":true
}

额外添加了stock库存,和saleable是否上架两个字段。

在看下索引库的映射关系: GET flytest/_mapping

{
"flytest": {
"mappings": {
"goods": {
"properties": {
"image": {
"type": "keyword",
"index": false
},
"images": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"price": {
"type": "float"
},
"saleable": {
"type": "boolean"
},
"stock": {
"type": "long"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
}
}

stock和saleable都被成功映射了。

2.7.修改数据

把新增的请求方式改为PUT,就是修改了。不过修改必须指定id,

  • id对应文档存在,则修改
  • id对应文档不存在,则新增

2.8.删除数据

删除使用DELETE请求,同样,需要根据id进行删除:

语法

DELETE /索引库名/类型名/id值

3.查询

  • 基本查询
  • _source过滤
  • 结果过滤
  • 高级查询
  • 排序

3.1.基本查询:

基本语法

GET /索引库名/_search
{
"query":{
"查询类型":{
"查询条件":"查询条件值"
}
}
}

这里的query代表一个查询对象,里面可以有不同的查询属性

  • 查询类型:

    • 例如:match_all, matchterm , range

3.1.1 查询所有(match_all)

示例:

GET /heima/_search
{
"query":{
"match_all": {}
}
}

结果:

{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1,
"hits": [
{
"_index": "flytest",
"_type": "goods",
"_id": "AWhK-5sLs9MXwc4ybvd6",
"_score": 1,
"_source": {
"title": "小米手机",
"images": "1.jpg",
"price": 999
}
},
{
"_index": "flytest",
"_type": "goods",
"_id": "2",
"_score": 1,
"_source": {
"title": "大米手机",
"images": "2.jpg",
"price": 2899
}
},
{
"_index": "flytest",
"_type": "goods",
"_id": "3",
"_score": 1,
"_source": {
"title": "超大米手机",
"images": "3.jpg",
"price": 3899,
"stock": 100,
"saleable": true
}
}
]
}
}
  • took:查询花费时间,单位是毫秒
  • time_out:是否超时
  • _shards:分片信息
  • hits:搜索结果总览对象
    • total:搜索到的总条数
    • max_score:所有结果中文档得分的最高分
    • hits:搜索结果的文档对象数组,每个元素是一条搜索到的文档信息
      • _index:索引库
      • _type:文档类型
      • _id:文档id
      • _score:文档得分
      • _source:文档的源数据

3.1.2 匹配查询(match)

先加入一条数据,便于测试:

PUT /flytest/goods/3
{
"title":"小米电视4A",
"images":"4.jpg",
"price":3899.00
}
  • or关系

match类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是or的关系

GET /flytest/_search
{
"query": {
"match": {
"title": "小米电视"
}
}
}
  • and关系

某些情况下,我们需要更精确查找,我们希望这个关系变成and,可以这样做:

GET /flytest/_search
{
"query": {
"match": {
"title":{
"query": "小米电视"
, "operator": "and"
}
}
}

match 查询支持 minimum_should_match 最小匹配参数, 这让我们可以指定必须匹配的词项数用来表示一个文档是否相关。我们可以将其设置为某个具体数字,更常用的做法是将其设置为一个百分数,因为我们无法控制用户搜索时输入的单词数量:

GET /flytest/_search
{
"query": {
"match": {
"title":{
"query": "小米曲面电视",
"minimum_should_match": "75%"
}
}
}
}

本例中,搜索语句可以分为3个词,这里采用最小品牌数:75%,只要匹配到总词条数量的75%即可,这里3*75% 约等于2。所以只要包含2个词条就算满足条件了。

3.1.3 多字段查询(multi_match)

multi_matchmatch类似,不同的是它可以在多个字段中查询

GET /flytest/_search
{
"query": {
"multi_match": {
"query": "小米",
"fields": ["title","subTitle"]
}
}
}

本例中,在title字段和subtitle字段中查询小米这个词

3.1.4 词条匹配(term)

term 查询被用于精确值 匹配,这些精确值可能是数字、时间、布尔或者那些未分词的字符串

GET /flytest/_search
{
"query": {
"term": {
"price": "999.00"
}
}
}

3.1.5 多词条精确匹配(terms)

terms 查询和 term 查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件:

GET /flytest/_search
{
"query": {
"terms": {
"price": [999.00,2899.00,3899.00]
}
}
}

3.2.结果过滤

3.2.1.直接指定字段

示例:

GET /flytest/_search
{
"_source": [
"title",
"price"
],
"query": {
"term": {
"price": {
"value": "2899"
}
}
}
}

3.2.2.指定includes和excludes

我们也可以通过:

  • includes:来指定想要显示的字段
  • excludes:来指定不想要显示的字段

二者都是可选的。

示例:

GET /flytest/_search
{
"_source": {
"includes": [
"title",
"price"
]
},
"query": {
"term": {
"price": {
"value": "2899"
}
}
}
}

3.3 高级查询

3.3.1 布尔组合(bool)

bool把各种其它查询通过must(与)、must_not(非)、should(或)的方式进行组合

GET /flytest/_search
{
"query": {
"bool": {
"must": {"match":{"title":"大米"}},
"must_not": {"match":{"title":"电视"}},
"should": {"match":{"title":"手机"}}
}
}
}

3.3.2 范围查询(range)

range 查询找出那些落在指定区间内的数字或者时间

GET /flytest/_search
{
"query": {
"range": {
"price": {
"gte": 1000.0,
"lte": 3000.0
}
}
}
}

range查询允许以下字符:

操作符 说明
gt 大于
gte 大于等于
lt 小于
lte 小于等于

3.3.3 模糊查询(fuzzy)

我们新增一个商品:

POST /flytest/goods/4
{
"title":"apple手机",
"images":"22.jpg",
"price":6899.00
}

fuzzy 查询是 term 查询的模糊等价。它允许用户搜索词条与实际词条的拼写出现偏差,但是偏差的编辑距离不得超过2:

GET /flytest/_search
{
"query": {
"fuzzy": {
"title": "ipple"
}
}
}

上面的查询,也能查询到apple手机

我们可以通过fuzziness来指定允许的编辑距离:

GET /flytest/_search
{
"query": {
"fuzzy": {
"title": {
"value": "appla",
"fuzziness": 1
}
}
}
}

3.4 过滤(filter)

条件查询中进行过滤

所有的查询都会影响到文档的评分及排名。如果我们需要在查询结果中进行过滤,并且不希望过滤条件影响评分,那么就不要把过滤条件作为查询条件来用。而是使用filter方式:

GET /flytest/_search
{
"query": {
"bool": {
"must": {
"match": {
"title": "手机"
}
},
"filter": {
"range": {
"price": {
"gte": 2000,
"lte": 4000
}
}
}
}
}
}

注意:filter中还可以再次进行bool组合条件过滤。

无查询条件,直接过滤

如果一次查询只有过滤,没有查询条件,不希望进行评分,我们可以使用constant_score取代只有 filter 语句的 bool 查询。在性能上是完全相同的,但对于提高查询简洁性和清晰度有很大帮助。

GET /flytest/_search
{
"query": {
"constant_score": {
"filter": {
"range": {
"price": {
"gte": 2000,
"lte": 4000
}
}
}
}
}
}

3.5 排序

3.4.1 单字段排序

sort 可以让我们按照不同的字段进行排序,并且通过order指定排序的方式

GET /flytest/_search
{
"query": {
"match": {
"title": "小米手机"
}
},
"sort": [
{
"price": {
"order": "desc"
}
}
]
}

3.4.2 多字段排序

假定我们想要结合使用 price和 _score(得分) 进行查询,并且匹配的结果首先按照价格排序,然后按照相关性得分排序:

GET /flytest/_search
{
"query": {
"bool": {
"must": {
"match": {
"title": "小米手机"
}
},
"filter": {
"range": {
"price": {
"gte": 2000,
"lte": 4000
}
}
}
}
},
"sort": [
{
"price": {
"order": "desc"
},
"_score": {
"order": "desc"
}
}
]
}

4. 聚合aggregations

聚合可以让我们极其方便的实现对数据的统计、分析。

4.1 基本概念

Elasticsearch中的聚合,包含多种类型,最常用的两种,一个叫,一个叫度量

桶(bucket)

桶的作用,是按照某种方式对数据进行分组,每一组数据在ES中称为一个,例如我们根据国籍对人划分,可以得到中国桶英国桶日本桶……或者我们按照年龄段对人进行划分:010,1020,2030,3040等。

Elasticsearch中提供的划分桶的方式有很多:

  • Date Histogram Aggregation:根据日期阶梯分组,例如给定阶梯为周,会自动每周分为一组
  • Histogram Aggregation:根据数值阶梯分组,与日期类似
  • Terms Aggregation:根据词条内容分组,词条内容完全匹配的为一组
  • Range Aggregation:数值和日期的范围分组,指定开始和结束,然后按段分组
  • ……

综上所述,我们发现bucket aggregations 只负责对数据进行分组,并不进行计算,因此往往bucket中往往会嵌套另一种聚合:metrics aggregations即度量

度量(metrics)

分组完成以后,我们一般会对组中的数据进行聚合运算,例如求平均值、最大、最小、求和等,这些在ES中称为度量

比较常用的一些度量聚合方式:

  • Avg Aggregation:求平均值
  • Max Aggregation:求最大值
  • Min Aggregation:求最小值
  • Percentiles Aggregation:求百分比
  • Stats Aggregation:同时返回avg、max、min、sum、count等
  • Sum Aggregation:求和
  • Top hits Aggregation:求前几
  • Value Count Aggregation:求总数
  • ……

为了测试聚合,我们先批量导入一些数据

创建索引:

PUT /cars
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"transactions": {
"properties": {
"color": {
"type": "keyword"
},
"make": {
"type": "keyword"
}
}
}
}
}

注意:在ES中,需要进行聚合、排序、过滤的字段其处理方式比较特殊,因此不能被分词。这里我们将color和make这两个文字类型的字段设置为keyword类型,这个类型不会被分词,将来就可以参与聚合

导入数据

POST /cars/transactions/_bulk
{ "index": {}}
{ "price" : 10000, "color" : "red", "make" : "honda", "sold" : "2014-10-28" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }
{ "index": {}}
{ "price" : 30000, "color" : "green", "make" : "ford", "sold" : "2014-05-18" }
{ "index": {}}
{ "price" : 15000, "color" : "blue", "make" : "toyota", "sold" : "2014-07-02" }
{ "index": {}}
{ "price" : 12000, "color" : "green", "make" : "toyota", "sold" : "2014-08-19" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }
{ "index": {}}
{ "price" : 80000, "color" : "red", "make" : "bmw", "sold" : "2014-01-01" }
{ "index": {}}
{ "price" : 25000, "color" : "blue", "make" : "ford", "sold" : "2014-02-12" }

4.2 聚合为桶

首先,我们按照 汽车的颜色color来划分

GET /cars/_search
{
"size" : 0,
"aggs" : {
"popular_colors" : {
"terms" : {
"field" : "color"
}
}
}
}
  • size: 查询条数,这里设置为0,因为我们不关心搜索到的数据,只关心聚合结果,提高效率
  • aggs:声明这是一个聚合查询,是aggregations的缩写
    • popular_colors:给这次聚合起一个名字,任意。

      • terms:划分桶的方式,这里是根据词条划分

        • field:划分桶的字段

结果:

{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 8,
"max_score": 0,
"hits": []
},
"aggregations": {
"popular_colors": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "red",
"doc_count": 4
},
{
"key": "blue",
"doc_count": 2
},
{
"key": "green",
"doc_count": 2
}
]
}
}
}
  • hits:查询结果为空,因为我们设置了size为0
  • aggregations:聚合的结果
  • popular_colors:我们定义的聚合名称
  • buckets:查找到的桶,每个不同的color字段值都会形成一个桶
    • key:这个桶对应的color字段的值
    • doc_count:这个桶中的文档数量

通过聚合的结果我们发现,目前红色的小车比较畅销!

4.3 桶内度量

前面的例子告诉我们每个桶里面的文档数量,这很有用。 但通常,我们的应用需要提供更复杂的文档度量。 例如,每种颜色汽车的平均价格是多少?

因此,我们需要告诉Elasticsearch使用哪个字段使用何种度量方式进行运算,这些信息要嵌套在内,度量的运算会基于内的文档进行

现在,我们为刚刚的聚合结果添加 求价格平均值的度量:

GET /cars/_search
{
"size" : 0,
"aggs" : {
"popular_colors" : {
"terms" : {
"field" : "color"
},
"aggs":{
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
  • aggs:我们在上一个aggs(popular_colors)中添加新的aggs。可见度量也是一个聚合,度量是在桶内的聚合
  • avg_price:聚合的名称
  • avg:度量的类型,这里是求平均值
  • field:度量运算的字段

结果:

...
"aggregations": {
"popular_colors": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "red",
"doc_count": 4,
"avg_price": {
"value": 32500
}
},
{
"key": "blue",
"doc_count": 2,
"avg_price": {
"value": 20000
}
},
{
"key": "green",
"doc_count": 2,
"avg_price": {
"value": 21000
}
}
]
}
}
...

可以看到每个桶中都有自己的avg_price字段,这是度量聚合的结果

4.4 桶内嵌套桶

刚刚的案例中,我们在桶内嵌套度量运算。事实上桶不仅可以嵌套运算, 还可以再嵌套其它桶。也就是说在每个分组中,再分更多组。

比如:我们想统计每种颜色的汽车中,分别属于哪个制造商,按照make字段再进行分桶

GET /cars/_search
{
"size" : 0,
"aggs" : {
"popular_colors" : {
"terms" : {
"field" : "color"
},
"aggs":{
"avg_price": {
"avg": {
"field": "price"
}
},
"maker":{
"terms":{
"field":"make"
}
}
}
}
}
}
  • 原来的color桶和avg计算我们不变
  • maker:在嵌套的aggs下新添一个桶,叫做maker
  • terms:桶的划分类型依然是词条
  • filed:这里根据make字段进行划分

部分结果:

...
{"aggregations": {
"popular_colors": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "red",
"doc_count": 4,
"maker": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "honda",
"doc_count": 3
},
{
"key": "bmw",
"doc_count": 1
}
]
},
"avg_price": {
"value": 32500
}
},
{
"key": "blue",
"doc_count": 2,
"maker": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "ford",
"doc_count": 1
},
{
"key": "toyota",
"doc_count": 1
}
]
},
"avg_price": {
"value": 20000
}
},
{
"key": "green",
"doc_count": 2,
"maker": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "ford",
"doc_count": 1
},
{
"key": "toyota",
"doc_count": 1
}
]
},
"avg_price": {
"value": 21000
}
}
]
}
}
}
...
  • 我们可以看到,新的聚合maker被嵌套在原来每一个color的桶中。
  • 每个颜色下面都根据 make字段进行了分组
  • 我们能读取到的信息:
    • 红色车共有4辆
    • 红色车的平均售价是 $32,500 美元。
    • 其中3辆是 Honda 本田制造,1辆是 BMW 宝马制造。

4.5.划分桶的其它方式

前面讲了,划分桶的方式有很多,例如:

  • Date Histogram Aggregation:根据日期阶梯分组,例如给定阶梯为周,会自动每周分为一组
  • Histogram Aggregation:根据数值阶梯分组,与日期类似
  • Terms Aggregation:根据词条内容分组,词条内容完全匹配的为一组
  • Range Aggregation:数值和日期的范围分组,指定开始和结束,然后按段分组

刚刚的案例中,我们采用的是Terms Aggregation,即根据词条划分桶。

接下来,我们再学习几个比较实用的:

4.5.1.阶梯分桶Histogram

原理:

histogram是把数值类型的字段,按照一定的阶梯大小进行分组。你需要指定一个阶梯值(interval)来划分阶梯大小。

举例:

比如你有价格字段,如果你设定interval的值为200,那么阶梯就会是这样的:

0,200,400,600,...

上面列出的是每个阶梯的key,也是区间的启点。

如果一件商品的价格是450,会落入哪个阶梯区间呢?计算公式如下:

bucket_key = Math.floor((value - offset) / interval) * interval + offset

value:就是当前数据的值,本例中是450

offset:起始偏移量,默认为0

interval:阶梯间隔,比如200

因此你得到的key = Math.floor((450 - 0) / 200) * 200 + 0 = 400

操作一下:

比如,我们对汽车的价格进行分组,指定间隔interval为5000:

GET /cars/_search
{
"size":0,
"aggs":{
"price":{
"histogram": {
"field": "price",
"interval": 5000
}
}
}
}

结果:

{
"took": 21,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 8,
"max_score": 0,
"hits": []
},
"aggregations": {
"price": {
"buckets": [
{
"key": 10000,
"doc_count": 2
},
{
"key": 15000,
"doc_count": 1
},
{
"key": 20000,
"doc_count": 2
},
{
"key": 25000,
"doc_count": 1
},
{
"key": 30000,
"doc_count": 1
},
{
"key": 35000,
"doc_count": 0
},
{
"key": 40000,
"doc_count": 0
},
{
"key": 45000,
"doc_count": 0
},
{
"key": 50000,
"doc_count": 0
},
{
"key": 55000,
"doc_count": 0
},
{
"key": 60000,
"doc_count": 0
},
{
"key": 65000,
"doc_count": 0
},
{
"key": 70000,
"doc_count": 0
},
{
"key": 75000,
"doc_count": 0
},
{
"key": 80000,
"doc_count": 1
}
]
}
}
}

你会发现,中间有大量的文档数量为0 的桶,看起来很丑。

我们可以增加一个参数min_doc_count为1,来约束最少文档数量为1,这样文档数量为0的桶会被过滤

示例:

GET /cars/_search
{
"size":0,
"aggs":{
"price":{
"histogram": {
"field": "price",
"interval": 5000,
"min_doc_count": 1
}
}
}
}

结果:

{
"took": 15,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 8,
"max_score": 0,
"hits": []
},
"aggregations": {
"price": {
"buckets": [
{
"key": 10000,
"doc_count": 2
},
{
"key": 15000,
"doc_count": 1
},
{
"key": 20000,
"doc_count": 2
},
{
"key": 25000,
"doc_count": 1
},
{
"key": 30000,
"doc_count": 1
},
{
"key": 80000,
"doc_count": 1
}
]
}
}
}

4.5.2.范围分桶range

范围分桶与阶梯分桶类似,也是把数字按照阶段进行分组,只不过range方式需要你自己指定每一组的起始和结束大小。

Elasticsearch基本用法(1)--原生操作的更多相关文章

  1. Elasticsearch SQL用法详解

    Elasticsearch SQL用法详解  mp.weixin.qq.com 本文详细介绍了不同版本中Elasticsearch SQL的使用方法,总结了实际中常用的方法和操作,并给出了几个具体例子 ...

  2. elasticsearch 5.0 获取 TransportClient 操作客户端java API

    本文转载自:http://blog.csdn.net/likui1314159/article/details/53233881 elasticsearch 5.0 获取 TransportClien ...

  3. ElasticStack学习(四):ElasticSearch文档使用与操作

    一.文档的CRUD介绍 ElasticSearch中存在五种操作,分别如下: 1.Index 该操作表示:如果文档的ID不存在,则创建新的文档.若有相同的ID,先删除现有文档,然后再创建新的文档,同时 ...

  4. jdbc原生操作数据库

    jdbc原生操作数据库流程: 第一步:Class.forName()加载数据库连接驱动: 第二步:DriverManager.getConnection()获取数据连接对象; 第三步:根据 SQL 获 ...

  5. 工具库用久了,你还会原生操作 Cookie 吗?

    用得好了,工具库和框架确实是一大助力,但就怕我们会因此习惯了走捷径,而忘了自己的根本依靠是什么. 前言 前端技术的飞速发展,给从业人员不可避免地带来了"疲劳"感,我们常常会感叹学不 ...

  6. Elasticsearch基本用法(2)--Spring Data Elasticsearch

    Spring Data Elasticsearch是Spring Data项目下的一个子模块. 查看 Spring Data的官网:http://projects.spring.io/spring-d ...

  7. Elasticsearch常见用法-入门

    前台启动 默认是只有本地可以访问 ./bin/elasticsearch 远程访问 修改elasticsearch.yml,把network.host(注意配置文件格式不是以 # 开头的要空一格, : ...

  8. Mongodb基础用法及查询操作[转载]

    插入多条测试数据> for(i=1;i<=1000;i++){... db.blog.insert({"title":i,"content":&qu ...

  9. Elasticsearch笔记五之java操作es

    Java操作es集群步骤1:配置集群对象信息:2:创建客户端:3:查看集群信息 1:集群名称 默认集群名为elasticsearch,如果集群名称和指定的不一致则在使用节点资源时会报错. 2:嗅探功能 ...

随机推荐

  1. 学react的第一天

    属性 class = className for = htmlFrom jsx语法被编译了,所以可以在return里写html标签 react的属性 constructor(props){ super ...

  2. :单件模式:Singleton

    #ifndef __SINGLETON_H__ #define __SINGLETON_H__ class Singleton { private: static Singleton* instanc ...

  3. 无法获取 vmci 驱动程序版本: 句柄无效

    https://jingyan.baidu.com/article/a3a3f811ea5d2a8da2eb8aa1.html 将 vmci0.present = "TURE" 改 ...

  4. STA/LTA方法

    STA是用于捕捉地震信号的时间窗,因此STA越短,就对短周期的地震信号捕捉越有效:LTA是用于衡量时间窗内的平均噪声,STA/LTA就可以根据周围环境噪声程度自适应地调整其对于某一类型地震信号的敏感度 ...

  5. C++中数组定义及初始化

    一.一维数组 静态 int array[100]; 定义了数组array,并未对数组进行初始化 静态 int array[100] = {1,2}: 定义并初始化了数组array 动态 int* ar ...

  6. L319 Zigbee test coding- field test fail-base on EFR32MG1

    1 Test coding Zigbee  test of Tx power and frequency for every channel. Testing Procedure1) Power up ...

  7. Delphi 10.3实现Android App的动态权限申请

    Delphi 10.3 RIO发布近两个月,针对Google Play的要求,完美实现了对Android 8的支持,即对Android API Level 26的支持.这支持当中,最主要的得算是动态申 ...

  8. 常见无线DOS攻击

    记录下自己最近一段时间对无线渗透学习的笔记. 无线DOS就是无线拒绝服务攻击.主要包括以下几种攻击类型:Auth Dos攻击.Deauth Flood攻击.Disassociate攻击及RF干扰攻击等 ...

  9. python--Selenium-模拟浏览器

    python--Selenium-模拟浏览器基本使用from selenium import webdriverfrom selenium.webdriver.common.by import Byf ...

  10. Python 面向对象和面向过程对比

    # 大象装冰箱 # 脚本, 此时代码是最简单的. 不需要构思整个程序的概况 print("开门") print("装大象") print("关门&qu ...