如何在go-redis聚合函数中按时间范围过滤计算duration总和
在go-redis中基于时间范围筛选并聚合Redis数据
要实现按时间范围筛选条目后聚合duration字段的总和,你需要利用RedisSearch的范围查询语法,在FTAggregateOptions中添加筛选条件。以下是具体实现方案:
核心思路
RedisSearch支持通过@字段名:[最小值 最大值]的语法筛选数值/日期类型的字段,优先使用全局过滤条件(先筛数据再聚合,性能更优),若需分组内过滤再单独配置分组的Filter。
修改后的代码示例
假设你的时间戳字段名为timestamp(存储为Unix时间戳),以下是完整实现:
import ( "context" "fmt" "github.com/redis/go-redis/v9" ) func getFilteredDurationSum(ctx context.Context, rdb *redis.Client) (float64, error) { // 定义目标时间范围(替换为你的实际时间戳) startTs := 1717000000 endTs := 1717864000 aggOpts := redis.FTAggregateOptions{ // 全局过滤:只保留timestamp在[startTs, endTs]范围内的条目 Filter: fmt.Sprintf("@timestamp:[%d %d]", startTs, endTs), GroupBy: []redis.FTAggregateGroupBy{ { Fields: []interface{}{"@ID"}, Reduce: []redis.FTAggregateReducer{ { Reducer: redis.SearchSum, Args: []interface{}{"@duration"}, As: "sum_duration", }, }, }, }, } // 执行聚合查询(注意替换*为你的实际索引名称) result, err := rdb.FTAggregateWithArgs(ctx, "*", &aggOpts).Result() if err != nil { return 0, err } // 计算所有分组的总和 total := 0.0 for _, row := range result { if sum, ok := row["sum_duration"].(float64); ok { total += sum } } return total, nil }
额外说明
- 时间格式适配:如果你的时间戳是ISO字符串(如
2024-06-01T00:00:00),且字段已被索引为日期类型,可直接用字符串范围查询:Filter: `@timestamp:["2024-06-01" "2024-06-10"]` - 范围类型调整:RedisSearch支持开区间(用
())和混合区间,比如@timestamp:[(1717000000 1717864000]表示大于startTs且小于等于endTs。 - 无分组聚合:如果不需要按
ID分组,仅需全局求和,可去掉GroupBy配置,改用顶层Reduce:aggOpts := redis.FTAggregateOptions{ Filter: fmt.Sprintf("@timestamp:[%d %d]", startTs, endTs), Reduce: []redis.FTAggregateReducer{ { Reducer: redis.SearchSum, Args: []interface{}{"@duration"}, As: "total_sum", }, }, } // 解析结果时直接取第一个行的total_sum total := result[0]["total_sum"].(float64)
内容的提问来源于stack exchange,提问作者user1716970
相关产品推荐
相关产品推荐

