typescriptredisnode-redis

node-redis: How to query argmin on redis timeSeries?


In typescript using node-redis with timeSeries, I want to get an argmin on range but I can't find a way to do that.

Bellow is a simple example with a timeSeries (6 points on timestamps 0, 1, 2, 3, 4, 5, each point has a random value). I want the argmin on timestamp range [3, 5]

import * as rd from 'redis';

// Connect to redis
const { REDIS_ENDPOINT, REDIS_PASSWORD, REDIS_PORT } = process.env;
if (!REDIS_ENDPOINT || !REDIS_PASSWORD || !REDIS_PORT) throw new Error('missing env variable');
const client = rd.createClient({ socket: { host: REDIS_ENDPOINT, port: parseInt(REDIS_PORT, 10) }, password: REDIS_PASSWORD });
await client.connect();

// Create a time series with timestamp 0, 1, 2, 3, 4, 5 (random value on each point)
const savePipeline = client.multi();
Array.from(Array(6).keys()).forEach((timestamp) => {
  savePipeline.ts.add('test_time_serie_key', timestamp, Math.random());
});
await savePipeline.exec();

// Query argmin: I want timestamp and value of point with min value in timestamp range [3, 5]
const fromTimestamp = 3;
const toTimestamp = 5;
const argmin = { timestamp: null, value: null }; // How to get It ?
console.log(`Argmin in range [${fromTimestamp}, ${toTimestamp}] is: ${JSON.stringify(argmin)}`);

I tried with aggregation but it does not work, with aggregations i can retrieve the min but not the timestamp corresponding to this min (because the range is divided into chunks ant it returns the start timestamp of the range). Here is an example. It will always return a point with timestamp 0 (even if at timestamp, we don't have the min value, and the query was between timestamp 3 and and 5, 0 is impossible).

const pipeline = client.multi();
pipeline.ts.range('test_time_serie_key', fromTimestamp, toTimestamp, {
  AGGREGATION: { type: rd.TimeSeriesAggregationType.MIN, timeBucket: 1_000000 },
});
const results = await pipeline.exec() as [{ timestamp: number, value: number } | null][];
console.log(results);

Note: I know one way to get the argmin with the aggregation: I could use a very low timeBucket (which would return all points in range) and then find the desired point using javascript code. But I would like to avoid fetching all points. In reality, the range is quite long, there are a lot of points and this task needs to be repeated frequently (around every 10 seconds). So fetching a huge amount of points to find a single point every 10 seconds seems a bad idea.


Solution

  • See Retrieving Time Series data from Redis

    As an aggregation type use TimeSeriesAggregationType.MIN, and as an aggregation bucket use a large value so your time range won't be split into buckets.

    Read more about aggregations here.

    The returned timestamp is the start, end, or mid time of each bucket (as specified with the [BUCKETTIMESTAMP bt] optional argument). Currently, you cannot retrieve the timestamps at which the reported minimum /maximum values were measured.

    However, once the minimum was retrieved, you can run another query and retrieve all the timestamps at which the minimum value was measured: TS.RANGE has a [FILTER_BY_VALUE min max] optional argument, so you can query over the same timeframe, without aggregation this time, and specify the retrieved value as both min and max (so you'll retrieve all the timestamps at which this exact value was measured).