Time series
Ingest and query time series data with Redis
The Redis time series data type lets you store real-valued data points along with the time they were collected. You can combine the values from a selection of time series and query them by time or value range. You can also compute aggregate functions of the data over periods of time and create new time series from the results. When you create a time series, you can specify a maximum retention period for the data, relative to the last reported timestamp, to prevent the time series from growing indefinitely.
Starting from Redis 8.6, time series support NaN (Not a Number) values, which allow you to represent missing or invalid measurements while maintaining the temporal structure of your data.
Time series support very fast reads and writes, making them ideal for applications such as:
- Instrument data logging
- System performance metrics
- Financial market data
- Internet of Things (IoT) sensor data
- Smart metering
- Quality of service (QoS) monitoring
Redis time series are available in Redis Open Source, Redis Software, and Redis Cloud. See Install Redis Open Source or Install Redis Software for full installation instructions.
Create a time series
You can create a new empty time series with the TS.CREATE
command, specifying a key name. Alternatively, if you use TS.ADD
to add data to a time series key that does not exist, it is automatically created (see
Adding data points below for more information about TS.ADD).
> TS.CREATE thermometer:1
OK
> TYPE thermometer:1
TSDB-TYPE
> TS.INFO thermometer:1
1) totalSamples
2) (integer) 0
.
."""
Code samples for time series page:
https://redis.io/docs/latest/develop/data-types/timeseries/
"""
import redis
r = redis.Redis(decode_responses=True)
res1 = r.ts().create("thermometer:1")
print(res1) # >>> True
res2 = r.type("thermometer:1")
print(res2) # >>> TSDB-TYPE
res3 = r.ts().info("thermometer:1")
print(res3)
# >>> {'rules': [], ... 'total_samples': 0, ...
res4 = r.ts().add("thermometer:2", 1, 10.8, retention_msecs=100)
print(res4) # >>> 1
res5 = r.ts().info("thermometer:2")
print(res5)
# >>> {'rules': [], ... 'retention_msecs': 100, ...
res6 = r.ts().create(
"thermometer:3", 1, 10.4,
labels={"location": "UK", "type": "Mercury"}
)
print(res6) # >>> 1
res7 = r.ts().info("thermometer:3")
print(res7)
# >>> {'rules': [], ... 'labels': {'location': 'UK', 'type': 'Mercury'}, ...
res8 = r.ts().madd([
("thermometer:1", 1, 9.2),
("thermometer:1", 2, 9.9),
("thermometer:2", 2, 10.3)
])
print(res8) # >>> [1, 2, 2]
# The last recorded temperature for thermometer:2
# was 10.3 at time 2.
res9 = r.ts().get("thermometer:2")
print(res9) # >>> (2, 10.3)
# Add 5 data points to a time series named "rg:1".
res10 = r.ts().create("rg:1")
print(res10) # >>> True
res11 = r.ts().madd([
("rg:1", 0, 18),
("rg:1", 1, 14),
("rg:1", 2, 22),
("rg:1", 3, 18),
("rg:1", 4, 24),
])
print(res11) # >>> [0, 1, 2, 3, 4]
# Retrieve all the data points in ascending order.
res12 = r.ts().range("rg:1", "-", "+")
print(res12) # >>> [(0, 18.0), (1, 14.0), (2, 22.0), (3, 18.0), (4, 24.0)]
# Retrieve data points up to time 1 (inclusive).
res13 = r.ts().range("rg:1", "-", 1)
print(res13) # >>> [(0, 18.0), (1, 14.0)]
# Retrieve data points from time 3 onwards.
res14 = r.ts().range("rg:1", 3, "+")
print(res14) # >>> [(3, 18.0), (4, 24.0)]
# Retrieve all the data points in descending order.
res15 = r.ts().revrange("rg:1", "-", "+")
print(res15) # >>> [(4, 24.0), (3, 18.0), (2, 22.0), (1, 14.0), (0, 18.0)]
# Retrieve data points up to time 1 (inclusive), but return them
# in descending order.
res16 = r.ts().revrange("rg:1", "-", 1)
print(res16) # >>> [(1, 14.0), (0, 18.0)]
res17 = r.ts().range("rg:1", "-", "+", filter_by_ts=[0, 2, 4])
print(res17) # >>> [(0, 18.0), (2, 22.0), (4, 24.0)]
res18 = r.ts().revrange(
"rg:1", "-", "+",
filter_by_ts=[0, 2, 4],
filter_by_min_value=20,
filter_by_max_value=25,
)
print(res18) # >>> [(4, 24.0), (2, 22.0)]
res19 = r.ts().revrange(
"rg:1", "-", "+",
filter_by_ts=[0, 2, 4],
filter_by_min_value=22,
filter_by_max_value=22,
count=1,
)
print(res19) # >>> [(2, 22.0)]
# Create three new "rg:" time series (two in the US
# and one in the UK, with different units) and add some
# data points.
res20 = r.ts().create(
"rg:2",
labels={"location": "us", "unit": "cm"},
)
print(res20) # >>> True
res21 = r.ts().create(
"rg:3",
labels={"location": "us", "unit": "in"},
)
print(res21) # >>> True
res22 = r.ts().create(
"rg:4",
labels={"location": "uk", "unit": "mm"},
)
print(res22) # >>> True
res23 = r.ts().madd([
("rg:2", 0, 1.8),
("rg:3", 0, 0.9),
("rg:4", 0, 25),
])
print(res23) # >>> [0, 0, 0]
res24 = r.ts().madd([
("rg:2", 1, 2.1),
("rg:3", 1, 0.77),
("rg:4", 1, 18),
])
print(res24) # >>> [1, 1, 1]
res25 = r.ts().madd([
("rg:2", 2, 2.3),
("rg:3", 2, 1.1),
("rg:4", 2, 21),
])
print(res25) # >>> [2, 2, 2]
res26 = r.ts().madd([
("rg:2", 3, 1.9),
("rg:3", 3, 0.81),
("rg:4", 3, 19),
])
print(res26) # >>> [3, 3, 3]
res27 = r.ts().madd([
("rg:2", 4, 1.78),
("rg:3", 4, 0.74),
("rg:4", 4, 23),
])
print(res27) # >>> [4, 4, 4]
# Retrieve the last data point from each US time series. If
# you don't specify any labels, an empty array is returned
# for the labels.
res28 = r.ts().mget(["location=us"])
print(res28) # >>> [{'rg:2': [{}, 4, 1.78]}, {'rg:3': [{}, 4, 0.74]}]
# Retrieve the same data points, but include the `unit`
# label in the results.
res29 = r.ts().mget(["location=us"], select_labels=["unit"])
print(res29) # >>> [{'unit': 'cm'}, (4, 1.78), {'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.
res30 = r.ts().mrange(
"-", 2, filters=["unit=mm"], with_labels=True
)
print(res30)
# >>> [{'rg:4': [{'location': 'uk', 'unit': 'mm'}, [(0, 25.4),...
# 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 = r.ts().mrevrange(
1, 3, filters=["unit=(cm,mm)"], select_labels=["location"]
)
print(res31)
# >>> [[{'location': 'uk'}, (3, 19.0), (2, 21.0), (1, 18.0)],...
res32 = r.ts().range(
"rg:2", "-", "+",
aggregation_type="avg",
bucket_size_msec=2
)
print(res32)
# >>> [(0, 1.9500000000000002), (2, 2.0999999999999996), (4, 1.78)]
res33 = r.ts().create("sensor3")
print(res33) # >>> True
res34 = r.ts().madd([
("sensor3", 10, 1000),
("sensor3", 20, 2000),
("sensor3", 30, 3000),
("sensor3", 40, 4000),
("sensor3", 50, 5000),
("sensor3", 60, 6000),
("sensor3", 70, 7000),
])
print(res34) # >>> [10, 20, 30, 40, 50, 60, 70]
res35 = r.ts().range(
"sensor3", 10, 70,
aggregation_type="min",
bucket_size_msec=25
)
print(res35)
# >>> [(0, 1000.0), (25, 3000.0), (50, 5000.0)]
res36 = r.ts().range(
"sensor3", 10, 70,
aggregation_type="min",
bucket_size_msec=25,
align="START"
)
print(res36)
# >>> [(10, 1000.0), (35, 4000.0), (60, 6000.0)]
res37 = r.ts().create(
"wind:1",
labels={"country": "uk"}
)
print(res37) # >>> True
res38 = r.ts().create(
"wind:2",
labels={"country": "uk"}
)
print(res38) # >>> True
res39 = r.ts().create(
"wind:3",
labels={"country": "us"}
)
print(res39) # >>> True
res40 = r.ts().create(
"wind:4",
labels={"country": "us"}
)
print(res40) # >>> True
res41 = r.ts().madd([
("wind:1", 1, 12),
("wind:2", 1, 18),
("wind:3", 1, 5),
("wind:4", 1, 20),
])
print(res41) # >>> [1, 1, 1, 1]
res42 = r.ts().madd([
("wind:1", 2, 14),
("wind:2", 2, 21),
("wind:3", 2, 4),
("wind:4", 2, 25),
])
print(res42) # >>> [2, 2, 2, 2]
res43 = r.ts().madd([
("wind:1", 3, 10),
("wind:2", 3, 24),
("wind:3", 3, 8),
("wind:4", 3, 18),
])
print(res43) # >>> [3, 3, 3, 3]
# The result pairs contain the timestamp and the maximum sample value
# for the country at that timestamp.
res44 = r.ts().mrange(
"-", "+",
filters=["country=(us,uk)"],
groupby="country",
reduce="max"
)
print(res44)
# >>> [{'country=uk': [{}, [(1, 18.0), (2, 21.0), (3, 24.0)]]}, ...
# The result pairs contain the timestamp and the average sample value
# for the country at that timestamp.
res45 = r.ts().mrange(
"-", "+",
filters=["country=(us,uk)"],
groupby="country",
reduce="avg"
)
print(res45)
# >>> [{'country=uk': [{}, [(1, 15.0), (2, 17.5), (3, 17.0)]]}, ...
res45 = r.ts().create("hyg:1")
print(res45) # >>> True
res46 = r.ts().create("hyg:compacted")
print(res46) # >>> True
res47 = r.ts().createrule("hyg:1", "hyg:compacted", "min", 3)
print(res47) # >>> True
res48 = r.ts().info("hyg:1")
print(res48.rules)
# >>> [['hyg:compacted', 3, 'MIN', 0]]
res49 = r.ts().info("hyg:compacted")
print(res49.source_key) # >>> 'hyg:1'
res50 = r.ts().madd([
("hyg:1", 0, 75),
("hyg:1", 1, 77),
("hyg:1", 2, 78),
])
print(res50) # >>> [0, 1, 2]
res51 = r.ts().range("hyg:compacted", "-", "+")
print(res51) # >>> []
res52 = r.ts().add("hyg:1", 3, 79)
print(res52) # >>> 3
res53 = r.ts().range("hyg:compacted", "-", "+")
print(res53) # >>> [(0, 75.0)]
res54 = r.ts().info("thermometer:1")
print(res54.total_samples) # >>> 2
print(res54.first_timestamp) # >>> 1
print(res54.last_timestamp) # >>> 2
res55 = r.ts().add("thermometer:1", 3, 9.7)
print(res55) # >>> 3
res56 = r.ts().info("thermometer:1")
print(res56.total_samples) # >>> 3
print(res56.first_timestamp) # >>> 1
print(res56.last_timestamp) # >>> 3
res57 = r.ts().delete("thermometer:1", 1, 2)
print(res57) # >>> 2
res58 = r.ts().info("thermometer:1")
print(res58.total_samples) # >>> 1
print(res58.first_timestamp) # >>> 3
print(res58.last_timestamp) # >>> 3
res59 = r.ts().delete("thermometer:1", 3, 3)
print(res59) # >>> 1
res60 = r.ts().info("thermometer:1")
print(res60.total_samples) # >>> 0
import assert from 'assert';
import { createClient } from 'redis';
import { TIME_SERIES_AGGREGATION_TYPE, TIME_SERIES_REDUCERS } from '@redis/time-series';
const client = createClient();
await client.connect();
const res1 = await client.ts.create('thermometer:1');
console.log(res1); // >>> OK
const res2 = await client.type('thermometer:1');
console.log(res2); // >>> TSDB-TYPE
const res3 = await client.ts.info('thermometer:1');
console.log(res3);
// >>> { rules: [], ... totalSamples: 0, ...
const res4 = await client.ts.add('thermometer:2', 1, 10.8, { RETENTION: 100 });
console.log(res4); // >>> 1
const res5 = await client.ts.info('thermometer:2');
console.log(res5);
// >>> { rules: [], ... retentionTime: 100, ...
const res6 = await client.ts.add('thermometer:3', 1, 10.4, {
LABELS: { location: 'UK', type: 'Mercury' }
});
console.log(res6); // >>> 1
const res7 = await client.ts.info('thermometer:3');
console.log(res7);
// >>> { labels: [{ name: 'location', value: 'UK' }, { name: 'type', value: 'Mercury' }], ... }
const res8 = await client.ts.mAdd([
{ key: 'thermometer:1', timestamp: 1, value: 9.2 },
{ key: 'thermometer:1', timestamp: 2, value: 9.9 },
{ key: 'thermometer:2', timestamp: 2, value: 10.3 }
]);
console.log(res8); // >>> [1, 2, 2]
// The last recorded temperature for thermometer:2
// was 10.3 at time 2.
const res9 = await client.ts.get('thermometer:2');
console.log(res9); // >>> { timestamp: 2, value: 10.3 }
// Add 5 data points to a time series named "rg:1".
const res10 = await client.ts.create('rg:1');
console.log(res10); // >>> OK
const res11 = await client.ts.mAdd([
{ key: 'rg:1', timestamp: 0, value: 18 },
{ key: 'rg:1', timestamp: 1, value: 14 },
{ key: 'rg:1', timestamp: 2, value: 22 },
{ key: 'rg:1', timestamp: 3, value: 18 },
{ key: 'rg:1', timestamp: 4, value: 24 }
]);
console.log(res11); // >>> [0, 1, 2, 3, 4]
// Retrieve all the data points in ascending order.
const res12 = await client.ts.range('rg:1', '-', '+');
console.log(res12);
// >>> [{ timestamp: 0, value: 18 }, { timestamp: 1, value: 14 }, ...]
// Retrieve data points up to time 1 (inclusive).
const res13 = await client.ts.range('rg:1', '-', 1);
console.log(res13);
// >>> [{ timestamp: 0, value: 18 }, { timestamp: 1, value: 14 }]
// Retrieve data points from time 3 onwards.
const res14 = await client.ts.range('rg:1', 3, '+');
console.log(res14);
// >>> [{ timestamp: 3, value: 18 }, { timestamp: 4, value: 24 }]
// Retrieve all the data points in descending order.
const res15 = await client.ts.revRange('rg:1', '-', '+');
console.log(res15);
// >>> [{ timestamp: 4, value: 24 }, { timestamp: 3, value: 18 }, ...]
// Retrieve data points up to time 1 (inclusive), but return them
// in descending order.
const res16 = await client.ts.revRange('rg:1', '-', 1);
console.log(res16);
// >>> [{ timestamp: 1, value: 14 }, { timestamp: 0, value: 18 }]
const res17 = await client.ts.range('rg:1', '-', '+', {
FILTER_BY_TS: [0, 2, 4]
});
console.log(res17);
// >>> [{ timestamp: 0, value: 18 }, { timestamp: 2, value: 22 }, { timestamp: 4, value: 24 }]
const res18 = await client.ts.revRange('rg:1', '-', '+', {
FILTER_BY_TS: [0, 2, 4],
FILTER_BY_VALUE: { min: 20, max: 25 }
});
console.log(res18);
// >>> [{ timestamp: 4, value: 24 }, { timestamp: 2, value: 22 }]
const res19 = await client.ts.revRange('rg:1', '-', '+', {
FILTER_BY_TS: [0, 2, 4],
FILTER_BY_VALUE: { min: 22, max: 22 },
COUNT: 1
});
console.log(res19);
// >>> [{ timestamp: 2, value: 22 }]
// Create three new "rg:" time series (two in the US
// and one in the UK, with different units) and add some
// data points.
const res20 = await client.ts.create('rg:2', {
LABELS: { location: 'us', unit: 'cm' }
});
console.log(res20); // >>> OK
const res21 = await client.ts.create('rg:3', {
LABELS: { location: 'us', unit: 'in' }
});
console.log(res21); // >>> OK
const res22 = await client.ts.create('rg:4', {
LABELS: { location: 'uk', unit: 'mm' }
});
console.log(res22); // >>> OK
const res23 = await client.ts.mAdd([
{ key: 'rg:2', timestamp: 0, value: 1.8 },
{ key: 'rg:3', timestamp: 0, value: 0.9 },
{ key: 'rg:4', timestamp: 0, value: 25 }
]);
console.log(res23); // >>> [0, 0, 0]
const res24 = await client.ts.mAdd([
{ key: 'rg:2', timestamp: 1, value: 2.1 },
{ key: 'rg:3', timestamp: 1, value: 0.77 },
{ key: 'rg:4', timestamp: 1, value: 18 }
]);
console.log(res24); // >>> [1, 1, 1]
const res25 = await client.ts.mAdd([
{ key: 'rg:2', timestamp: 2, value: 2.3 },
{ key: 'rg:3', timestamp: 2, value: 1.1 },
{ key: 'rg:4', timestamp: 2, value: 21 }
]);
console.log(res25); // >>> [2, 2, 2]
const res26 = await client.ts.mAdd([
{ key: 'rg:2', timestamp: 3, value: 1.9 },
{ key: 'rg:3', timestamp: 3, value: 0.81 },
{ key: 'rg:4', timestamp: 3, value: 19 }
]);
console.log(res26); // >>> [3, 3, 3]
const res27 = await client.ts.mAdd([
{ key: 'rg:2', timestamp: 4, value: 1.78 },
{ key: 'rg:3', timestamp: 4, value: 0.74 },
{ key: 'rg:4', timestamp: 4, value: 23 }
]);
console.log(res27); // >>> [4, 4, 4]
// Retrieve the last data point from each US time series.
const res28 = await client.ts.mGet(['location=us']);
console.log(res28);
// >>> { "rg:2": { sample: { timestamp: 4, value: 1.78 } }, "rg:3": { sample: { timestamp: 4, value: 0.74 } } }
// Retrieve the same data points, but include the `unit`
// label in the results.
const res29 = await client.ts.mGetSelectedLabels(['location=us'], ['unit']);
console.log(res29);
// >>> { "rg:2": { labels: { unit: 'cm' }, sample: { timestamp: 4, value: 1.78 } }, "rg:3": { labels: { unit: 'in' }, sample: { timestamp: 4, value: 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.
const res30 = await client.ts.mRangeWithLabels('-', 2, 'unit=mm');
console.log(res30);
// >>> { "rg:4": { labels: { location: 'uk', unit: 'mm' }, samples: [
// { timestamp: 0, value: 25 },
// { timestamp: 1, value: 18 },
// { timestamp: 2, value: 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.
const res31 = await client.ts.mRevRangeSelectedLabels(
1, 3,
['location'],
['unit=(cm,mm)']
);
console.log(res31);
// >>> { "rg:2": { labels: { location: 'us' }, samples: [
// { timestamp: 3, value: 1.9 },
// { timestamp: 2, value: 2.3 },
// { timestamp: 1, value: 2.1 }
// ] }, "rg:4": { labels: { location: 'uk' }, samples: [
// { timestamp: 3, value: 19 },
// { timestamp: 2, value: 21 },
// { timestamp: 1, value: 18 }
// ] } }
const res32 = await client.ts.range('rg:2', '-', '+', {
AGGREGATION: {
type: TIME_SERIES_AGGREGATION_TYPE.AVG,
timeBucket: 2
}
});
console.log(res32);
// >>> [{ timestamp: 0, value: 1.9500000000000002 },{ timestamp: 2, value: 2.0999999999999996 }, { timestamp: 4, value: 1.78 }]
const res33 = await client.ts.create('sensor3');
console.log(res33); // >>> OK
const res34 = await client.ts.mAdd([
{ key: 'sensor3', timestamp: 10, value: 1000 },
{ key: 'sensor3', timestamp: 20, value: 2000 },
{ key: 'sensor3', timestamp: 30, value: 3000 },
{ key: 'sensor3', timestamp: 40, value: 4000 },
{ key: 'sensor3', timestamp: 50, value: 5000 },
{ key: 'sensor3', timestamp: 60, value: 6000 },
{ key: 'sensor3', timestamp: 70, value: 7000 }
]);
console.log(res34); // >>> [10, 20, 30, 40, 50, 60, 70]
const res35 = await client.ts.range('sensor3', 10, 70, {
AGGREGATION: {
type: TIME_SERIES_AGGREGATION_TYPE.MIN,
timeBucket: 25
}
});
console.log(res35);
// >>> [{ timestamp: 0, value: 1000 }, { timestamp: 25, value: 3000 }, { timestamp: 50, value: 5000 }]
const res36 = await client.ts.range('sensor3', 10, 70, {
AGGREGATION: {
type: TIME_SERIES_AGGREGATION_TYPE.MIN,
timeBucket: 25
},
ALIGN: 'START'
});
console.log(res36);
// >>> [{ timestamp: 10, value: 1000 }, { timestamp: 35, value: 4000 }, { timestamp: 60, value: 6000 }]
const res37 = await client.ts.create('wind:1', {
LABELS: { country: 'uk' }
});
console.log(res37); // >>> OK
const res38 = await client.ts.create('wind:2', {
LABELS: { country: 'uk' }
});
console.log(res38); // >>> OK
const res39 = await client.ts.create('wind:3', {
LABELS: { country: 'us' }
});
console.log(res39); // >>> OK
const res40 = await client.ts.create('wind:4', {
LABELS: { country: 'us' }
});
console.log(res40); // >>> OK
const res41 = await client.ts.mAdd([
{ key: 'wind:1', timestamp: 1, value: 12 },
{ key: 'wind:2', timestamp: 1, value: 18 },
{ key: 'wind:3', timestamp: 1, value: 5 },
{ key: 'wind:4', timestamp: 1, value: 20 }
]);
console.log(res41); // >>> [1, 1, 1, 1]
const res42 = await client.ts.mAdd([
{ key: 'wind:1', timestamp: 2, value: 14 },
{ key: 'wind:2', timestamp: 2, value: 21 },
{ key: 'wind:3', timestamp: 2, value: 4 },
{ key: 'wind:4', timestamp: 2, value: 25 }
]);
console.log(res42); // >>> [2, 2, 2, 2]
const res43 = await client.ts.mAdd([
{ key: 'wind:1', timestamp: 3, value: 10 },
{ key: 'wind:2', timestamp: 3, value: 24 },
{ key: 'wind:3', timestamp: 3, value: 8 },
{ key: 'wind:4', timestamp: 3, value: 18 }
]);
console.log(res43); // >>> [3, 3, 3, 3]
// The result pairs contain the timestamp and the maximum sample value
// for the country at that timestamp.
const res44 = await client.ts.mRangeGroupBy(
'-', '+', ['country=(us,uk)'],
{label: 'country', REDUCE: TIME_SERIES_REDUCERS.MAX}
);
console.log(res44);
// >>> { "country=uk": { samples: [
// { timestamp: 1, value: 18 },
// { timestamp: 2, value: 21 },
// { timestamp: 3, value: 24 }
// ] }, "country=us": { samples: [
// { timestamp: 1, value: 20 },
// { timestamp: 2, value: 25 },
// { timestamp: 3, value: 18 }
// ] } }
// The result pairs contain the timestamp and the average sample value
// for the country at that timestamp.
const res45 = await client.ts.mRangeGroupBy(
'-', '+', ['country=(us,uk)'],
{ label: 'country', REDUCE: TIME_SERIES_REDUCERS.AVG}
);
console.log(res45);
// >>> {
// "country=uk": {
// samples: [{ timestamp: 1, value: 15 }, { timestamp: 2, value: 17.5 }, { timestamp: 3, value: 17 }]
// },
// "country=us": {
// samples: [{ timestamp: 1, value: 12.5 }, { timestamp: 2, value: 14.5 }, { timestamp: 3, value: 13 }]
// }
// }
const res46 = await client.ts.create('hyg:1');
console.log(res46); // >>> OK
const res47 = await client.ts.create('hyg:compacted');
console.log(res47); // >>> OK
const res48 = await client.ts.createRule('hyg:1', 'hyg:compacted', TIME_SERIES_AGGREGATION_TYPE.MIN, 3);
console.log(res48); // >>> OK
const res49 = await client.ts.info('hyg:1');
console.log(res49.rules);
// >>> [{ aggregationType: 'MIN', key: 'hyg:compacted', timeBucket: 3}]
const res50 = await client.ts.info('hyg:compacted');
console.log(res50.sourceKey); // >>> 'hyg:1'
const res51 = await client.ts.mAdd([
{ key: 'hyg:1', timestamp: 0, value: 75 },
{ key: 'hyg:1', timestamp: 1, value: 77 },
{ key: 'hyg:1', timestamp: 2, value: 78 }
]);
console.log(res51); // >>> [0, 1, 2]
const res52 = await client.ts.range('hyg:compacted', '-', '+');
console.log(res52); // >>> []
const res53 = await client.ts.add('hyg:1', 3, 79);
console.log(res53); // >>> 3
const res54 = await client.ts.range('hyg:compacted', '-', '+');
console.log(res54); // >>> [{ timestamp: 0, value: 75 }]
const res55 = await client.ts.info('thermometer:1');
console.log(res55.totalSamples); // >>> 2
console.log(res55.firstTimestamp); // >>> 1
console.log(res55.lastTimestamp); // >>> 2
const res56 = await client.ts.add('thermometer:1', 3, 9.7);
console.log(res56); // >>> 3
const res57 = await client.ts.info('thermometer:1');
console.log(res57.totalSamples); // >>> 3
console.log(res57.firstTimestamp); // >>> 1
console.log(res57.lastTimestamp); // >>> 3
const res58 = await client.ts.del('thermometer:1', 1, 2);
console.log(res58); // >>> 2
const res59 = await client.ts.info('thermometer:1');
console.log(res59.totalSamples); // >>> 1
console.log(res59.firstTimestamp); // >>> 3
console.log(res59.lastTimestamp); // >>> 3
const res60 = await client.ts.del('thermometer:1', 3, 3);
console.log(res60); // >>> 1
const res61 = await client.ts.info('thermometer:1');
console.log(res61.totalSamples); // >>> 0
await client.quit();
import redis.clients.jedis.RedisClient;
import redis.clients.jedis.timeseries.*;
import redis.clients.jedis.timeseries.TSElement;
import java.util.*;
public class TimeSeriesTutorialExample {
public void run() {
RedisClient jedis = RedisClient.create("redis://localhost:6379");
String res1 = jedis.tsCreate("thermometer:1");
System.out.println(res1); // >>> OK
String res2 = jedis.type("thermometer:1");
System.out.println(res2); // >>> TSDB-TYPE
TSInfo res3 = jedis.tsInfo("thermometer:1");
System.out.println(res3.getProperty("totalSamples")); // >>> 0
long res4 = jedis.tsAdd("thermometer:2", 1L, 10.8,
TSCreateParams.createParams().retention(100));
System.out.println(res4); // >>> 1
TSInfo res5 = jedis.tsInfo("thermometer:2");
System.out.println(res5.getProperty("retentionTime")); // >>> 100
Map<String, String> labels = new HashMap<>();
labels.put("location", "UK");
labels.put("type", "Mercury");
long res6 = jedis.tsAdd("thermometer:3", 1L, 10.4,
TSCreateParams.createParams().labels(labels));
System.out.println(res6); // >>> 1
TSInfo res7 = jedis.tsInfo("thermometer:3");
System.out.println("Labels: " + res7.getLabels());
// >>> Labels: {location=UK, type=Mercury}
List<Long> res8 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("thermometer:1", new TSElement(1L, 9.2)),
new AbstractMap.SimpleEntry<>("thermometer:1", new TSElement(2L, 9.9)),
new AbstractMap.SimpleEntry<>("thermometer:2", new TSElement(2L, 10.3))
);
System.out.println(res8); // >>> [1, 2, 2]
// The last recorded temperature for thermometer:2
// was 10.3 at time 2.
TSElement res9 = jedis.tsGet("thermometer:2");
System.out.println("(" + res9.getTimestamp() + ", " + res9.getValue() + ")");
// >>> (2, 10.3)
// Add 5 data points to a time series named "rg:1"
String res10 = jedis.tsCreate("rg:1");
System.out.println(res10); // >>> OK
List<Long> res11 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:1", new TSElement(0L, 18.0)),
new AbstractMap.SimpleEntry<>("rg:1", new TSElement(1L, 14.0)),
new AbstractMap.SimpleEntry<>("rg:1", new TSElement(2L, 22.0)),
new AbstractMap.SimpleEntry<>("rg:1", new TSElement(3L, 18.0)),
new AbstractMap.SimpleEntry<>("rg:1", new TSElement(4L, 24.0))
);
System.out.println(res11); // >>> [0, 1, 2, 3, 4]
// Retrieve all the data points in ascending order
List<TSElement> res12 = jedis.tsRange("rg:1", 0L, 4L);
System.out.println(res12);
// >>> [(0:18.0), (1:14.0), (2:22.0), (3:18.0), (4:24.0)]
// Retrieve data points up to time 1 (inclusive)
List<TSElement> res13 = jedis.tsRange("rg:1", 0L, 1L);
System.out.println(res13);
// >>> [(0:18.0), (1:14.0)]
// Retrieve data points from time 3 onwards
List<TSElement> res14 = jedis.tsRange("rg:1", 3L, 4L);
System.out.println(res14);
// >>> [(3:18.0), (4:24.0)]
// Retrieve all the data points in descending order
List<TSElement> res15 = jedis.tsRevRange("rg:1", 0L, 4L);
System.out.println(res15);
// >>> [(4:24.0), (3:18.0), (2:22.0), (1:14.0), (0:18.0)]
// Retrieve data points up to time 1 (inclusive), in descending order
List<TSElement> res16 = jedis.tsRevRange("rg:1", 0L, 1L);
System.out.println(res16);
// >>> [(1:14.0), (0:18.0)]
List<TSElement> res17 = jedis.tsRange("rg:1",
TSRangeParams.rangeParams()
.fromTimestamp(0L)
.toTimestamp(4L)
.filterByTS(0L, 2L, 4L)
);
System.out.println(res17);
// >>> [(0:18.0), (2:22.0), (4:24.0)]
List<TSElement> res18 = jedis.tsRevRange("rg:1",
TSRangeParams.rangeParams()
.fromTimestamp(0L)
.toTimestamp(4L)
.filterByTS(0L, 2L, 4L)
.filterByValues(20.0, 25.0)
);
System.out.println(res18);
// >>> [(4:24.0), (2:22.0)]
List<TSElement> res19 = jedis.tsRevRange("rg:1",
TSRangeParams.rangeParams()
.fromTimestamp(0L)
.toTimestamp(4L)
.filterByTS(0L, 2L, 4L)
.filterByValues(22.0, 22.0)
.count(1)
);
System.out.println(res19);
// >>> [(2:22.0)]
// Create three new "rg:" time series (two in the US
// and one in the UK, with different units) and add some
// data points.
Map<String, String> usLabels1 = new HashMap<>();
usLabels1.put("location", "us");
usLabels1.put("unit", "cm");
Map<String, String> usLabels2 = new HashMap<>();
usLabels2.put("location", "us");
usLabels2.put("unit", "in");
Map<String, String> ukLabels = new HashMap<>();
ukLabels.put("location", "uk");
ukLabels.put("unit", "mm");
String res20 = jedis.tsCreate("rg:2",
TSCreateParams.createParams().labels(usLabels1));
System.out.println(res20); // >>> OK
String res21 = jedis.tsCreate("rg:3",
TSCreateParams.createParams().labels(usLabels2));
System.out.println(res21); // >>> OK
String res22 = jedis.tsCreate("rg:4",
TSCreateParams.createParams().labels(ukLabels));
System.out.println(res22); // >>> OK
List<Long> res23 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:2", new TSElement(0L, 1.8)),
new AbstractMap.SimpleEntry<>("rg:3", new TSElement(0L, 0.9)),
new AbstractMap.SimpleEntry<>("rg:4", new TSElement(0L, 25.0))
);
System.out.println(res23); // >>> [0, 0, 0]
List<Long> res24 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:2", new TSElement(1L, 2.1)),
new AbstractMap.SimpleEntry<>("rg:3", new TSElement(1L, 0.77)),
new AbstractMap.SimpleEntry<>("rg:4", new TSElement(1L, 18.0))
);
System.out.println(res24); // >>> [1, 1, 1]
List<Long> res25 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:2", new TSElement(2L, 2.3)),
new AbstractMap.SimpleEntry<>("rg:3", new TSElement(2L, 1.1)),
new AbstractMap.SimpleEntry<>("rg:4", new TSElement(2L, 21.0))
);
System.out.println(res25); // >>> [2, 2, 2]
List<Long> res26 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:2", new TSElement(3L, 1.9)),
new AbstractMap.SimpleEntry<>("rg:3", new TSElement(3L, 0.81)),
new AbstractMap.SimpleEntry<>("rg:4", new TSElement(3L, 19.0))
);
System.out.println(res26); // >>> [3, 3, 3]
List<Long> res27 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:2", new TSElement(4L, 1.78)),
new AbstractMap.SimpleEntry<>("rg:3", new TSElement(4L, 0.74)),
new AbstractMap.SimpleEntry<>("rg:4", new TSElement(4L, 23.0))
);
System.out.println(res27); // >>> [4, 4, 4]
// Retrieve the last data point from each US time series.
Map<String, TSMGetElement> res28 = jedis.tsMGet(
TSMGetParams.multiGetParams().latest(),
"location=us"
);
System.out.println(res28);
// >>> {rg:2=TSMGetElement{key=rg:2, labels={}, element=(4:1.78)}...
// Retrieve the same data points, but include the `unit`
// label in the results.
Map<String, TSMGetElement> res29 = jedis.tsMGet(
TSMGetParams.multiGetParams().selectedLabels("unit"),
"location=us"
);
System.out.println(res29);
// >>> {rg:2=TSMGetElement{key=rg:2, labels={unit=cm}, element=(4:1.78)}...
// Retrieve data points up to time 2 (inclusive) from all
// time series that use millimeters as the unit. Include all
// labels in the results.
Map<String, TSMRangeElements> res30 = jedis.tsMRange(
TSMRangeParams.multiRangeParams(0L, 2L)
.withLabels()
.filter("unit=mm")
);
System.out.println(res30);
// >>> {rg:4=TSMRangeElements{key=rg:4, labels={location=uk, unit=mm}, value=[(0:25.0), (1:18.0), (2:21.0)]}}
// 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.
Map<String, TSMRangeElements> res31 = jedis.tsMRevRange(
TSMRangeParams.multiRangeParams(1L, 3L)
.selectedLabels("location")
.filter("unit=(cm,mm)")
);
System.out.println(res31);
// >>> {rg:2=TSMRangeElements{key=rg:2, labels={location=us, unit=cm}, value=[(1:2.1)...
List<TSElement> res32 = jedis.tsRange("rg:2",
TSRangeParams.rangeParams()
.fromTimestamp(0L)
.toTimestamp(4L)
.aggregation(AggregationType.AVG, 2)
);
System.out.println(res32);
// >>> [(0:1.9500000000000002), (2:2.0999999999999996), (4:1.78)]
String res33 = jedis.tsCreate("sensor3");
System.out.println(res33); // >>> OK
List<Long> res34 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("sensor3", new TSElement(10L, 1000.0)),
new AbstractMap.SimpleEntry<>("sensor3", new TSElement(20L, 2000.0)),
new AbstractMap.SimpleEntry<>("sensor3", new TSElement(30L, 3000.0)),
new AbstractMap.SimpleEntry<>("sensor3", new TSElement(40L, 4000.0)),
new AbstractMap.SimpleEntry<>("sensor3", new TSElement(50L, 5000.0)),
new AbstractMap.SimpleEntry<>("sensor3", new TSElement(60L, 6000.0)),
new AbstractMap.SimpleEntry<>("sensor3", new TSElement(70L, 7000.0))
);
System.out.println(res34); // >>> [10, 20, 30, 40, 50, 60, 70]
List<TSElement> res35 = jedis.tsRange("sensor3",
TSRangeParams.rangeParams()
.fromTimestamp(10L)
.toTimestamp(70L)
.aggregation(AggregationType.MIN, 25)
);
System.out.println(res35);
// >>> [(0:1000.0), (25:3000.0), (50:5000.0)]
List<TSElement> res36 = jedis.tsRange("sensor3",
TSRangeParams.rangeParams()
.fromTimestamp(10L)
.toTimestamp(70L)
.aggregation(AggregationType.MIN, 25)
.alignStart()
);
System.out.println(res36);
// >>> [(10:1000.0), (35:4000.0), (60:6000.0)]
Map<String, String> ukCountry = new HashMap<>();
ukCountry.put("country", "uk");
Map<String, String> usCountry = new HashMap<>();
usCountry.put("country", "us");
jedis.tsCreate("wind:1", TSCreateParams.createParams().labels(ukCountry));
jedis.tsCreate("wind:2", TSCreateParams.createParams().labels(ukCountry));
jedis.tsCreate("wind:3", TSCreateParams.createParams().labels(usCountry));
jedis.tsCreate("wind:4", TSCreateParams.createParams().labels(usCountry));
jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("wind:1", new TSElement(0L, 10.0)),
new AbstractMap.SimpleEntry<>("wind:2", new TSElement(0L, 12.0)),
new AbstractMap.SimpleEntry<>("wind:3", new TSElement(0L, 8.0)),
new AbstractMap.SimpleEntry<>("wind:4", new TSElement(0L, 15.0))
);
jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("wind:1", new TSElement(1L, 11.0)),
new AbstractMap.SimpleEntry<>("wind:2", new TSElement(1L, 13.0)),
new AbstractMap.SimpleEntry<>("wind:3", new TSElement(1L, 9.0)),
new AbstractMap.SimpleEntry<>("wind:4", new TSElement(1L, 16.0))
);
jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("wind:1", new TSElement(2L, 9.0)),
new AbstractMap.SimpleEntry<>("wind:2", new TSElement(2L, 11.0)),
new AbstractMap.SimpleEntry<>("wind:3", new TSElement(2L, 7.0)),
new AbstractMap.SimpleEntry<>("wind:4", new TSElement(2L, 14.0))
);
jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("wind:1", new TSElement(3L, 12.0)),
new AbstractMap.SimpleEntry<>("wind:2", new TSElement(3L, 14.0)),
new AbstractMap.SimpleEntry<>("wind:3", new TSElement(3L, 10.0)),
new AbstractMap.SimpleEntry<>("wind:4", new TSElement(3L, 17.0))
);
jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("wind:1", new TSElement(4L, 8.0)),
new AbstractMap.SimpleEntry<>("wind:2", new TSElement(4L, 10.0)),
new AbstractMap.SimpleEntry<>("wind:3", new TSElement(4L, 6.0)),
new AbstractMap.SimpleEntry<>("wind:4", new TSElement(4L, 13.0))
);
// Group by country with max reduction
Map<String, TSMRangeElements> res44 = jedis.tsMRange(
TSMRangeParams.multiRangeParams(0L, 4L)
.filter("country=(us,uk)")
.groupBy("country", "max"));
System.out.println(res44);
// >>> {country=uk=TSMRangeElements{key=country=uk, labels={}, value=[(0:12.0)...
// Group by country with avg reduction
Map<String, TSMRangeElements> res45 = jedis.tsMRange(
TSMRangeParams.multiRangeParams(0L, 4L)
.filter("country=(us,uk)")
.groupBy("country", "avg"));
System.out.println(res45);
// >>> {country=uk=TSMRangeElements{key=country=uk, labels={}, value=[(0:11.0)...
String res46 = jedis.tsCreate("hyg:1");
System.out.println(res46); // >>> OK
String res47 = jedis.tsCreate("hyg:compacted");
System.out.println(res47); // >>> OK
String res48 = jedis.tsCreateRule("hyg:1", "hyg:compacted", AggregationType.MIN, 3);
System.out.println(res48); // >>> OK
TSInfo res49 = jedis.tsInfo("hyg:1");
System.out.println("Rules: " + res49.getProperty("rules"));
// >>> Rules: [{compactionKey=hyg:compacted, bucketDuration=3, aggregationType=MIN, alignmentTimestamp=0}]
TSInfo res50 = jedis.tsInfo("hyg:compacted");
System.out.println("Source key: " + res50.getProperty("sourceKey"));
// >>> Source key: hyg:1
List<Long> res51 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("hyg:1", new TSElement(0L, 75.0)),
new AbstractMap.SimpleEntry<>("hyg:1", new TSElement(1L, 77.0)),
new AbstractMap.SimpleEntry<>("hyg:1", new TSElement(2L, 78.0))
);
System.out.println(res51); // >>> [0, 1, 2]
List<TSElement> res52 = jedis.tsRange("hyg:compacted", 0L, 10L);
System.out.println(res52); // >>> []
long res53 = jedis.tsAdd("hyg:1", 3L, 79.0);
System.out.println(res53); // >>> 3
List<TSElement> res54 = jedis.tsRange("hyg:compacted", 0L, 10L);
System.out.println(res54); // >>> [(0:75.0)]
TSInfo res55 = jedis.tsInfo("thermometer:1");
System.out.println(res55.getProperty("totalSamples")); // >>> 2
System.out.println(res55.getProperty("firstTimestamp")); // >>> 1
System.out.println(res55.getProperty("lastTimestamp")); // >>> 2
long res56 = jedis.tsAdd("thermometer:1", 3L, 9.7);
System.out.println(res56); // >>> 3
TSInfo res57 = jedis.tsInfo("thermometer:1");
System.out.println(res57.getProperty("totalSamples")); // >>> 3
long res58 = jedis.tsDel("thermometer:1", 1L, 2L);
System.out.println(res58); // >>> 2
TSInfo res59 = jedis.tsInfo("thermometer:1");
System.out.println(res59.getProperty("totalSamples")); // >>> 1
long res60 = jedis.tsDel("thermometer:1", 3L, 3L);
System.out.println(res60); // >>> 1
TSInfo res61 = jedis.tsInfo("thermometer:1");
System.out.println(res61.getProperty("totalSamples")); // >>> 0
jedis.close();
}
}
package example_commands_test
import (
"context"
"fmt"
"maps"
"math"
"slices"
"sort"
"github.com/redis/go-redis/v9"
)
func ExampleClient_timeseries_create() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
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
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
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]
}
func ExampleClient_timeseries_add() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
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]
// 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}
}
func ExampleClient_timeseries_range() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
// 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}]
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}]
}
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
})
// 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}]
}
func ExampleClient_timeseries_aggregation() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
// 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)
}
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}]
}
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
})
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}]
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}]
}
func ExampleClient_timeseries_aggmulti() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
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]]
}
func ExampleClient_timeseries_compaction() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
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
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}]
}
func ExampleClient_timeseries_delete() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
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
}
/*
Code samples for time series page:
https://redis.io/docs/latest/develop/data-types/timeseries/
*/
using NRedisStack.DataTypes;
using NRedisStack.Literals.Enums;
using StackExchange.Redis;
public class TimeSeriesTutorial
{
public void Run()
{
var muxer = ConnectionMultiplexer.Connect("localhost:6379");
var db = muxer.GetDatabase();
bool res1 = db.TS().Create(
"thermometer:1",
new TsCreateParamsBuilder().build()
);
Console.WriteLine(res1); // >>> True
RedisType res2 = db.KeyType("thermometer:1");
Console.WriteLine(res2); // >>> TSDB-TYPE
TimeSeriesInformation res3 = db.TS().Info("thermometer:1");
Console.WriteLine(res3.TotalSamples); // >>> 0
long res4 = db.TS().Add(
"thermometer:2",
new TsAddParamsBuilder()
.AddTimestamp(1)
.AddValue(10.8)
.AddRetentionTime(100)
.build()
);
Console.WriteLine(res4); // >>> 1
TimeSeriesInformation res5 = db.TS().Info("thermometer:2");
Console.WriteLine(res5.RetentionTime);
// >>> 100
var labels = new List<TimeSeriesLabel>
{
new("location", "UK"),
new("type", "Mercury")
};
long res6 = db.TS().Add(
"thermometer:3",
new TsAddParamsBuilder()
.AddTimestamp(1)
.AddValue(10.4)
.AddLabels(labels)
.build()
);
Console.WriteLine(res6); // >>> 1
TimeSeriesInformation res7 = db.TS().Info("thermometer:3");
Console.WriteLine(
$"Labels: {string.Join(", ", res7.Labels!.Select(l => $"{l.Key}={l.Value}"))}"
);
// >>> Labels: location=UK, type=Mercury
var sequence = new List<(string, TimeStamp, double)>
{
("thermometer:1", 1, 9.2),
("thermometer:1", 2, 9.9),
("thermometer:2", 2, 10.3)
};
IReadOnlyList<TimeStamp> res8 = db.TS().MAdd(sequence);
Console.WriteLine($"[{string.Join(", ", res8.Select(t => t.Value))}]");
// >>> [1, 2, 2]
// The last recorded temperature for thermometer:2
// was 10.3 at time 2.
TimeSeriesTuple? res9 = db.TS().Get("thermometer:2");
Console.WriteLine($"({res9!.Time.Value}, {res9.Val})");
// >>> (2, 10.3)
// Add 5 data points to a time series named "rg:1".
bool res10 = db.TS().Create(
"rg:1",
new TsCreateParamsBuilder().build()
);
Console.WriteLine(res10); // >>> True
var sequence2 = new List<(string, TimeStamp, double)>
{
("rg:1", 0, 18),
("rg:1", 1, 14),
("rg:1", 2, 22),
("rg:1", 3, 18),
("rg:1", 4, 24)
};
IReadOnlyList<TimeStamp> res11 = db.TS().MAdd(sequence2);
Console.WriteLine(
$"[{string.Join(", ", res11.Select(t => t.Value))}]"
);
// >>> [0, 1, 2, 3, 4]
// Retrieve all the data points in ascending order.
IReadOnlyList<TimeSeriesTuple> res12 = db.TS().Range("rg:1", "-", "+");
Console.WriteLine(
$"[{string.Join(", ", res12.Select(t => $"({t.Time.Value}, {t.Val})"))}]"
);
// >>> [(0, 18), (1, 14), (2, 22), (3, 18), (4, 24)]
// Retrieve data points up to time 1 (inclusive).
IReadOnlyList<TimeSeriesTuple> res13 = db.TS().Range("rg:1", "-", 1);
Console.WriteLine(
$"[{string.Join(", ", res13.Select(t => $"({t.Time.Value}, {t.Val})"))}]"
);
// >>> [(0, 18), (1, 14)]
// Retrieve data points from time 3 onwards.
IReadOnlyList<TimeSeriesTuple> res14 = db.TS().Range("rg:1", 3, "+");
Console.WriteLine(
$"[{string.Join(", ", res14.Select(t => $"({t.Time.Value}, {t.Val})"))}]"
);
// >>> [(3, 18), (4, 24)]
// Retrieve all the data points in descending order.
IReadOnlyList<TimeSeriesTuple> res15 = db.TS().RevRange("rg:1", "-", "+");
Console.WriteLine(
$"[{string.Join(", ", res15.Select(t => $"({t.Time.Value}, {t.Val})"))}]"
);
// >>> [(4, 24), (3, 18), (2, 22), (1, 14), (0, 18)]
// Retrieve data points up to time 1 (inclusive), but return them
// in descending order.
IReadOnlyList<TimeSeriesTuple> res16 = db.TS().RevRange("rg:1", "-", 1);
Console.WriteLine(
$"[{string.Join(", ", res16.Select(t => $"({t.Time.Value}, {t.Val})"))}]"
);
// >>> [(1, 14), (0, 18)]
var filterByTs = new List<TimeStamp> { 0, 2, 4 };
IReadOnlyList<TimeSeriesTuple> res17 = db.TS().Range(
"rg:1", "-", "+", filterByTs: filterByTs
);
Console.WriteLine(
$"[{string.Join(", ", res17.Select(t => $"({t.Time.Value}, {t.Val})"))}]"
);
// >>> [(0, 18), (2, 22), (4, 24)]
IReadOnlyList<TimeSeriesTuple> res18 = db.TS().RevRange(
"rg:1", "-", "+",
filterByTs: filterByTs,
filterByValue: (20, 25)
);
Console.WriteLine(
$"[{string.Join(", ", res18.Select(t => $"({t.Time.Value}, {t.Val})"))}]"
);
// >>> [(4, 24), (2, 22)]
IReadOnlyList<TimeSeriesTuple> res19 = db.TS().RevRange(
"rg:1", "-", "+",
filterByTs: filterByTs,
filterByValue: (22, 22),
count: 1
);
Console.WriteLine(
$"[{string.Join(", ", res19.Select(t => $"({t.Time.Value}, {t.Val})"))}]"
);
// >>> [(2, 22)]
// Create three new "rg:" time series (two in the US
// and one in the UK, with different units) and add some
// data points.
var labels2 = new List<TimeSeriesLabel>
{
new("location", "us"),
new("unit", "cm")
};
bool res20 = db.TS().Create(
"rg:2",
new TsCreateParamsBuilder()
.AddLabels(labels2)
.build()
);
Console.WriteLine(res20); // >>> True
var labels3 = new List<TimeSeriesLabel>
{
new("location", "us"),
new("unit", "in")
};
bool res21 = db.TS().Create(
"rg:3",
new TsCreateParamsBuilder()
.AddLabels(labels3)
.build()
);
Console.WriteLine(res21); // >>> True
var labels4 = new List<TimeSeriesLabel>
{
new("location", "uk"),
new("unit", "mm")
};
bool res22 = db.TS().Create(
"rg:4",
new TsCreateParamsBuilder()
.AddLabels(labels4)
.build()
);
Console.WriteLine(res22); // >>> True
var sequence3 = new List<(string, TimeStamp, double)>
{
("rg:2", 0, 1.8),
("rg:3", 0, 0.9),
("rg:4", 0, 25)
};
IReadOnlyList<TimeStamp> res23 = db.TS().MAdd(sequence3);
Console.WriteLine(
$"[{string.Join(", ", res23.Select(t => t.Value))}]"
);
// >>> [0, 0, 0]
var sequence4 = new List<(string, TimeStamp, double)>
{
("rg:2", 1, 2.1),
("rg:3", 1, 0.77),
("rg:4", 1, 18)
};
IReadOnlyList<TimeStamp> res24 = db.TS().MAdd(sequence4);
Console.WriteLine(
$"[{string.Join(", ", res24.Select(t => t.Value))}]"
);
// >>> [1, 1, 1]
var sequence5 = new List<(string, TimeStamp, double)>
{
("rg:2", 2, 2.3),
("rg:3", 2, 1.1),
("rg:4", 2, 21)
};
IReadOnlyList<TimeStamp> res25 = db.TS().MAdd(sequence5);
Console.WriteLine(
$"[{string.Join(", ", res25.Select(t => t.Value))}]"
);
// >>> [2, 2, 2]
var sequence6 = new List<(string, TimeStamp, double)>
{
("rg:2", 3, 1.9),
("rg:3", 3, 0.81),
("rg:4", 3, 19)
};
IReadOnlyList<TimeStamp> res26 = db.TS().MAdd(sequence6);
Console.WriteLine(
$"[{string.Join(", ", res26.Select(t => t.Value))}]"
);
// >>> [3, 3, 3]
var sequence7 = new List<(string, TimeStamp, double)>
{
("rg:2", 4, 1.78),
("rg:3", 4, 0.74),
("rg:4", 4, 23)
};
IReadOnlyList<TimeStamp> res27 = db.TS().MAdd(sequence7);
Console.WriteLine(
$"[{string.Join(", ", res27.Select(t => t.Value))}]"
);
// >>> [4, 4, 4]
// Retrieve the last data point from each US time series. If
// you don't specify any labels, an empty array is returned
// for the labels.
var filters = new List<string> { "location=us" };
var res28 = db.TS().MGet(filters);
Console.WriteLine(res28.Count); // >>> 2
foreach (var (key, labelsResult, value) in res28)
{
Console.WriteLine($"{key}: ({value.Time.Value}, {value.Val})");
}
// >>> rg:2: (4, 1.78)
// >>> rg:3: (4, 0.74)
// Retrieve the same data points, but include the `unit`
// label in the results.
var selectUnitLabel = new List<string> { "unit" };
var res29 = db.TS().MGet(
filters,
selectedLabels: selectUnitLabel
);
Console.WriteLine(res29.Count); // >>> 2
foreach (var (key, labelsResult, value) in res29)
{
var unitLabel = labelsResult.FirstOrDefault(l => l.Key == "unit");
Console.WriteLine($"{key} (unit: {unitLabel?.Value}): ({value.Time.Value}, {value.Val})");
}
// >>> 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.
var mmFilters = new List<string> { "unit=mm" };
IReadOnlyList<
(string, IReadOnlyList<TimeSeriesLabel>, IReadOnlyList<TimeSeriesTuple>)
> res30 = db.TS().MRange(
"-", 2, mmFilters, withLabels: true
);
Console.WriteLine(res30.Count); // >>> 1
foreach (var (key, labelsResult, values) in res30)
{
Console.WriteLine($"{key}:");
Console.WriteLine($" Labels: ({string.Join(", ", labelsResult.Select(l => $"{l.Key}={l.Value}"))})");
Console.WriteLine($" Values: [{string.Join(", ", values.Select(t => $"({t.Time.Value}, {t.Val})"))}]");
}
// >>> rg:4:
// >>> Labels:location=uk,unit=mm
// >>> Values: [(1, 23), (2, 21), (3, 19)]
// 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.
var cmMmFilters = new List<string> { "unit=(cm,mm)" };
var locationLabels = new List<string> { "location" };
IReadOnlyList<
(string, IReadOnlyList<TimeSeriesLabel>, IReadOnlyList<TimeSeriesTuple>)
> res31 = db.TS().MRevRange(
1, 3, cmMmFilters, selectLabels: locationLabels
);
Console.WriteLine(res31.Count); // >>> 2
foreach (var (key, labelsResult, values) in res31)
{
var locationLabel = labelsResult.FirstOrDefault(l => l.Key == "location");
Console.WriteLine($"{key} (location: {locationLabel?.Value})");
Console.WriteLine($" Values: [{string.Join(", ", values.Select(t => $"({t.Time.Value}, {t.Val})"))}]");
}
// >>> rg:4 (location: uk)
// >>> Values: [(3, 19), (2, 21), (1, 23)]
// >>> rg:2 (location: us)
// >>> Values: [(3, 2.3), (2, 2.1), (1, 1.8)]
IReadOnlyList<TimeSeriesTuple> res32 = db.TS().Range(
"rg:2", "-", "+",
aggregation: TsAggregation.Avg,
timeBucket: 2
);
Console.WriteLine($"[{string.Join(", ", res32.Select(t => $"({t.Time.Value}, {t.Val})"))}]");
// >>> [(0, 1.95), (2, 2.1), (4, 1.78)]
bool res33 = db.TS().Create(
"sensor3",
new TsCreateParamsBuilder()
.build()
);
Console.WriteLine(res33); // >>> True
var sensorSequence = new List<(string, TimeStamp, double)>
{
("sensor3", 10, 1000),
("sensor3", 20, 2000),
("sensor3", 30, 3000),
("sensor3", 40, 4000),
("sensor3", 50, 5000),
("sensor3", 60, 6000),
("sensor3", 70, 7000)
};
IReadOnlyList<TimeStamp> res34 = db.TS().MAdd(sensorSequence);
Console.WriteLine($"[{string.Join(", ", res34.Select(t => t.Value))}]");
// >>> [10, 20, 30, 40, 50, 60, 70]
IReadOnlyList<TimeSeriesTuple> res35 = db.TS().Range(
"sensor3", 10, 70,
aggregation: TsAggregation.Min,
timeBucket: 25
);
Console.WriteLine($"[{string.Join(", ", res35.Select(t => $"({t.Time.Value}, {t.Val})"))}]");
// >>> [(0, 1000), (25, 3000), (50, 5000)]
IReadOnlyList<TimeSeriesTuple> res36 = db.TS().Range(
"sensor3", 10, 70,
aggregation: TsAggregation.Min,
timeBucket: 25,
align: "-"
);
Console.WriteLine(
$"[{string.Join(", ", res36.Select(t => $"({t.Time.Value}, {t.Val})"))}]"
);
// >>> [(10, 1000), (35, 4000), (60, 6000)]
var ukLabels = new List<TimeSeriesLabel> { new("country", "uk") };
bool res37 = db.TS().Create(
"wind:1",
new TsCreateParamsBuilder()
.AddLabels(ukLabels)
.build()
);
Console.WriteLine(res37); // >>> True
bool res38 = db.TS().Create(
"wind:2",
new TsCreateParamsBuilder()
.AddLabels(ukLabels)
.build()
);
Console.WriteLine(res38); // >>> True
var usLabels = new List<TimeSeriesLabel> { new("country", "us") };
bool res39 = db.TS().Create(
"wind:3",
new TsCreateParamsBuilder()
.AddLabels(usLabels)
.build()
);
Console.WriteLine(res39); // >>> True
bool res40 = db.TS().Create(
"wind:4",
new TsCreateParamsBuilder()
.AddLabels(usLabels)
.build()
);
Console.WriteLine(res40); // >>> True
var windSequence1 = new List<(string, TimeStamp, double)>
{
("wind:1", 1, 12),
("wind:2", 1, 18),
("wind:3", 1, 5),
("wind:4", 1, 20)
};
IReadOnlyList<TimeStamp> res41 = db.TS().MAdd(windSequence1);
Console.WriteLine(
$"[{string.Join(", ", res41.Select(t => t.Value))}]"
);
// >>> [1, 1, 1, 1]
var windSequence2 = new List<(string, TimeStamp, double)>
{
("wind:1", 2, 14),
("wind:2", 2, 21),
("wind:3", 2, 4),
("wind:4", 2, 25)
};
IReadOnlyList<TimeStamp> res42 = db.TS().MAdd(windSequence2);
Console.WriteLine(
$"[{string.Join(", ", res42.Select(t => t.Value))}]"
);
// >>> [2, 2, 2, 2]
var windSequence3 = new List<(string, TimeStamp, double)>
{
("wind:1", 3, 10),
("wind:2", 3, 24),
("wind:3", 3, 8),
("wind:4", 3, 18)
};
IReadOnlyList<TimeStamp> res43 = db.TS().MAdd(windSequence3);
Console.WriteLine(
$"[{string.Join(", ", res43.Select(t => t.Value))}]"
);
// >>> [3, 3, 3, 3]
// The result pairs contain the timestamp and the maximum sample value
// for the country at that timestamp.
var countryFilters = new List<string> { "country=(us,uk)" };
IReadOnlyList<
(string, IReadOnlyList<TimeSeriesLabel>, IReadOnlyList<TimeSeriesTuple>)
> res44 = db.TS().MRange(
"-", "+",
countryFilters,
groupbyTuple: ("country", TsReduce.Max)
);
Console.WriteLine(res44.Count); // >>> 2
foreach (var (key, labelsResult, values) in res44)
{
Console.WriteLine($"{key}:");
Console.WriteLine($" Values: [{string.Join(", ", values.Select(t => $"({t.Time.Value}, {t.Val})"))}]");
}
// >>> country=uk
// >>> Values: [(1, 18), (2, 21), (3, 24)]
// >>> country=us
// >>> Values: [(1, 20), (2, 25), (3, 18)]
// The result pairs contain the timestamp and the average sample value
// for the country at that timestamp.
IReadOnlyList<
(string, IReadOnlyList<TimeSeriesLabel>, IReadOnlyList<TimeSeriesTuple>)
> res45 = db.TS().MRange(
"-", "+",
countryFilters,
groupbyTuple: ("country", TsReduce.Avg)
);
Console.WriteLine(res45.Count); // >>> 2
foreach (var (key, labelsResult, values) in res45)
{
Console.WriteLine($"{key}:");
Console.WriteLine($" Values: [{string.Join(", ", values.Select(t => $"({t.Time.Value}, {t.Val})"))}]");
}
// >>> country=uk
// >>> Values: [(1, 14), (2, 18), (3, 10)]
// >>> country=us
// >>> Values: [(1, 16), (2, 22), (3, 14)]
bool res46 = db.TS().Create(
"hyg:1",
new TsCreateParamsBuilder().build()
);
Console.WriteLine(res46); // >>> True
bool res47 = db.TS().Create(
"hyg:compacted",
new TsCreateParamsBuilder().build()
);
Console.WriteLine(res47); // >>> True
var compactionRule = new TimeSeriesRule("hyg:compacted", 3, TsAggregation.Min);
bool res48 = db.TS().CreateRule("hyg:1", compactionRule);
Console.WriteLine(res48); // >>> True
TimeSeriesInformation res49 = db.TS().Info("hyg:1");
Console.WriteLine(res49.Rules!.Count);
// >>> 1
TimeSeriesInformation res50 = db.TS().Info("hyg:compacted");
Console.WriteLine(res50.SourceKey);
// >>> hyg:1
var hygSequence1 = new List<(string, TimeStamp, double)>
{
("hyg:1", 0, 75),
("hyg:1", 1, 77),
("hyg:1", 2, 78)
};
IReadOnlyList<TimeStamp> res51 = db.TS().MAdd(hygSequence1);
Console.WriteLine($"[{string.Join(", ", res51.Select(t => t.Value))}]");
// >>> [0, 1, 2]
IReadOnlyList<TimeSeriesTuple> res52 = db.TS().Range("hyg:compacted", "-", "+");
Console.WriteLine(res52.Count); // >>> 0
TimeStamp res53 = db.TS().Add(
"hyg:1",
new TsAddParamsBuilder()
.AddTimestamp(3)
.AddValue(79)
.build()
);
Console.WriteLine(res53.Value); // >>> 3
IReadOnlyList<TimeSeriesTuple> res54 = db.TS().Range("hyg:compacted", "-", "+");
Console.WriteLine(
$"[{string.Join(", ", res54.Select(t => $"({t.Time.Value}, {t.Val})"))}]"
);
// >>> [(0, 75)]
TimeSeriesInformation res55 = db.TS().Info("thermometer:1");
Console.WriteLine(res55.TotalSamples); // >>> 2
Console.WriteLine(res55.FirstTimeStamp!); // >>> 1
Console.WriteLine(res55.LastTimeStamp!); // >>> 2
TimeStamp res56 = db.TS().Add(
"thermometer:1",
new TsAddParamsBuilder()
.AddTimestamp(3)
.AddValue(9.7)
.build()
);
Console.WriteLine(res56.Value); // >>> 3
TimeSeriesInformation res57 = db.TS().Info("thermometer:1");
Console.WriteLine(res57.TotalSamples); // >>> 3
Console.WriteLine(res57.FirstTimeStamp!); // >>> 1
Console.WriteLine(res57.LastTimeStamp!); // >>> 3
long res58 = db.TS().Del("thermometer:1", 1, 2);
Console.WriteLine(res58); // >>> 2
TimeSeriesInformation res59 = db.TS().Info("thermometer:1");
Console.WriteLine(res59.TotalSamples); // >>> 1
Console.WriteLine(res59.FirstTimeStamp!); // >>> 3
Console.WriteLine(res59.LastTimeStamp!); // >>> 3
long res60 = db.TS().Del("thermometer:1", 3, 3);
Console.WriteLine(res60); // >>> 1
TimeSeriesInformation res61 = db.TS().Info("thermometer:1");
Console.WriteLine(res61.TotalSamples); // >>> 0
}
}
The timestamp for each data point is a 64-bit integer value. The value represents a Unix timestamp, measured in milliseconds since the Unix epoch. When you create a time series, you can specify a maximum retention period for the data, relative to the last reported timestamp. A retention period of zero means the data does not expire.
# Create a new time series with a first value of 10.8 (Celsius), recorded at time 1, with a retention period of 100ms.
> TS.ADD thermometer:2 1 10.8 RETENTION 100
(integer) 1
> TS.INFO thermometer:2
.
.
9) retentionTime
10) (integer) 100
.
."""
Code samples for time series page:
https://redis.io/docs/latest/develop/data-types/timeseries/
"""
import redis
r = redis.Redis(decode_responses=True)
res1 = r.ts().create("thermometer:1")
print(res1) # >>> True
res2 = r.type("thermometer:1")
print(res2) # >>> TSDB-TYPE
res3 = r.ts().info("thermometer:1")
print(res3)
# >>> {'rules': [], ... 'total_samples': 0, ...
res4 = r.ts().add("thermometer:2", 1, 10.8, retention_msecs=100)
print(res4) # >>> 1
res5 = r.ts().info("thermometer:2")
print(res5)
# >>> {'rules': [], ... 'retention_msecs': 100, ...
res6 = r.ts().create(
"thermometer:3", 1, 10.4,
labels={"location": "UK", "type": "Mercury"}
)
print(res6) # >>> 1
res7 = r.ts().info("thermometer:3")
print(res7)
# >>> {'rules': [], ... 'labels': {'location': 'UK', 'type': 'Mercury'}, ...
res8 = r.ts().madd([
("thermometer:1", 1, 9.2),
("thermometer:1", 2, 9.9),
("thermometer:2", 2, 10.3)
])
print(res8) # >>> [1, 2, 2]
# The last recorded temperature for thermometer:2
# was 10.3 at time 2.
res9 = r.ts().get("thermometer:2")
print(res9) # >>> (2, 10.3)
# Add 5 data points to a time series named "rg:1".
res10 = r.ts().create("rg:1")
print(res10) # >>> True
res11 = r.ts().madd([
("rg:1", 0, 18),
("rg:1", 1, 14),
("rg:1", 2, 22),
("rg:1", 3, 18),
("rg:1", 4, 24),
])
print(res11) # >>> [0, 1, 2, 3, 4]
# Retrieve all the data points in ascending order.
res12 = r.ts().range("rg:1", "-", "+")
print(res12) # >>> [(0, 18.0), (1, 14.0), (2, 22.0), (3, 18.0), (4, 24.0)]
# Retrieve data points up to time 1 (inclusive).
res13 = r.ts().range("rg:1", "-", 1)
print(res13) # >>> [(0, 18.0), (1, 14.0)]
# Retrieve data points from time 3 onwards.
res14 = r.ts().range("rg:1", 3, "+")
print(res14) # >>> [(3, 18.0), (4, 24.0)]
# Retrieve all the data points in descending order.
res15 = r.ts().revrange("rg:1", "-", "+")
print(res15) # >>> [(4, 24.0), (3, 18.0), (2, 22.0), (1, 14.0), (0, 18.0)]
# Retrieve data points up to time 1 (inclusive), but return them
# in descending order.
res16 = r.ts().revrange("rg:1", "-", 1)
print(res16) # >>> [(1, 14.0), (0, 18.0)]
res17 = r.ts().range("rg:1", "-", "+", filter_by_ts=[0, 2, 4])
print(res17) # >>> [(0, 18.0), (2, 22.0), (4, 24.0)]
res18 = r.ts().revrange(
"rg:1", "-", "+",
filter_by_ts=[0, 2, 4],
filter_by_min_value=20,
filter_by_max_value=25,
)
print(res18) # >>> [(4, 24.0), (2, 22.0)]
res19 = r.ts().revrange(
"rg:1", "-", "+",
filter_by_ts=[0, 2, 4],
filter_by_min_value=22,
filter_by_max_value=22,
count=1,
)
print(res19) # >>> [(2, 22.0)]
# Create three new "rg:" time series (two in the US
# and one in the UK, with different units) and add some
# data points.
res20 = r.ts().create(
"rg:2",
labels={"location": "us", "unit": "cm"},
)
print(res20) # >>> True
res21 = r.ts().create(
"rg:3",
labels={"location": "us", "unit": "in"},
)
print(res21) # >>> True
res22 = r.ts().create(
"rg:4",
labels={"location": "uk", "unit": "mm"},
)
print(res22) # >>> True
res23 = r.ts().madd([
("rg:2", 0, 1.8),
("rg:3", 0, 0.9),
("rg:4", 0, 25),
])
print(res23) # >>> [0, 0, 0]
res24 = r.ts().madd([
("rg:2", 1, 2.1),
("rg:3", 1, 0.77),
("rg:4", 1, 18),
])
print(res24) # >>> [1, 1, 1]
res25 = r.ts().madd([
("rg:2", 2, 2.3),
("rg:3", 2, 1.1),
("rg:4", 2, 21),
])
print(res25) # >>> [2, 2, 2]
res26 = r.ts().madd([
("rg:2", 3, 1.9),
("rg:3", 3, 0.81),
("rg:4", 3, 19),
])
print(res26) # >>> [3, 3, 3]
res27 = r.ts().madd([
("rg:2", 4, 1.78),
("rg:3", 4, 0.74),
("rg:4", 4, 23),
])
print(res27) # >>> [4, 4, 4]
# Retrieve the last data point from each US time series. If
# you don't specify any labels, an empty array is returned
# for the labels.
res28 = r.ts().mget(["location=us"])
print(res28) # >>> [{'rg:2': [{}, 4, 1.78]}, {'rg:3': [{}, 4, 0.74]}]
# Retrieve the same data points, but include the `unit`
# label in the results.
res29 = r.ts().mget(["location=us"], select_labels=["unit"])
print(res29) # >>> [{'unit': 'cm'}, (4, 1.78), {'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.
res30 = r.ts().mrange(
"-", 2, filters=["unit=mm"], with_labels=True
)
print(res30)
# >>> [{'rg:4': [{'location': 'uk', 'unit': 'mm'}, [(0, 25.4),...
# 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 = r.ts().mrevrange(
1, 3, filters=["unit=(cm,mm)"], select_labels=["location"]
)
print(res31)
# >>> [[{'location': 'uk'}, (3, 19.0), (2, 21.0), (1, 18.0)],...
res32 = r.ts().range(
"rg:2", "-", "+",
aggregation_type="avg",
bucket_size_msec=2
)
print(res32)
# >>> [(0, 1.9500000000000002), (2, 2.0999999999999996), (4, 1.78)]
res33 = r.ts().create("sensor3")
print(res33) # >>> True
res34 = r.ts().madd([
("sensor3", 10, 1000),
("sensor3", 20, 2000),
("sensor3", 30, 3000),
("sensor3", 40, 4000),
("sensor3", 50, 5000),
("sensor3", 60, 6000),
("sensor3", 70, 7000),
])
print(res34) # >>> [10, 20, 30, 40, 50, 60, 70]
res35 = r.ts().range(
"sensor3", 10, 70,
aggregation_type="min",
bucket_size_msec=25
)
print(res35)
# >>> [(0, 1000.0), (25, 3000.0), (50, 5000.0)]
res36 = r.ts().range(
"sensor3", 10, 70,
aggregation_type="min",
bucket_size_msec=25,
align="START"
)
print(res36)
# >>> [(10, 1000.0), (35, 4000.0), (60, 6000.0)]
res37 = r.ts().create(
"wind:1",
labels={"country": "uk"}
)
print(res37) # >>> True
res38 = r.ts().create(
"wind:2",
labels={"country": "uk"}
)
print(res38) # >>> True
res39 = r.ts().create(
"wind:3",
labels={"country": "us"}
)
print(res39) # >>> True
res40 = r.ts().create(
"wind:4",
labels={"country": "us"}
)
print(res40) # >>> True
res41 = r.ts().madd([
("wind:1", 1, 12),
("wind:2", 1, 18),
("wind:3", 1, 5),
("wind:4", 1, 20),
])
print(res41) # >>> [1, 1, 1, 1]
res42 = r.ts().madd([
("wind:1", 2, 14),
("wind:2", 2, 21),
("wind:3", 2, 4),
("wind:4", 2, 25),
])
print(res42) # >>> [2, 2, 2, 2]
res43 = r.ts().madd([
("wind:1", 3, 10),
("wind:2", 3, 24),
("wind:3", 3, 8),
("wind:4", 3, 18),
])
print(res43) # >>> [3, 3, 3, 3]
# The result pairs contain the timestamp and the maximum sample value
# for the country at that timestamp.
res44 = r.ts().mrange(
"-", "+",
filters=["country=(us,uk)"],
groupby="country",
reduce="max"
)
print(res44)
# >>> [{'country=uk': [{}, [(1, 18.0), (2, 21.0), (3, 24.0)]]}, ...
# The result pairs contain the timestamp and the average sample value
# for the country at that timestamp.
res45 = r.ts().mrange(
"-", "+",
filters=["country=(us,uk)"],
groupby="country",
reduce="avg"
)
print(res45)
# >>> [{'country=uk': [{}, [(1, 15.0), (2, 17.5), (3, 17.0)]]}, ...
res45 = r.ts().create("hyg:1")
print(res45) # >>> True
res46 = r.ts().create("hyg:compacted")
print(res46) # >>> True
res47 = r.ts().createrule("hyg:1", "hyg:compacted", "min", 3)
print(res47) # >>> True
res48 = r.ts().info("hyg:1")
print(res48.rules)
# >>> [['hyg:compacted', 3, 'MIN', 0]]
res49 = r.ts().info("hyg:compacted")
print(res49.source_key) # >>> 'hyg:1'
res50 = r.ts().madd([
("hyg:1", 0, 75),
("hyg:1", 1, 77),
("hyg:1", 2, 78),
])
print(res50) # >>> [0, 1, 2]
res51 = r.ts().range("hyg:compacted", "-", "+")
print(res51) # >>> []
res52 = r.ts().add("hyg:1", 3, 79)
print(res52) # >>> 3
res53 = r.ts().range("hyg:compacted", "-", "+")
print(res53) # >>> [(0, 75.0)]
res54 = r.ts().info("thermometer:1")
print(res54.total_samples) # >>> 2
print(res54.first_timestamp) # >>> 1
print(res54.last_timestamp) # >>> 2
res55 = r.ts().add("thermometer:1", 3, 9.7)
print(res55) # >>> 3
res56 = r.ts().info("thermometer:1")
print(res56.total_samples) # >>> 3
print(res56.first_timestamp) # >>> 1
print(res56.last_timestamp) # >>> 3
res57 = r.ts().delete("thermometer:1", 1, 2)
print(res57) # >>> 2
res58 = r.ts().info("thermometer:1")
print(res58.total_samples) # >>> 1
print(res58.first_timestamp) # >>> 3
print(res58.last_timestamp) # >>> 3
res59 = r.ts().delete("thermometer:1", 3, 3)
print(res59) # >>> 1
res60 = r.ts().info("thermometer:1")
print(res60.total_samples) # >>> 0
import assert from 'assert';
import { createClient } from 'redis';
import { TIME_SERIES_AGGREGATION_TYPE, TIME_SERIES_REDUCERS } from '@redis/time-series';
const client = createClient();
await client.connect();
const res1 = await client.ts.create('thermometer:1');
console.log(res1); // >>> OK
const res2 = await client.type('thermometer:1');
console.log(res2); // >>> TSDB-TYPE
const res3 = await client.ts.info('thermometer:1');
console.log(res3);
// >>> { rules: [], ... totalSamples: 0, ...
const res4 = await client.ts.add('thermometer:2', 1, 10.8, { RETENTION: 100 });
console.log(res4); // >>> 1
const res5 = await client.ts.info('thermometer:2');
console.log(res5);
// >>> { rules: [], ... retentionTime: 100, ...
const res6 = await client.ts.add('thermometer:3', 1, 10.4, {
LABELS: { location: 'UK', type: 'Mercury' }
});
console.log(res6); // >>> 1
const res7 = await client.ts.info('thermometer:3');
console.log(res7);
// >>> { labels: [{ name: 'location', value: 'UK' }, { name: 'type', value: 'Mercury' }], ... }
const res8 = await client.ts.mAdd([
{ key: 'thermometer:1', timestamp: 1, value: 9.2 },
{ key: 'thermometer:1', timestamp: 2, value: 9.9 },
{ key: 'thermometer:2', timestamp: 2, value: 10.3 }
]);
console.log(res8); // >>> [1, 2, 2]
// The last recorded temperature for thermometer:2
// was 10.3 at time 2.
const res9 = await client.ts.get('thermometer:2');
console.log(res9); // >>> { timestamp: 2, value: 10.3 }
// Add 5 data points to a time series named "rg:1".
const res10 = await client.ts.create('rg:1');
console.log(res10); // >>> OK
const res11 = await client.ts.mAdd([
{ key: 'rg:1', timestamp: 0, value: 18 },
{ key: 'rg:1', timestamp: 1, value: 14 },
{ key: 'rg:1', timestamp: 2, value: 22 },
{ key: 'rg:1', timestamp: 3, value: 18 },
{ key: 'rg:1', timestamp: 4, value: 24 }
]);
console.log(res11); // >>> [0, 1, 2, 3, 4]
// Retrieve all the data points in ascending order.
const res12 = await client.ts.range('rg:1', '-', '+');
console.log(res12);
// >>> [{ timestamp: 0, value: 18 }, { timestamp: 1, value: 14 }, ...]
// Retrieve data points up to time 1 (inclusive).
const res13 = await client.ts.range('rg:1', '-', 1);
console.log(res13);
// >>> [{ timestamp: 0, value: 18 }, { timestamp: 1, value: 14 }]
// Retrieve data points from time 3 onwards.
const res14 = await client.ts.range('rg:1', 3, '+');
console.log(res14);
// >>> [{ timestamp: 3, value: 18 }, { timestamp: 4, value: 24 }]
// Retrieve all the data points in descending order.
const res15 = await client.ts.revRange('rg:1', '-', '+');
console.log(res15);
// >>> [{ timestamp: 4, value: 24 }, { timestamp: 3, value: 18 }, ...]
// Retrieve data points up to time 1 (inclusive), but return them
// in descending order.
const res16 = await client.ts.revRange('rg:1', '-', 1);
console.log(res16);
// >>> [{ timestamp: 1, value: 14 }, { timestamp: 0, value: 18 }]
const res17 = await client.ts.range('rg:1', '-', '+', {
FILTER_BY_TS: [0, 2, 4]
});
console.log(res17);
// >>> [{ timestamp: 0, value: 18 }, { timestamp: 2, value: 22 }, { timestamp: 4, value: 24 }]
const res18 = await client.ts.revRange('rg:1', '-', '+', {
FILTER_BY_TS: [0, 2, 4],
FILTER_BY_VALUE: { min: 20, max: 25 }
});
console.log(res18);
// >>> [{ timestamp: 4, value: 24 }, { timestamp: 2, value: 22 }]
const res19 = await client.ts.revRange('rg:1', '-', '+', {
FILTER_BY_TS: [0, 2, 4],
FILTER_BY_VALUE: { min: 22, max: 22 },
COUNT: 1
});
console.log(res19);
// >>> [{ timestamp: 2, value: 22 }]
// Create three new "rg:" time series (two in the US
// and one in the UK, with different units) and add some
// data points.
const res20 = await client.ts.create('rg:2', {
LABELS: { location: 'us', unit: 'cm' }
});
console.log(res20); // >>> OK
const res21 = await client.ts.create('rg:3', {
LABELS: { location: 'us', unit: 'in' }
});
console.log(res21); // >>> OK
const res22 = await client.ts.create('rg:4', {
LABELS: { location: 'uk', unit: 'mm' }
});
console.log(res22); // >>> OK
const res23 = await client.ts.mAdd([
{ key: 'rg:2', timestamp: 0, value: 1.8 },
{ key: 'rg:3', timestamp: 0, value: 0.9 },
{ key: 'rg:4', timestamp: 0, value: 25 }
]);
console.log(res23); // >>> [0, 0, 0]
const res24 = await client.ts.mAdd([
{ key: 'rg:2', timestamp: 1, value: 2.1 },
{ key: 'rg:3', timestamp: 1, value: 0.77 },
{ key: 'rg:4', timestamp: 1, value: 18 }
]);
console.log(res24); // >>> [1, 1, 1]
const res25 = await client.ts.mAdd([
{ key: 'rg:2', timestamp: 2, value: 2.3 },
{ key: 'rg:3', timestamp: 2, value: 1.1 },
{ key: 'rg:4', timestamp: 2, value: 21 }
]);
console.log(res25); // >>> [2, 2, 2]
const res26 = await client.ts.mAdd([
{ key: 'rg:2', timestamp: 3, value: 1.9 },
{ key: 'rg:3', timestamp: 3, value: 0.81 },
{ key: 'rg:4', timestamp: 3, value: 19 }
]);
console.log(res26); // >>> [3, 3, 3]
const res27 = await client.ts.mAdd([
{ key: 'rg:2', timestamp: 4, value: 1.78 },
{ key: 'rg:3', timestamp: 4, value: 0.74 },
{ key: 'rg:4', timestamp: 4, value: 23 }
]);
console.log(res27); // >>> [4, 4, 4]
// Retrieve the last data point from each US time series.
const res28 = await client.ts.mGet(['location=us']);
console.log(res28);
// >>> { "rg:2": { sample: { timestamp: 4, value: 1.78 } }, "rg:3": { sample: { timestamp: 4, value: 0.74 } } }
// Retrieve the same data points, but include the `unit`
// label in the results.
const res29 = await client.ts.mGetSelectedLabels(['location=us'], ['unit']);
console.log(res29);
// >>> { "rg:2": { labels: { unit: 'cm' }, sample: { timestamp: 4, value: 1.78 } }, "rg:3": { labels: { unit: 'in' }, sample: { timestamp: 4, value: 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.
const res30 = await client.ts.mRangeWithLabels('-', 2, 'unit=mm');
console.log(res30);
// >>> { "rg:4": { labels: { location: 'uk', unit: 'mm' }, samples: [
// { timestamp: 0, value: 25 },
// { timestamp: 1, value: 18 },
// { timestamp: 2, value: 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.
const res31 = await client.ts.mRevRangeSelectedLabels(
1, 3,
['location'],
['unit=(cm,mm)']
);
console.log(res31);
// >>> { "rg:2": { labels: { location: 'us' }, samples: [
// { timestamp: 3, value: 1.9 },
// { timestamp: 2, value: 2.3 },
// { timestamp: 1, value: 2.1 }
// ] }, "rg:4": { labels: { location: 'uk' }, samples: [
// { timestamp: 3, value: 19 },
// { timestamp: 2, value: 21 },
// { timestamp: 1, value: 18 }
// ] } }
const res32 = await client.ts.range('rg:2', '-', '+', {
AGGREGATION: {
type: TIME_SERIES_AGGREGATION_TYPE.AVG,
timeBucket: 2
}
});
console.log(res32);
// >>> [{ timestamp: 0, value: 1.9500000000000002 },{ timestamp: 2, value: 2.0999999999999996 }, { timestamp: 4, value: 1.78 }]
const res33 = await client.ts.create('sensor3');
console.log(res33); // >>> OK
const res34 = await client.ts.mAdd([
{ key: 'sensor3', timestamp: 10, value: 1000 },
{ key: 'sensor3', timestamp: 20, value: 2000 },
{ key: 'sensor3', timestamp: 30, value: 3000 },
{ key: 'sensor3', timestamp: 40, value: 4000 },
{ key: 'sensor3', timestamp: 50, value: 5000 },
{ key: 'sensor3', timestamp: 60, value: 6000 },
{ key: 'sensor3', timestamp: 70, value: 7000 }
]);
console.log(res34); // >>> [10, 20, 30, 40, 50, 60, 70]
const res35 = await client.ts.range('sensor3', 10, 70, {
AGGREGATION: {
type: TIME_SERIES_AGGREGATION_TYPE.MIN,
timeBucket: 25
}
});
console.log(res35);
// >>> [{ timestamp: 0, value: 1000 }, { timestamp: 25, value: 3000 }, { timestamp: 50, value: 5000 }]
const res36 = await client.ts.range('sensor3', 10, 70, {
AGGREGATION: {
type: TIME_SERIES_AGGREGATION_TYPE.MIN,
timeBucket: 25
},
ALIGN: 'START'
});
console.log(res36);
// >>> [{ timestamp: 10, value: 1000 }, { timestamp: 35, value: 4000 }, { timestamp: 60, value: 6000 }]
const res37 = await client.ts.create('wind:1', {
LABELS: { country: 'uk' }
});
console.log(res37); // >>> OK
const res38 = await client.ts.create('wind:2', {
LABELS: { country: 'uk' }
});
console.log(res38); // >>> OK
const res39 = await client.ts.create('wind:3', {
LABELS: { country: 'us' }
});
console.log(res39); // >>> OK
const res40 = await client.ts.create('wind:4', {
LABELS: { country: 'us' }
});
console.log(res40); // >>> OK
const res41 = await client.ts.mAdd([
{ key: 'wind:1', timestamp: 1, value: 12 },
{ key: 'wind:2', timestamp: 1, value: 18 },
{ key: 'wind:3', timestamp: 1, value: 5 },
{ key: 'wind:4', timestamp: 1, value: 20 }
]);
console.log(res41); // >>> [1, 1, 1, 1]
const res42 = await client.ts.mAdd([
{ key: 'wind:1', timestamp: 2, value: 14 },
{ key: 'wind:2', timestamp: 2, value: 21 },
{ key: 'wind:3', timestamp: 2, value: 4 },
{ key: 'wind:4', timestamp: 2, value: 25 }
]);
console.log(res42); // >>> [2, 2, 2, 2]
const res43 = await client.ts.mAdd([
{ key: 'wind:1', timestamp: 3, value: 10 },
{ key: 'wind:2', timestamp: 3, value: 24 },
{ key: 'wind:3', timestamp: 3, value: 8 },
{ key: 'wind:4', timestamp: 3, value: 18 }
]);
console.log(res43); // >>> [3, 3, 3, 3]
// The result pairs contain the timestamp and the maximum sample value
// for the country at that timestamp.
const res44 = await client.ts.mRangeGroupBy(
'-', '+', ['country=(us,uk)'],
{label: 'country', REDUCE: TIME_SERIES_REDUCERS.MAX}
);
console.log(res44);
// >>> { "country=uk": { samples: [
// { timestamp: 1, value: 18 },
// { timestamp: 2, value: 21 },
// { timestamp: 3, value: 24 }
// ] }, "country=us": { samples: [
// { timestamp: 1, value: 20 },
// { timestamp: 2, value: 25 },
// { timestamp: 3, value: 18 }
// ] } }
// The result pairs contain the timestamp and the average sample value
// for the country at that timestamp.
const res45 = await client.ts.mRangeGroupBy(
'-', '+', ['country=(us,uk)'],
{ label: 'country', REDUCE: TIME_SERIES_REDUCERS.AVG}
);
console.log(res45);
// >>> {
// "country=uk": {
// samples: [{ timestamp: 1, value: 15 }, { timestamp: 2, value: 17.5 }, { timestamp: 3, value: 17 }]
// },
// "country=us": {
// samples: [{ timestamp: 1, value: 12.5 }, { timestamp: 2, value: 14.5 }, { timestamp: 3, value: 13 }]
// }
// }
const res46 = await client.ts.create('hyg:1');
console.log(res46); // >>> OK
const res47 = await client.ts.create('hyg:compacted');
console.log(res47); // >>> OK
const res48 = await client.ts.createRule('hyg:1', 'hyg:compacted', TIME_SERIES_AGGREGATION_TYPE.MIN, 3);
console.log(res48); // >>> OK
const res49 = await client.ts.info('hyg:1');
console.log(res49.rules);
// >>> [{ aggregationType: 'MIN', key: 'hyg:compacted', timeBucket: 3}]
const res50 = await client.ts.info('hyg:compacted');
console.log(res50.sourceKey); // >>> 'hyg:1'
const res51 = await client.ts.mAdd([
{ key: 'hyg:1', timestamp: 0, value: 75 },
{ key: 'hyg:1', timestamp: 1, value: 77 },
{ key: 'hyg:1', timestamp: 2, value: 78 }
]);
console.log(res51); // >>> [0, 1, 2]
const res52 = await client.ts.range('hyg:compacted', '-', '+');
console.log(res52); // >>> []
const res53 = await client.ts.add('hyg:1', 3, 79);
console.log(res53); // >>> 3
const res54 = await client.ts.range('hyg:compacted', '-', '+');
console.log(res54); // >>> [{ timestamp: 0, value: 75 }]
const res55 = await client.ts.info('thermometer:1');
console.log(res55.totalSamples); // >>> 2
console.log(res55.firstTimestamp); // >>> 1
console.log(res55.lastTimestamp); // >>> 2
const res56 = await client.ts.add('thermometer:1', 3, 9.7);
console.log(res56); // >>> 3
const res57 = await client.ts.info('thermometer:1');
console.log(res57.totalSamples); // >>> 3
console.log(res57.firstTimestamp); // >>> 1
console.log(res57.lastTimestamp); // >>> 3
const res58 = await client.ts.del('thermometer:1', 1, 2);
console.log(res58); // >>> 2
const res59 = await client.ts.info('thermometer:1');
console.log(res59.totalSamples); // >>> 1
console.log(res59.firstTimestamp); // >>> 3
console.log(res59.lastTimestamp); // >>> 3
const res60 = await client.ts.del('thermometer:1', 3, 3);
console.log(res60); // >>> 1
const res61 = await client.ts.info('thermometer:1');
console.log(res61.totalSamples); // >>> 0
await client.quit();
import redis.clients.jedis.RedisClient;
import redis.clients.jedis.timeseries.*;
import redis.clients.jedis.timeseries.TSElement;
import java.util.*;
public class TimeSeriesTutorialExample {
public void run() {
RedisClient jedis = RedisClient.create("redis://localhost:6379");
String res1 = jedis.tsCreate("thermometer:1");
System.out.println(res1); // >>> OK
String res2 = jedis.type("thermometer:1");
System.out.println(res2); // >>> TSDB-TYPE
TSInfo res3 = jedis.tsInfo("thermometer:1");
System.out.println(res3.getProperty("totalSamples")); // >>> 0
long res4 = jedis.tsAdd("thermometer:2", 1L, 10.8,
TSCreateParams.createParams().retention(100));
System.out.println(res4); // >>> 1
TSInfo res5 = jedis.tsInfo("thermometer:2");
System.out.println(res5.getProperty("retentionTime")); // >>> 100
Map<String, String> labels = new HashMap<>();
labels.put("location", "UK");
labels.put("type", "Mercury");
long res6 = jedis.tsAdd("thermometer:3", 1L, 10.4,
TSCreateParams.createParams().labels(labels));
System.out.println(res6); // >>> 1
TSInfo res7 = jedis.tsInfo("thermometer:3");
System.out.println("Labels: " + res7.getLabels());
// >>> Labels: {location=UK, type=Mercury}
List<Long> res8 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("thermometer:1", new TSElement(1L, 9.2)),
new AbstractMap.SimpleEntry<>("thermometer:1", new TSElement(2L, 9.9)),
new AbstractMap.SimpleEntry<>("thermometer:2", new TSElement(2L, 10.3))
);
System.out.println(res8); // >>> [1, 2, 2]
// The last recorded temperature for thermometer:2
// was 10.3 at time 2.
TSElement res9 = jedis.tsGet("thermometer:2");
System.out.println("(" + res9.getTimestamp() + ", " + res9.getValue() + ")");
// >>> (2, 10.3)
// Add 5 data points to a time series named "rg:1"
String res10 = jedis.tsCreate("rg:1");
System.out.println(res10); // >>> OK
List<Long> res11 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:1", new TSElement(0L, 18.0)),
new AbstractMap.SimpleEntry<>("rg:1", new TSElement(1L, 14.0)),
new AbstractMap.SimpleEntry<>("rg:1", new TSElement(2L, 22.0)),
new AbstractMap.SimpleEntry<>("rg:1", new TSElement(3L, 18.0)),
new AbstractMap.SimpleEntry<>("rg:1", new TSElement(4L, 24.0))
);
System.out.println(res11); // >>> [0, 1, 2, 3, 4]
// Retrieve all the data points in ascending order
List<TSElement> res12 = jedis.tsRange("rg:1", 0L, 4L);
System.out.println(res12);
// >>> [(0:18.0), (1:14.0), (2:22.0), (3:18.0), (4:24.0)]
// Retrieve data points up to time 1 (inclusive)
List<TSElement> res13 = jedis.tsRange("rg:1", 0L, 1L);
System.out.println(res13);
// >>> [(0:18.0), (1:14.0)]
// Retrieve data points from time 3 onwards
List<TSElement> res14 = jedis.tsRange("rg:1", 3L, 4L);
System.out.println(res14);
// >>> [(3:18.0), (4:24.0)]
// Retrieve all the data points in descending order
List<TSElement> res15 = jedis.tsRevRange("rg:1", 0L, 4L);
System.out.println(res15);
// >>> [(4:24.0), (3:18.0), (2:22.0), (1:14.0), (0:18.0)]
// Retrieve data points up to time 1 (inclusive), in descending order
List<TSElement> res16 = jedis.tsRevRange("rg:1", 0L, 1L);
System.out.println(res16);
// >>> [(1:14.0), (0:18.0)]
List<TSElement> res17 = jedis.tsRange("rg:1",
TSRangeParams.rangeParams()
.fromTimestamp(0L)
.toTimestamp(4L)
.filterByTS(0L, 2L, 4L)
);
System.out.println(res17);
// >>> [(0:18.0), (2:22.0), (4:24.0)]
List<TSElement> res18 = jedis.tsRevRange("rg:1",
TSRangeParams.rangeParams()
.fromTimestamp(0L)
.toTimestamp(4L)
.filterByTS(0L, 2L, 4L)
.filterByValues(20.0, 25.0)
);
System.out.println(res18);
// >>> [(4:24.0), (2:22.0)]
List<TSElement> res19 = jedis.tsRevRange("rg:1",
TSRangeParams.rangeParams()
.fromTimestamp(0L)
.toTimestamp(4L)
.filterByTS(0L, 2L, 4L)
.filterByValues(22.0, 22.0)
.count(1)
);
System.out.println(res19);
// >>> [(2:22.0)]
// Create three new "rg:" time series (two in the US
// and one in the UK, with different units) and add some
// data points.
Map<String, String> usLabels1 = new HashMap<>();
usLabels1.put("location", "us");
usLabels1.put("unit", "cm");
Map<String, String> usLabels2 = new HashMap<>();
usLabels2.put("location", "us");
usLabels2.put("unit", "in");
Map<String, String> ukLabels = new HashMap<>();
ukLabels.put("location", "uk");
ukLabels.put("unit", "mm");
String res20 = jedis.tsCreate("rg:2",
TSCreateParams.createParams().labels(usLabels1));
System.out.println(res20); // >>> OK
String res21 = jedis.tsCreate("rg:3",
TSCreateParams.createParams().labels(usLabels2));
System.out.println(res21); // >>> OK
String res22 = jedis.tsCreate("rg:4",
TSCreateParams.createParams().labels(ukLabels));
System.out.println(res22); // >>> OK
List<Long> res23 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:2", new TSElement(0L, 1.8)),
new AbstractMap.SimpleEntry<>("rg:3", new TSElement(0L, 0.9)),
new AbstractMap.SimpleEntry<>("rg:4", new TSElement(0L, 25.0))
);
System.out.println(res23); // >>> [0, 0, 0]
List<Long> res24 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:2", new TSElement(1L, 2.1)),
new AbstractMap.SimpleEntry<>("rg:3", new TSElement(1L, 0.77)),
new AbstractMap.SimpleEntry<>("rg:4", new TSElement(1L, 18.0))
);
System.out.println(res24); // >>> [1, 1, 1]
List<Long> res25 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:2", new TSElement(2L, 2.3)),
new AbstractMap.SimpleEntry<>("rg:3", new TSElement(2L, 1.1)),
new AbstractMap.SimpleEntry<>("rg:4", new TSElement(2L, 21.0))
);
System.out.println(res25); // >>> [2, 2, 2]
List<Long> res26 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:2", new TSElement(3L, 1.9)),
new AbstractMap.SimpleEntry<>("rg:3", new TSElement(3L, 0.81)),
new AbstractMap.SimpleEntry<>("rg:4", new TSElement(3L, 19.0))
);
System.out.println(res26); // >>> [3, 3, 3]
List<Long> res27 = jedis.tsMAdd(
new AbstractMap.SimpleEntry<>("rg:2", new TSElement(4L, 1.78)),
new AbstractMap.SimpleEntry<>("rg:3", new TSElement(4L, 0.74)),
new AbstractMap.SimpleEntry<>("rg:4", new TSElement(4L, 23.0))
);
System.out.println(res27); // >>> [4, 4, 4]
// Retrieve the last data point from each US time series.
Map<String, TSMGetElement> res28 = jedis.tsMGet(
TSMGetParams.multiGetParams().latest(),
"location=us"
);
System.out.println(res28);
// >>> {rg:2=TSMGetElement{key=rg:2, labels={}, element=(4:1.78)}...
// Retrieve the same data points, but include the `unit`
// label in the results.
Map<String, TSMGetElement> res29 = jedis.tsMGet(
TSMGetParams.multiGetParams().selectedLabels("unit"),
"location=us"
);
System.out.println(res29);
// >>> {rg:2=TSMGetElement{key=rg:2, labels={unit=cm}, element=(4:1.78)}...
// Retrieve data points up to time 2 (inclusive) from all
// time series that use millimeters as the unit. Include all
// labels in the results.
Map<String, TSMRangeElements> res30 = jedis.tsMRange(
TSMRangeParams.multiRangeParams(0L, 2L)
.withLabels()
.filter("unit=mm")
);
System.out.println(res30);
// >>> {rg:4=TSMRangeElements{key=rg:4, labels={location=uk, unit=mm}, value=[(0:25.0), (1:18.0), (2:21.0)]}}