背景: Elasticsearch 的查询模板(Search Template)功能非常强大,可以让你参数化复杂的查询,从而在不同的上下文中重用相同的查询逻辑。以下是一个从 Elasticsearch 官方文档中提取的查询模板案例,涵盖了如何创建和使用查询模板。
目前项目采用的es版本:Elasticsearch 6.8.6
1. 创建查询模板
首先,我们需要创建一个查询模板。假设我们有一个索引 event_index
,其中包含 user_id
、user_name
和 create_time
字段。我们希望统计在某个时间范围内用户的唯一数量。
创建索引映射
PUT /event_index
{
"mappings": {
"properties": {
"user_id": {
"type": "keyword"
},
"create_time": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"user_name": {
"type": "text"
}
}
}
}
插入示例数据
PUT /event_index/_doc/1
{
"user_id": "1",
"user_name": "format1",
"create_time": "2015-11-07 12:00:00"
}
PUT /event_index/_doc/2
{
"user_id": "2",
"user_name": "format2",
"create_time": "2015-11-07 13:30:00"
}
PUT /event_index/_doc/3
{
"user_id": "3",
"user_name": "format3",
"create_time": "2015-11-07 13:30:00"
}
PUT /event_index/_doc/4
{
"user_id": "1",
"user_name": "format1",
"create_time": "2015-11-07 13:50:00"
}
PUT /event_index/_doc/5
{
"user_id": "1",
"user_name": "format1",
"create_time": "2015-11-07 13:55:00"
}
创建查询模板
PUT _scripts/stats
{
"script": {
"lang": "mustache",
"source": {
"query": {
"bool": {
"must": [
{
"range": {
"create_time": {
"gte": "{{start_date}}",
"lte": "{{end_date}}"
}
}
}
]
}
},
"size": 0,
"aggs": {
"stats_data": {
"date_histogram": {
"field": "create_time",
"calendar_interval": "{{interval}}"
},
"aggs": {
"unique_users": {
"cardinality": {
"field": "user_id"
}
}
}
}
}
}
}
}
2. 使用查询模板
查询以小时为单位
GET _search/template
{
"id": "stats",
"params": {
"start_date": "2015-11-07 00:00:00",
"end_date": "2015-11-07 23:59:59",
"interval": "hour"
}
}
查询以天为单位
GET _search/template
{
"id": "stats",
"params": {
"start_date": "2015-11-07 00:00:00",
"end_date": "2015-11-07 23:59:59",
"interval": "day"
}
}
3. 解释
- 创建索引映射:定义了
event_index
索引的字段类型和格式。 - 插入示例数据:向
event_index
索引中插入了一些示例数据。 - 创建查询模板:定义了一个查询模板
stats
,使用 Mustache 语言参数化了查询条件和聚合条件。range
查询用于筛选在指定时间范围内的数据。date_histogram
聚合用于按时间间隔(小时或天)统计数据。cardinality
聚合用于统计唯一用户数。
- 使用查询模板:通过
GET _search/template
请求调用查询模板,并传入参数start_date
、end_date
和interval
。
4.遇到的版本问题
执行上述案例[1:185] [date_histogram] unknown field [calendar_interval], parser not found
在 Elasticsearch 6.8.6 版本中,date_histogram
聚合确实没有 calendar_interval
参数。取而代之的是使用 interval
参数来指定时间间隔。上述案例的查询在另一个师兄的较高版本的es里执行是可以哦.
让我们更新查询模板,使用 interval
参数来指定时间间隔。
更新查询模板
将 calendar_interval
替换为 interval
:
PUT _scripts/stats
{
"script": {
"lang": "mustache",
"source": {
"query": {
"bool": {
"must": [
{
"range": {
"create_time": {
"gte": "{{start_date}}",
"lte": "{{end_date}}"
}
}
}
]
}
},
"size": 0,
"aggs": {
"stats_data": {
"date_histogram": {
"field": "create_time",
"interval": "{{interval}}"
},
"aggs": {
"unique_users": {
"cardinality": {
"field": "user_id"
}
}
}
}
}
}
}
}
5. 输出示例
以小时为单位的输出
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 5,
"max_score": 0,
"hits": []
},
"aggregations": {
"stats_data": {
"buckets": [
{
"key_as_string": "2015-11-07 12:00:00",
"key": 1446897600000,
"doc_count": 1,
"unique_users": {
"value": 1
}
},
{
"key_as_string": "2015-11-07 13:00:00",
"key": 1446901200000,
"doc_count": 4,
"unique_users": {
"value": 3
}
}
]
}
}
}
以天为单位的输出
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 5,
"max_score": 0,
"hits": []
},
"aggregations": {
"stats_data": {
"buckets": [
{
"key_as_string": "2015-11-07 00:00:00",
"key": 1446854400000,
"doc_count": 5,
"unique_users": {
"value": 3
}
}
]
}
}
}
5.总结
通过这个案例,你可以看到如何使用 Elasticsearch 的查询模板来参数化复杂的查询,并在不同的上下文中重用这些查询。查询模板不仅可以简化应用,还可以封装复杂的业务逻辑,提高开发效率。希望这个案例对你有所帮助!如果有更多问题或需要进一步的帮助,请随时告诉我。