mirror of
https://github.com/redis/go-redis.git
synced 2025-09-04 09:22:10 +03:00
* DOC-5472 added and fixed tests up to * DOC-5472 added agg bucket examples * DOC-5472 time series doc examples * DOC-5472 removed black lines above error checks, following feedback * DOC-5472 fixed param formatting, following feedback --------- Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com>
1164 lines
23 KiB
Go
1164 lines
23 KiB
Go
// EXAMPLE: time_series_tutorial
|
|
// HIDE_START
|
|
package example_commands_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"maps"
|
|
"math"
|
|
"slices"
|
|
"sort"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
// HIDE_END
|
|
|
|
func ExampleClient_timeseries_create() {
|
|
ctx := context.Background()
|
|
|
|
rdb := redis.NewClient(&redis.Options{
|
|
Addr: "localhost:6379",
|
|
Password: "", // no password set
|
|
DB: 0, // use default DB
|
|
})
|
|
|
|
// REMOVE_START
|
|
// make sure we are working with fresh database
|
|
rdb.FlushDB(ctx)
|
|
rdb.Del(ctx, "thermometer:1", "thermometer:2", "thermometer:3")
|
|
// REMOVE_END
|
|
|
|
// STEP_START create
|
|
res1, err := rdb.TSCreate(ctx, "thermometer:1").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res1) // >>> OK
|
|
|
|
res2, err := rdb.Type(ctx, "thermometer:1").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res2) // >>> TSDB-TYPE
|
|
|
|
res3, err := rdb.TSInfo(ctx, "thermometer:1").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res3["totalSamples"]) // >>> 0
|
|
// STEP_END
|
|
|
|
// STEP_START create_retention
|
|
res4, err := rdb.TSAddWithArgs(
|
|
ctx,
|
|
"thermometer:2",
|
|
1,
|
|
10.8,
|
|
&redis.TSOptions{
|
|
Retention: 100,
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res4) // >>> 1
|
|
|
|
res5, err := rdb.TSInfo(ctx, "thermometer:2").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res5["retentionTime"]) // >>> 100
|
|
// STEP_END
|
|
|
|
// STEP_START create_labels
|
|
res6, err := rdb.TSAddWithArgs(
|
|
ctx,
|
|
"thermometer:3",
|
|
1,
|
|
10.4,
|
|
&redis.TSOptions{
|
|
Labels: map[string]string{
|
|
"location": "UK",
|
|
"type": "Mercury",
|
|
},
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res6) // >>> 1
|
|
|
|
res7, err := rdb.TSInfo(ctx, "thermometer:3").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res7["labels"])
|
|
// >>> map[location:UK type:Mercury]
|
|
// STEP_END
|
|
|
|
// Output:
|
|
// OK
|
|
// TSDB-TYPE
|
|
// 0
|
|
// 1
|
|
// 100
|
|
// 1
|
|
// map[location:UK type:Mercury]
|
|
}
|
|
|
|
func ExampleClient_timeseries_add() {
|
|
ctx := context.Background()
|
|
|
|
rdb := redis.NewClient(&redis.Options{
|
|
Addr: "localhost:6379",
|
|
Password: "", // no password set
|
|
DB: 0, // use default DB
|
|
})
|
|
|
|
// REMOVE_START
|
|
// make sure we are working with fresh database
|
|
rdb.FlushDB(ctx)
|
|
rdb.Del(ctx, "thermometer:1", "thermometer:2")
|
|
rdb.TSCreate(ctx, "thermometer:1")
|
|
rdb.TSCreate(ctx, "thermometer:2")
|
|
// REMOVE_END
|
|
|
|
// STEP_START madd
|
|
res1, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"thermometer:1", 1, 9.2},
|
|
{"thermometer:1", 2, 9.9},
|
|
{"thermometer:2", 2, 10.3},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res1) // >>> [1 2 2]
|
|
// STEP_END
|
|
|
|
// STEP_START get
|
|
// The last recorded temperature for thermometer:2
|
|
// was 10.3 at time 2.
|
|
res2, err := rdb.TSGet(ctx, "thermometer:2").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res2)
|
|
// >>> {2 10.3}
|
|
// STEP_END
|
|
|
|
// Output:
|
|
// [1 2 2]
|
|
// {2 10.3}
|
|
}
|
|
|
|
func ExampleClient_timeseries_range() {
|
|
ctx := context.Background()
|
|
|
|
rdb := redis.NewClient(&redis.Options{
|
|
Addr: "localhost:6379",
|
|
Password: "", // no password set
|
|
DB: 0, // use default DB
|
|
})
|
|
|
|
// REMOVE_START
|
|
// make sure we are working with fresh database
|
|
rdb.FlushDB(ctx)
|
|
rdb.Del(ctx, "rg:1")
|
|
// REMOVE_END
|
|
|
|
// STEP_START range
|
|
// Add 5 data points to a time series named "rg:1".
|
|
res1, err := rdb.TSCreate(ctx, "rg:1").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res1) // >>> OK
|
|
|
|
res2, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"rg:1", 0, 18},
|
|
{"rg:1", 1, 14},
|
|
{"rg:1", 2, 22},
|
|
{"rg:1", 3, 18},
|
|
{"rg:1", 4, 24},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res2) // >>> [0 1 2 3 4]
|
|
|
|
// Retrieve all the data points in ascending order.
|
|
// Note: use 0 and `math.MaxInt64` instead of - and +
|
|
// to denote the minimum and maximum possible timestamps.
|
|
res3, err := rdb.TSRange(ctx, "rg:1", 0, math.MaxInt64).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res3)
|
|
// >>> [{0 18} {1 14} {2 22} {3 18} {4 24}]
|
|
|
|
// Retrieve data points up to time 1 (inclusive).
|
|
res4, err := rdb.TSRange(ctx, "rg:1", 0, 1).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res4)
|
|
// >>> [{0 18} {1 14}]
|
|
|
|
// Retrieve data points from time 3 onwards.
|
|
res5, err := rdb.TSRange(ctx, "rg:1", 3, math.MaxInt64).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res5)
|
|
// >>> [{3 18} {4 24}]
|
|
|
|
// Retrieve all the data points in descending order.
|
|
res6, err := rdb.TSRevRange(ctx, "rg:1", 0, math.MaxInt64).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res6)
|
|
// >>> [{4 24} {3 18} {2 22} {1 14} {0 18}]
|
|
|
|
// Retrieve data points up to time 1 (inclusive), but return them
|
|
// in descending order.
|
|
res7, err := rdb.TSRevRange(ctx, "rg:1", 0, 1).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res7)
|
|
// >>> [{1 14} {0 18}]
|
|
// STEP_END
|
|
|
|
// STEP_START range_filter
|
|
res8, err := rdb.TSRangeWithArgs(
|
|
ctx,
|
|
"rg:1",
|
|
0,
|
|
math.MaxInt64,
|
|
&redis.TSRangeOptions{
|
|
FilterByTS: []int{0, 2, 4},
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res8) // >>> [{0 18} {2 22} {4 24}]
|
|
|
|
res9, err := rdb.TSRevRangeWithArgs(
|
|
ctx,
|
|
"rg:1",
|
|
0,
|
|
math.MaxInt64,
|
|
&redis.TSRevRangeOptions{
|
|
FilterByTS: []int{0, 2, 4},
|
|
FilterByValue: []int{20, 25},
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res9) // >>> [{4 24} {2 22}]
|
|
|
|
res10, err := rdb.TSRevRangeWithArgs(
|
|
ctx,
|
|
"rg:1",
|
|
0,
|
|
math.MaxInt64,
|
|
&redis.TSRevRangeOptions{
|
|
FilterByTS: []int{0, 2, 4},
|
|
FilterByValue: []int{22, 22},
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res10) // >>> [{2 22}]
|
|
// STEP_END
|
|
|
|
// Output:
|
|
// OK
|
|
// [0 1 2 3 4]
|
|
// [{0 18} {1 14} {2 22} {3 18} {4 24}]
|
|
// [{0 18} {1 14}]
|
|
// [{3 18} {4 24}]
|
|
// [{4 24} {3 18} {2 22} {1 14} {0 18}]
|
|
// [{1 14} {0 18}]
|
|
// [{0 18} {2 22} {4 24}]
|
|
// [{4 24} {2 22}]
|
|
// [{2 22}]
|
|
}
|
|
|
|
func ExampleClient_timeseries_query_multi() {
|
|
ctx := context.Background()
|
|
|
|
rdb := redis.NewClient(&redis.Options{
|
|
Addr: "localhost:6379",
|
|
Password: "", // no password set
|
|
DB: 0, // use default DB
|
|
})
|
|
|
|
// REMOVE_START
|
|
// make sure we are working with fresh database
|
|
rdb.FlushDB(ctx)
|
|
rdb.Del(ctx, "rg:2", "rg:3", "rg:4")
|
|
// REMOVE_END
|
|
|
|
// STEP_START query_multi
|
|
// Create three new "rg:" time series (two in the US
|
|
// and one in the UK, with different units) and add some
|
|
// data points.
|
|
res20, err := rdb.TSCreateWithArgs(ctx, "rg:2", &redis.TSOptions{
|
|
Labels: map[string]string{"location": "us", "unit": "cm"},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res20) // >>> OK
|
|
|
|
res21, err := rdb.TSCreateWithArgs(ctx, "rg:3", &redis.TSOptions{
|
|
Labels: map[string]string{"location": "us", "unit": "in"},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res21) // >>> OK
|
|
|
|
res22, err := rdb.TSCreateWithArgs(ctx, "rg:4", &redis.TSOptions{
|
|
Labels: map[string]string{"location": "uk", "unit": "mm"},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res22) // >>> OK
|
|
|
|
res23, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"rg:2", 0, 1.8},
|
|
{"rg:3", 0, 0.9},
|
|
{"rg:4", 0, 25},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res23) // >>> [0 0 0]
|
|
|
|
res24, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"rg:2", 1, 2.1},
|
|
{"rg:3", 1, 0.77},
|
|
{"rg:4", 1, 18},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res24) // >>> [1 1 1]
|
|
|
|
res25, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"rg:2", 2, 2.3},
|
|
{"rg:3", 2, 1.1},
|
|
{"rg:4", 2, 21},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res25) // >>> [2 2 2]
|
|
|
|
res26, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"rg:2", 3, 1.9},
|
|
{"rg:3", 3, 0.81},
|
|
{"rg:4", 3, 19},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res26) // >>> [3 3 3]
|
|
|
|
res27, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"rg:2", 4, 1.78},
|
|
{"rg:3", 4, 0.74},
|
|
{"rg:4", 4, 23},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res27) // >>> [4 4 4]
|
|
|
|
// Retrieve the last data point from each US time series.
|
|
res28, err := rdb.TSMGet(ctx, []string{"location=us"}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
res28Keys := slices.Collect(maps.Keys(res28))
|
|
sort.Strings(res28Keys)
|
|
|
|
for _, k := range res28Keys {
|
|
labels := res28[k][0].(map[interface{}]interface{})
|
|
|
|
labelKeys := make([]string, 0, len(labels))
|
|
|
|
for lk := range labels {
|
|
labelKeys = append(labelKeys, lk.(string))
|
|
}
|
|
|
|
sort.Strings(labelKeys)
|
|
|
|
fmt.Printf("%v:\n", k)
|
|
|
|
for _, lk := range labelKeys {
|
|
fmt.Printf(" %v: %v\n", lk, labels[lk])
|
|
}
|
|
|
|
fmt.Printf(" %v\n", res28[k][1])
|
|
}
|
|
// >>> rg:2:
|
|
// >>> {4 1.78}
|
|
// >>> rg:3:
|
|
// >>> {4 0.74}
|
|
|
|
// Retrieve the same data points, but include the `unit`
|
|
// label in the results.
|
|
res29, err := rdb.TSMGetWithArgs(
|
|
ctx,
|
|
[]string{"location=us"},
|
|
&redis.TSMGetOptions{
|
|
SelectedLabels: []interface{}{"unit"},
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
res29Keys := slices.Collect(maps.Keys(res29))
|
|
sort.Strings(res29Keys)
|
|
|
|
for _, k := range res29Keys {
|
|
labels := res29[k][0].(map[interface{}]interface{})
|
|
|
|
labelKeys := make([]string, 0, len(labels))
|
|
|
|
for lk := range labels {
|
|
labelKeys = append(labelKeys, lk.(string))
|
|
}
|
|
|
|
sort.Strings(labelKeys)
|
|
|
|
fmt.Printf("%v:\n", k)
|
|
|
|
for _, lk := range labelKeys {
|
|
fmt.Printf(" %v: %v\n", lk, labels[lk])
|
|
}
|
|
|
|
fmt.Printf(" %v\n", res29[k][1])
|
|
}
|
|
|
|
// >>> rg:2:
|
|
// >>> unit: cm
|
|
// >>> [4 1.78]
|
|
// >>> rg:3:
|
|
// >>> unit: in
|
|
// >>> [4 0.74]
|
|
|
|
// Retrieve data points up to time 2 (inclusive) from all
|
|
// time series that use millimeters as the unit. Include all
|
|
// labels in the results.
|
|
// Note that the `aggregators` field is empty if you don't
|
|
// specify any aggregators.
|
|
res30, err := rdb.TSMRangeWithArgs(
|
|
ctx,
|
|
0,
|
|
2,
|
|
[]string{"unit=mm"},
|
|
&redis.TSMRangeOptions{
|
|
WithLabels: true,
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
res30Keys := slices.Collect(maps.Keys(res30))
|
|
sort.Strings(res30Keys)
|
|
|
|
for _, k := range res30Keys {
|
|
labels := res30[k][0].(map[interface{}]interface{})
|
|
labelKeys := make([]string, 0, len(labels))
|
|
|
|
for lk := range labels {
|
|
labelKeys = append(labelKeys, lk.(string))
|
|
}
|
|
|
|
sort.Strings(labelKeys)
|
|
|
|
fmt.Printf("%v:\n", k)
|
|
|
|
for _, lk := range labelKeys {
|
|
fmt.Printf(" %v: %v\n", lk, labels[lk])
|
|
}
|
|
|
|
fmt.Printf(" Aggregators: %v\n", res30[k][1])
|
|
fmt.Printf(" %v\n", res30[k][2])
|
|
}
|
|
// >>> rg:4:
|
|
// >>> location: uk
|
|
// >>> unit: mm
|
|
// >>> Aggregators: map[aggregators:[]]
|
|
// >>> [{0 25} {1 18} {2 21}]
|
|
|
|
// Retrieve data points from time 1 to time 3 (inclusive) from
|
|
// all time series that use centimeters or millimeters as the unit,
|
|
// but only return the `location` label. Return the results
|
|
// in descending order of timestamp.
|
|
res31, err := rdb.TSMRevRangeWithArgs(
|
|
ctx,
|
|
1,
|
|
3,
|
|
[]string{"unit=(cm,mm)"},
|
|
&redis.TSMRevRangeOptions{
|
|
SelectedLabels: []interface{}{"location"},
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
res31Keys := slices.Collect(maps.Keys(res31))
|
|
sort.Strings(res31Keys)
|
|
|
|
for _, k := range res31Keys {
|
|
labels := res31[k][0].(map[interface{}]interface{})
|
|
labelKeys := make([]string, 0, len(labels))
|
|
|
|
for lk := range labels {
|
|
labelKeys = append(labelKeys, lk.(string))
|
|
}
|
|
|
|
sort.Strings(labelKeys)
|
|
|
|
fmt.Printf("%v:\n", k)
|
|
|
|
for _, lk := range labelKeys {
|
|
fmt.Printf(" %v: %v\n", lk, labels[lk])
|
|
}
|
|
|
|
fmt.Printf(" Aggregators: %v\n", res31[k][1])
|
|
fmt.Printf(" %v\n", res31[k][2])
|
|
}
|
|
// >>> rg:2:
|
|
// >>> location: us
|
|
// >>> Aggregators: map[aggregators:[]]
|
|
// >>> [{3 1.9} {2 2.3} {1 2.1}]
|
|
// >>> rg:4:
|
|
// >>> location: uk
|
|
// >>> Aggregators: map[aggregators:[]]
|
|
// >>> [{3 19} {2 21} {1 18}]
|
|
// STEP_END
|
|
|
|
// Output:
|
|
// OK
|
|
// OK
|
|
// OK
|
|
// [0 0 0]
|
|
// [1 1 1]
|
|
// [2 2 2]
|
|
// [3 3 3]
|
|
// [4 4 4]
|
|
// rg:2:
|
|
// [4 1.78]
|
|
// rg:3:
|
|
// [4 0.74]
|
|
// rg:2:
|
|
// unit: cm
|
|
// [4 1.78]
|
|
// rg:3:
|
|
// unit: in
|
|
// [4 0.74]
|
|
// rg:4:
|
|
// location: uk
|
|
// unit: mm
|
|
// Aggregators: map[aggregators:[]]
|
|
// [[0 25] [1 18] [2 21]]
|
|
// rg:2:
|
|
// location: us
|
|
// Aggregators: map[aggregators:[]]
|
|
// [[3 1.9] [2 2.3] [1 2.1]]
|
|
// rg:4:
|
|
// location: uk
|
|
// Aggregators: map[aggregators:[]]
|
|
// [[3 19] [2 21] [1 18]]
|
|
}
|
|
|
|
func ExampleClient_timeseries_aggregation() {
|
|
ctx := context.Background()
|
|
|
|
rdb := redis.NewClient(&redis.Options{
|
|
Addr: "localhost:6379",
|
|
Password: "", // no password set
|
|
DB: 0, // use default DB
|
|
})
|
|
|
|
// REMOVE_START
|
|
// make sure we are working with fresh database
|
|
rdb.FlushDB(ctx)
|
|
rdb.Del(ctx, "rg:2")
|
|
// REMOVE_END
|
|
|
|
// Setup data for aggregation example
|
|
_, err := rdb.TSCreateWithArgs(ctx, "rg:2", &redis.TSOptions{
|
|
Labels: map[string]string{"location": "us", "unit": "cm"},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
_, err = rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"rg:2", 0, 1.8},
|
|
{"rg:2", 1, 2.1},
|
|
{"rg:2", 2, 2.3},
|
|
{"rg:2", 3, 1.9},
|
|
{"rg:2", 4, 1.78},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// STEP_START agg
|
|
res32, err := rdb.TSRangeWithArgs(
|
|
ctx,
|
|
"rg:2",
|
|
0,
|
|
math.MaxInt64,
|
|
&redis.TSRangeOptions{
|
|
Aggregator: redis.Avg,
|
|
BucketDuration: 2,
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res32)
|
|
// >>> [{0 1.9500000000000002} {2 2.0999999999999996} {4 1.78}]
|
|
// STEP_END
|
|
|
|
// Output:
|
|
// [{0 1.9500000000000002} {2 2.0999999999999996} {4 1.78}]
|
|
}
|
|
func ExampleClient_timeseries_agg_bucket() {
|
|
ctx := context.Background()
|
|
|
|
rdb := redis.NewClient(&redis.Options{
|
|
Addr: "localhost:6379",
|
|
Password: "", // no password set
|
|
DB: 0, // use default DB
|
|
})
|
|
|
|
// REMOVE_START
|
|
// make sure we are working with fresh database
|
|
rdb.FlushDB(ctx)
|
|
rdb.Del(ctx, "sensor3")
|
|
// REMOVE_END
|
|
|
|
// STEP_START agg_bucket
|
|
res1, err := rdb.TSCreate(ctx, "sensor3").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res1) // >>> OK
|
|
|
|
res2, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"sensor3", 10, 1000},
|
|
{"sensor3", 20, 2000},
|
|
{"sensor3", 30, 3000},
|
|
{"sensor3", 40, 4000},
|
|
{"sensor3", 50, 5000},
|
|
{"sensor3", 60, 6000},
|
|
{"sensor3", 70, 7000},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res2) // >>> [10 20 30 40 50 60 70]
|
|
|
|
res3, err := rdb.TSRangeWithArgs(
|
|
ctx,
|
|
"sensor3",
|
|
10,
|
|
70,
|
|
&redis.TSRangeOptions{
|
|
Aggregator: redis.Min,
|
|
BucketDuration: 25,
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res3) // >>> [{0 1000} {25 3000} {50 5000}]
|
|
// STEP_END
|
|
|
|
// STEP_START agg_align
|
|
res4, err := rdb.TSRangeWithArgs(
|
|
ctx,
|
|
"sensor3",
|
|
10,
|
|
70,
|
|
&redis.TSRangeOptions{
|
|
Aggregator: redis.Min,
|
|
BucketDuration: 25,
|
|
Align: "START",
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res4) // >>> [{10 1000} {35 4000} {60 6000}]
|
|
// STEP_END
|
|
|
|
// Output:
|
|
// OK
|
|
// [10 20 30 40 50 60 70]
|
|
// [{0 1000} {25 3000} {50 5000}]
|
|
// [{10 1000} {35 4000} {60 6000}]
|
|
}
|
|
|
|
func ExampleClient_timeseries_aggmulti() {
|
|
ctx := context.Background()
|
|
|
|
rdb := redis.NewClient(&redis.Options{
|
|
Addr: "localhost:6379",
|
|
Password: "", // no password set
|
|
DB: 0, // use default DB
|
|
})
|
|
|
|
// REMOVE_START
|
|
// make sure we are working with fresh database
|
|
rdb.FlushDB(ctx)
|
|
rdb.Del(ctx, "wind:1", "wind:2", "wind:3", "wind:4")
|
|
// REMOVE_END
|
|
|
|
// STEP_START agg_multi
|
|
res37, err := rdb.TSCreateWithArgs(ctx, "wind:1", &redis.TSOptions{
|
|
Labels: map[string]string{"country": "uk"},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res37) // >>> OK
|
|
|
|
res38, err := rdb.TSCreateWithArgs(ctx, "wind:2", &redis.TSOptions{
|
|
Labels: map[string]string{"country": "uk"},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res38) // >>> OK
|
|
|
|
res39, err := rdb.TSCreateWithArgs(ctx, "wind:3", &redis.TSOptions{
|
|
Labels: map[string]string{"country": "us"},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res39) // >>> OK
|
|
|
|
res40, err := rdb.TSCreateWithArgs(ctx, "wind:4", &redis.TSOptions{
|
|
Labels: map[string]string{"country": "us"},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res40) // >>> OK
|
|
|
|
res41, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"wind:1", 1, 12},
|
|
{"wind:2", 1, 18},
|
|
{"wind:3", 1, 5},
|
|
{"wind:4", 1, 20},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res41) // >>> [1 1 1 1]
|
|
|
|
res42, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"wind:1", 2, 14},
|
|
{"wind:2", 2, 21},
|
|
{"wind:3", 2, 4},
|
|
{"wind:4", 2, 25},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res42) // >>> [2 2 2 2]
|
|
|
|
res43, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"wind:1", 3, 10},
|
|
{"wind:2", 3, 24},
|
|
{"wind:3", 3, 8},
|
|
{"wind:4", 3, 18},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res43) // >>> [3 3 3 3]
|
|
|
|
// The result pairs contain the timestamp and the maximum sample value
|
|
// for the country at that timestamp.
|
|
res44, err := rdb.TSMRangeWithArgs(
|
|
ctx,
|
|
0,
|
|
math.MaxInt64,
|
|
[]string{"country=(us,uk)"},
|
|
&redis.TSMRangeOptions{
|
|
GroupByLabel: "country",
|
|
Reducer: "max",
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
res44Keys := slices.Collect(maps.Keys(res44))
|
|
sort.Strings(res44Keys)
|
|
|
|
for _, k := range res44Keys {
|
|
labels := res44[k][0].(map[interface{}]interface{})
|
|
labelKeys := make([]string, 0, len(labels))
|
|
|
|
for lk := range labels {
|
|
labelKeys = append(labelKeys, lk.(string))
|
|
}
|
|
|
|
sort.Strings(labelKeys)
|
|
|
|
fmt.Printf("%v:\n", k)
|
|
|
|
for _, lk := range labelKeys {
|
|
fmt.Printf(" %v: %v\n", lk, labels[lk])
|
|
}
|
|
|
|
fmt.Printf(" %v\n", res44[k][1])
|
|
fmt.Printf(" %v\n", res44[k][2])
|
|
fmt.Printf(" %v\n", res44[k][3])
|
|
}
|
|
// >>> country=uk:
|
|
// >>> map[reducers:[max]]
|
|
// >>> map[sources:[wind:1 wind:2]]
|
|
// >>> [[1 18] [2 21] [3 24]]
|
|
// >>> country=us:
|
|
// >>> map[reducers:[max]]
|
|
// >>> map[sources:[wind:3 wind:4]]
|
|
// >>> [[1 20] [2 25] [3 18]]
|
|
|
|
// The result pairs contain the timestamp and the average sample value
|
|
// for the country at that timestamp.
|
|
res45, err := rdb.TSMRangeWithArgs(
|
|
ctx,
|
|
0,
|
|
math.MaxInt64,
|
|
[]string{"country=(us,uk)"},
|
|
&redis.TSMRangeOptions{
|
|
GroupByLabel: "country",
|
|
Reducer: "avg",
|
|
},
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
res45Keys := slices.Collect(maps.Keys(res45))
|
|
sort.Strings(res45Keys)
|
|
|
|
for _, k := range res45Keys {
|
|
labels := res45[k][0].(map[interface{}]interface{})
|
|
labelKeys := make([]string, 0, len(labels))
|
|
|
|
for lk := range labels {
|
|
labelKeys = append(labelKeys, lk.(string))
|
|
}
|
|
|
|
sort.Strings(labelKeys)
|
|
|
|
fmt.Printf("%v:\n", k)
|
|
|
|
for _, lk := range labelKeys {
|
|
fmt.Printf(" %v: %v\n", lk, labels[lk])
|
|
}
|
|
|
|
fmt.Printf(" %v\n", res45[k][1])
|
|
fmt.Printf(" %v\n", res45[k][2])
|
|
fmt.Printf(" %v\n", res45[k][3])
|
|
}
|
|
// >>> country=uk:
|
|
// >>> map[reducers:[avg]]
|
|
// >>> map[sources:[wind:1 wind:2]]
|
|
// >>> [[1 15] [2 17.5] [3 17]]
|
|
// >>> country=us:
|
|
// >>> map[reducers:[avg]]
|
|
// >>> map[sources:[wind:3 wind:4]]
|
|
// >>> [[1 12.5] [2 14.5] [3 13]]
|
|
// STEP_END
|
|
|
|
// Output:
|
|
// OK
|
|
// OK
|
|
// OK
|
|
// OK
|
|
// [1 1 1 1]
|
|
// [2 2 2 2]
|
|
// [3 3 3 3]
|
|
// country=uk:
|
|
// map[reducers:[max]]
|
|
// map[sources:[wind:1 wind:2]]
|
|
// [[1 18] [2 21] [3 24]]
|
|
// country=us:
|
|
// map[reducers:[max]]
|
|
// map[sources:[wind:3 wind:4]]
|
|
// [[1 20] [2 25] [3 18]]
|
|
// country=uk:
|
|
// map[reducers:[avg]]
|
|
// map[sources:[wind:1 wind:2]]
|
|
// [[1 15] [2 17.5] [3 17]]
|
|
// country=us:
|
|
// map[reducers:[avg]]
|
|
// map[sources:[wind:3 wind:4]]
|
|
// [[1 12.5] [2 14.5] [3 13]]
|
|
}
|
|
|
|
func ExampleClient_timeseries_compaction() {
|
|
ctx := context.Background()
|
|
|
|
rdb := redis.NewClient(&redis.Options{
|
|
Addr: "localhost:6379",
|
|
Password: "", // no password set
|
|
DB: 0, // use default DB
|
|
})
|
|
|
|
// REMOVE_START
|
|
// make sure we are working with fresh database
|
|
rdb.FlushDB(ctx)
|
|
rdb.Del(ctx, "hyg:1", "hyg:compacted")
|
|
// REMOVE_END
|
|
|
|
// STEP_START create_compaction
|
|
res45, err := rdb.TSCreate(ctx, "hyg:1").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res45) // >>> OK
|
|
|
|
res46, err := rdb.TSCreate(ctx, "hyg:compacted").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res46) // >>> OK
|
|
|
|
res47, err := rdb.TSCreateRule(
|
|
ctx, "hyg:1", "hyg:compacted", redis.Min, 3,
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res47) // >>> OK
|
|
|
|
res48, err := rdb.TSInfo(ctx, "hyg:1").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res48["rules"]) // >>> [[hyg:compacted 3 MIN 0]]
|
|
|
|
res49, err := rdb.TSInfo(ctx, "hyg:compacted").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res49["sourceKey"]) // >>> hyg:1
|
|
// STEP_END
|
|
|
|
// STEP_START comp_add
|
|
res50, err := rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"hyg:1", 0, 75},
|
|
{"hyg:1", 1, 77},
|
|
{"hyg:1", 2, 78},
|
|
}).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res50) // >>> [0 1 2]
|
|
|
|
res51, err := rdb.TSRange(
|
|
ctx, "hyg:compacted", 0, math.MaxInt64,
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res51) // >>> []
|
|
|
|
res52, err := rdb.TSAdd(ctx, "hyg:1", 3, 79).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res52) // >>> 3
|
|
|
|
res53, err := rdb.TSRange(
|
|
ctx, "hyg:compacted", 0, math.MaxInt64,
|
|
).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res53) // >>> [{0 75}]
|
|
// STEP_END
|
|
|
|
// Output:
|
|
// OK
|
|
// OK
|
|
// OK
|
|
// map[hyg:compacted:[3 MIN 0]]
|
|
// hyg:1
|
|
// [0 1 2]
|
|
// []
|
|
// 3
|
|
// [{0 75}]
|
|
}
|
|
|
|
func ExampleClient_timeseries_delete() {
|
|
ctx := context.Background()
|
|
|
|
rdb := redis.NewClient(&redis.Options{
|
|
Addr: "localhost:6379",
|
|
Password: "", // no password set
|
|
DB: 0, // use default DB
|
|
})
|
|
|
|
// REMOVE_START
|
|
// make sure we are working with fresh database
|
|
rdb.FlushDB(ctx)
|
|
rdb.Del(ctx, "thermometer:1")
|
|
// Setup initial data
|
|
rdb.TSCreate(ctx, "thermometer:1")
|
|
rdb.TSMAdd(ctx, [][]interface{}{
|
|
{"thermometer:1", 1, 9.2},
|
|
{"thermometer:1", 2, 9.9},
|
|
})
|
|
// REMOVE_END
|
|
|
|
// STEP_START del
|
|
res54, err := rdb.TSInfo(ctx, "thermometer:1").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res54["totalSamples"]) // >>> 2
|
|
fmt.Println(res54["firstTimestamp"]) // >>> 1
|
|
fmt.Println(res54["lastTimestamp"]) // >>> 2
|
|
|
|
res55, err := rdb.TSAdd(ctx, "thermometer:1", 3, 9.7).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res55) // >>> 3
|
|
|
|
res56, err := rdb.TSInfo(ctx, "thermometer:1").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res56["totalSamples"]) // >>> 3
|
|
fmt.Println(res56["firstTimestamp"]) // >>> 1
|
|
fmt.Println(res56["lastTimestamp"]) // >>> 3
|
|
|
|
res57, err := rdb.TSDel(ctx, "thermometer:1", 1, 2).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res57) // >>> 2
|
|
|
|
res58, err := rdb.TSInfo(ctx, "thermometer:1").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res58["totalSamples"]) // >>> 1
|
|
fmt.Println(res58["firstTimestamp"]) // >>> 3
|
|
fmt.Println(res58["lastTimestamp"]) // >>> 3
|
|
|
|
res59, err := rdb.TSDel(ctx, "thermometer:1", 3, 3).Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res59) // >>> 1
|
|
|
|
res60, err := rdb.TSInfo(ctx, "thermometer:1").Result()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(res60["totalSamples"]) // >>> 0
|
|
// STEP_END
|
|
|
|
// Output:
|
|
// 2
|
|
// 1
|
|
// 2
|
|
// 3
|
|
// 3
|
|
// 1
|
|
// 3
|
|
// 2
|
|
// 1
|
|
// 3
|
|
// 3
|
|
// 1
|
|
// 0
|
|
}
|