码农日记

薄洪涛的个人博客

Elasticsearch按照日期聚合

我们现在做的是医疗的业务,有个需求是这样的,查询出某位医生前七天的坐诊记录,并且,医生的坐诊记录是不连续的,这样就需要写一个dsl语句来实现es库的搜索

首先我使用了es库中的聚合功能,按照日期去聚合,相当于mysql中的group by,查询语句和结果是这样的

{
	"query": {
		"match": {
			"ysdm": "000485"
		}
	},
	"aggs": {
		"jzrq": {
			"date_histogram": {
				"field": "jzrq",
				"format": "yyyy-MM-dd",
				"interval": "day",
				"min_doc_count": 1,
				"order": {
					"_key": "desc"
				}
			}
		}
	}
}

我们这里指定的医生代码,然后按照就诊日期去分组,这里的出的聚合数据我们是没办法指定size的,所以只能通过日期去限制了,从结果中拿到7天的数据,他这里的聚合实际上是根据query中的条件拿到数据,再执行的聚合

返回结果如下,敏感信息我已经用xx代替:

{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": xx,
        "max_score": xx,
        "hits": [
            {
                "_index": "xx",
                "_type": "xx",
                "_id": "xx",
                "_score": 6.271472,
                "_source": {
                    "jzid": "xx",
                    "jzrq": "2019-05-14T09:07:29+08:00",
                    "ksdm": "xx",
                    "ksmc": "xx",
                    "ysdm": "xx",
                    "ysxm": "xx",
                    "blh": "xx",
                    "kh": "xx",
                    "brxm": "xx",
                    "diaginfo": "屈光不正;",
                    "zydm": "xx",
                    "zymc": "xx",
                    "vapphisid": "45287777",
                    "vappregid": "xx",
                    "csrq": "xx0",
                    "age": "",
                    "xb": "0",
                    "xb1": "男",
                    "ybh": "",
                    "sfzh": "xx",
                    "contactname": "xx",
                    "contactphone": "x",
                    "contactidcard": "x",
                    "vprovince": "x",
                    "vcity": "朝阳市",
                    "dz": "朝阳县",
                    "vbjhlcode": ""
                }
            }
        ]
    },
    "aggregations": {
        "jzrq": {
            "buckets": [
                {
                    "key_as_string": "2019-12-26",
                    "key": 1577318400000,
                    "doc_count": 2
                },
                {
                    "key_as_string": "2019-12-17",
                    "key": 1576540800000,
                    "doc_count": 43
                },
                {
                    "key_as_string": "2019-12-12",
                    "key": 1576108800000,
                    "doc_count": 1
                }
            ]
        }
    }
}

可以看到,我们会得到es库中的搜索结果和聚合信息,但是我们只想要聚合信息,不想要搜索结果,这里我们加一个size:0来去掉搜索结果,语句如下

{
	"query": {
		"match": {
			"ysdm": "000485"
		}
	},
	"aggs": {
		"jzrq": {
			"date_histogram": {
				"field": "jzrq",
				"format": "yyyy-MM-dd",
				"interval": "day",
				"min_doc_count": 1,
				"order": {
					"_key": "desc"
				}
			}
		}
	},
	"size": 0
}

说一下几个参数的作用

aggs:指定这是一个聚合功能

jzrq:这个是聚合函数的名字

date_histogram:按照时间去聚合

field:指定字段,按照哪个字段聚合

format:指定返回的buckets的key_as_string的格式

interval:按照天/月/年去分组

min_doc_count:所允许的buckets中最小的doc_count条数

order:_key 排序方式

这里是文档,点我

这里要强调一点

GET /cars/transactions/_search{
   "size" : 0,
   "aggs": {
      "sales": {
         "date_histogram": {
            "field": "sold",
            "interval": "month",
            "format": "yyyy-MM-dd",
            "min_doc_count" : 0, 
            "extended_bounds" : { 
                "min" : "2014-01-01",
                "max" : "2014-12-31"
            }
         }
      }
   }}

文档中说道有一个extened_bounds参数,我试了一下,并没有对日期做限制,比如我限定2019-12-01至2019-12-31,仍然会在聚合结果中显示出其他时间段的数据,其实这里的extened_bounds仅仅是个扩展时间的范围,一切以实际数据为准,官方解释如下

extended_bounds 参数需要一点解释。 min_doc_count 参数强制返回空 buckets,但是 Elasticsearch 默认只返回你的数据中最小值和最大值之间的 buckets。

因此如果你的数据只落在了 4 月和 7 月之间,那么你只能得到这些月份的 buckets(可能为空也可能不为空)。因此为了得到全年数据,我们需要告诉 Elasticsearch 我们想要全部 buckets, 即便那些 buckets 可能落在最小日期 之前 或 最大日期 之后 。

image.png

我的时间字段的类型是date,即

image.png


于是我在query中对日期做了限制,就可以

{
    "query": {
        "bool": {
            "must": {
                "term": {
                    "ysdm": "000485"
                }
            },
            "filter": {
                "range": {
                    "jzrq": {
                        "from": "2019-12-01",
                        "to": "2019-12-05"
                    }
                }
            }
        }
    },
    "size": 0,
    "aggs": {
        "jzrq": {
            "date_histogram": {
                "field": "jzrq",
                "format": "yyyy-MM-dd",
                "interval": "day",
                "min_doc_count": 1,
                "order": {
                    "_key": "desc"
                }
            }
        }
    }
}

好了踩坑到此结束,希望对大家有所帮助

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Powered By Z-BlogPHP 1.7.3

版权所有 | 转载请标明出处