Elasticsearch 数据处理:group by sum操作
Elasticsearch 数据聚合实现类型 mysql中 group by sum。
et:
select sum(flow) from appflow group by opTime, userId
type AppFlow struct {
OpTime int64 `json:"opTime"` // 操作时间
UserId string `json:"userId"` // 用户id
App string `json:"app"` // app
Flow int64 `json:"flow"` // 流量
Channel string `json:"channel"` // 渠道
GroupUser string `json:"groupUser"` // 聚合字段
}
type UserFlow struct {
OpTime int64 `json:"opTime"` // 操作时间
UserId string `json:"userId"` // 用户id
Flow int64 `json:"flow"` // 流量
}
Elasticsearch 中实现group by 需要使用 Aggregation et:
// userFlowGroup 聚合用户数据并返回
func (e *AppFlow) userFlowGroup() []*UserFlow {
dtList := make([]*UserFlow, 0)
boolQuery := elastic.NewBoolQuery()
timeAgg := elastic.NewTermsAggregation().Field("opTime")
userAgg := elastic.NewTermsAggregation().Field("userId")
flowSumAgg := elastic.NewSumAggregation().Field("flow")
userAgg.SubAggregation("flow_sum", flowSumAgg)
timeAgg.SubAggregation("user", userAgg)
searchResult, err := getESClient().Search().
Index(e.Index()). // 设置索引名
Query(boolQuery).
Aggregation("times", timeAgg). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 不需要文档详情,只需要聚合结果
Do(ctx) // 执行请求
if err != nil {
log.print("search err:%+v", err)
return dtList
}
timeAggRes, _ := searchResult.Aggregations.Terms("times")
for _, timeBucket := range timeAggRes.Buckets {
userAggRes, _:= timeBucket.Aggregations.Terms("user")
for _, userBucket := range userAggRes.Buckets{
sentFlow, _ := schemeBucket.Aggregations.Sum("flow_sum")
tmp:= &UserFlow{
OpTime:fmt.Sprintf("%v", timeBucket.Key),
UserId:fmt.Sprintf("%v", userBucket.Key),
Flow: int64(*sentFlow.Value)
}
dtList = append(dtList, tmp)
}
}
return dtList
}
在以上代码中:只是group by 2个字段,处理结果的时候就需要 嵌套for循环,这种嵌套for循环个人感觉非常不安全,所以我想了个办法,弄了个骚操作。
在插入数据的时候,根据group by 的字段生成一个groupUser 字段并存储到es中。这样就只需要一次循环一次聚合了
func (e *AppFlow) GroupId() []*UserFlow {
e.GroupUser = fmt.Sprintf("%d_%s", e.OpTime, e.UserId)
}
// userFlowGroup 聚合用户数据并返回
func (e *AppFlow) userFlowGroup() []*UserFlow {
dtList := make([]*UserFlow, 0)
boolQuery := elastic.NewBoolQuery()
groupAgg := elastic.NewTermsAggregation().Field("groupUser")
flowSumAgg := elastic.NewSumAggregation().Field("flow")
groupAgg.SubAggregation("flow_sum", flowSumAgg)
searchResult, err := getESClient().Search().
Index(e.Index()). // 设置索引名
Query(boolQuery).
Aggregation("group", groupAgg). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 不需要文档详情,只需要聚合结果
Do(ctx) // 执行请求
if err != nil {
log.print("search err:%+v", err)
return dtList
}
groupAggRes, _ := searchResult.Aggregations.Terms("group")
for _, groupData := range groupAggRes.Buckets {
sentFlow, _ := schemeBucket.Aggregations.Sum("flow_sum")
sL := strings.Split(groupData, "_")
if len(sL) < 2 {
continue
}
dt, _ := strconv.ParseInt(sL[0], 10, 0)
tmp:= &UserFlow{
OpTime:dt,
UserId:sL[1],
Flow: int64(*sentFlow.Value)
}
dtList = append(dtList, tmp)}
}
return dtList
}
使用中间的groupUser 增加了es使用空间,优化了查询,不知道诸位有没有更好的方式。。。。。总感觉这个骚操作有点不靠谱..。。。