将Pandas聚合逻辑转换为Elasticsearch实现方案咨询
Elasticsearch实现指定聚合分析任务方案
需求说明
筛选出满足以下两个条件的城市:
- 拥有不少于10家独立餐厅
- 这些餐厅的投票数均≥100
之后从符合条件的城市中,找出AverageCostForTwo平均值最高的7个城市。
已实现的Pandas代码
import pandas as pd import numpy as np # 筛选出餐厅数量≥10的城市数据 df_filtered = df[df.groupby('City')['RestaurantName'].transform('nunique') >= 10] # 进一步筛选投票数≥100的餐厅 df_filtered = df_filtered[df_filtered['Votes'] >= 100] # 按城市计算AverageCostForTwo的均值 df_city_avg = df_filtered.groupby('City')['AverageCostForTwo'].mean().reset_index() # 排序取Top7 df_top_cities = df_city_avg.sort_values(by='AverageCostForTwo', ascending=False).head(7)
Elasticsearch实现思路与DSL
Elasticsearch需要通过多层聚合+管道聚合匹配Pandas的逻辑,具体步骤如下:
- 前置过滤:先用查询过滤出所有
Votes≥100的餐厅文档,缩小聚合范围; - 按城市分组:用
terms聚合按City字段分组; - 统计独立餐厅数:在每个城市分组内,用
cardinality聚合统计RestaurantName的去重数量(对应Pandas的nunique); - 过滤符合条件的城市:用
bucket_selector管道聚合,只保留独立餐厅数≥10的城市分组; - 计算均值:在每个城市分组内,用
avg聚合计算AverageCostForTwo的平均值; - 排序取Top7:在
terms聚合中设置排序规则(按平均值降序),并限制返回7个结果。
完整DSL示例
{ "size": 0, // 无需返回原始文档,仅获取聚合结果 "query": { "bool": { "filter": [ { "range": { "Votes": { "gte": 100 } } } ] } }, "aggs": { "group_by_city": { "terms": { "field": "City.keyword", // City字段需为keyword类型,避免分词导致分组错误 "size": 7, "order": { "avg_cost": "desc" // 按AverageCostForTwo均值降序排序 } }, "aggs": { "unique_restaurant_count": { "cardinality": { "field": "RestaurantName.keyword" // RestaurantName同样需为keyword类型 } }, "avg_cost": { "avg": { "field": "AverageCostForTwo" } }, "filter_valid_cities": { "bucket_selector": { "buckets_path": { "restCount": "unique_restaurant_count" }, "script": "params.restCount >= 10" // 筛选餐厅数≥10的城市 } } } } } }
注意事项
- 确保
City和RestaurantName字段的映射类型为keyword,否则terms和cardinality聚合会因分词得到错误结果; - 若
AverageCostForTwo是字符串类型,需先转换为数值类型(如float或integer),否则avg聚合无法执行; - 若数据量极大,可考虑用
composite聚合替代terms聚合避免内存溢出,本需求取Top7,设置size:7即可。
内容的提问来源于stack exchange,提问作者Irene Hawkins
相关产品推荐
相关产品推荐

