Skip to content

Commit aed3c93

Browse files
authored
Support reducers in RedisTimeSeries 1.8 GA (#348)
Add new reducers in RedisTimeSeries 1.8 GA
1 parent dd11910 commit aed3c93

File tree

3 files changed

+218
-1
lines changed

3 files changed

+218
-1
lines changed

src/NRedisStack/TimeSeries/Extensions/ReduceExtensions.cs

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ internal static class ReduceExtensions
99
TsReduce.Sum => "SUM",
1010
TsReduce.Min => "MIN",
1111
TsReduce.Max => "MAX",
12+
TsReduce.Avg => "AVG",
13+
TsReduce.Range => "RANGE",
14+
TsReduce.Count => "COUNT",
15+
TsReduce.StdP => "STD.P",
16+
TsReduce.StdS => "STD.S",
17+
TsReduce.VarP => "VAR.P",
18+
TsReduce.VarS => "VAR.S",
1219
_ => throw new ArgumentOutOfRangeException(nameof(reduce), "Invalid Reduce type"),
1320
};
1421
}

src/NRedisStack/TimeSeries/Literals/Enums/Reduce.cs

+35
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,40 @@ public enum TsReduce
1919
/// A maximum sample of all samples in the group
2020
/// </summary>
2121
Max,
22+
23+
/// <summary>
24+
/// Arithmetic mean of all non-NaN values (since RedisTimeSeries v1.8)
25+
/// </summary>
26+
Avg,
27+
28+
/// <summary>
29+
/// Difference between maximum non-NaN value and minimum non-NaN value (since RedisTimeSeries v1.8)
30+
/// </summary>
31+
Range,
32+
33+
/// <summary>
34+
/// Number of non-NaN values (since RedisTimeSeries v1.8)
35+
/// </summary>
36+
Count,
37+
38+
/// <summary>
39+
/// Population standard deviation of all non-NaN values (since RedisTimeSeries v1.8)
40+
/// </summary>
41+
StdP,
42+
43+
/// <summary>
44+
/// Sample standard deviation of all non-NaN values (since RedisTimeSeries v1.8)
45+
/// </summary>
46+
StdS,
47+
48+
/// <summary>
49+
/// Population variance of all non-NaN values (since RedisTimeSeries v1.8)
50+
/// </summary>
51+
VarP,
52+
53+
/// <summary>
54+
/// Sample variance of all non-NaN values (since RedisTimeSeries v1.8)
55+
/// </summary>
56+
VarS
2257
}
2358
}

tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs

+176-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ public void TestMRangeGroupby()
257257
}
258258

259259
[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
260-
public void TestMRangeReduce()
260+
public void TestMRangeReduceSum()
261261
{
262262
IDatabase db = redisFixture.Redis.GetDatabase();
263263
db.Execute("FLUSHALL");
@@ -281,6 +281,181 @@ public void TestMRangeReduce()
281281
}
282282
}
283283

284+
[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
285+
public void TestMRangeReduceAvg()
286+
{
287+
IDatabase db = redisFixture.Redis.GetDatabase();
288+
db.Execute("FLUSHALL");
289+
var ts = db.TS();
290+
foreach (var key in _keys)
291+
{
292+
var label = new TimeSeriesLabel("key", "MRangeReduce");
293+
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
294+
}
295+
296+
var tuples = CreateData(ts, 50);
297+
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.Avg));
298+
Assert.Equal(1, results.Count);
299+
Assert.Equal("key=MRangeReduce", results[0].key);
300+
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
301+
Assert.Equal(new TimeSeriesLabel("__reducer__", "avg"), results[0].labels[1]);
302+
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
303+
for (int i = 0; i < results[0].values.Count; i++)
304+
{
305+
Assert.Equal(tuples[i].Val, results[0].values[i].Val);
306+
}
307+
}
308+
309+
[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
310+
public void TestMRangeReduceRange()
311+
{
312+
IDatabase db = redisFixture.Redis.GetDatabase();
313+
db.Execute("FLUSHALL");
314+
var ts = db.TS();
315+
foreach (var key in _keys)
316+
{
317+
var label = new TimeSeriesLabel("key", "MRangeReduce");
318+
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
319+
}
320+
321+
var tuples = CreateData(ts, 50);
322+
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.Range));
323+
Assert.Equal(1, results.Count);
324+
Assert.Equal("key=MRangeReduce", results[0].key);
325+
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
326+
Assert.Equal(new TimeSeriesLabel("__reducer__", "range"), results[0].labels[1]);
327+
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
328+
for (int i = 0; i < results[0].values.Count; i++)
329+
{
330+
Assert.Equal(0, results[0].values[i].Val);
331+
}
332+
}
333+
334+
[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
335+
public void TestMRangeReduceCount()
336+
{
337+
IDatabase db = redisFixture.Redis.GetDatabase();
338+
db.Execute("FLUSHALL");
339+
var ts = db.TS();
340+
foreach (var key in _keys)
341+
{
342+
var label = new TimeSeriesLabel("key", "MRangeReduce");
343+
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
344+
}
345+
346+
var tuples = CreateData(ts, 50);
347+
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.Count));
348+
Assert.Equal(1, results.Count);
349+
Assert.Equal("key=MRangeReduce", results[0].key);
350+
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
351+
Assert.Equal(new TimeSeriesLabel("__reducer__", "count"), results[0].labels[1]);
352+
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
353+
for (int i = 0; i < results[0].values.Count; i++)
354+
{
355+
Assert.Equal(2, results[0].values[i].Val);
356+
}
357+
}
358+
359+
[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
360+
public void TestMRangeReduceStdP()
361+
{
362+
IDatabase db = redisFixture.Redis.GetDatabase();
363+
db.Execute("FLUSHALL");
364+
var ts = db.TS();
365+
foreach (var key in _keys)
366+
{
367+
var label = new TimeSeriesLabel("key", "MRangeReduce");
368+
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
369+
}
370+
371+
var tuples = CreateData(ts, 50);
372+
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.StdP));
373+
Assert.Equal(1, results.Count);
374+
Assert.Equal("key=MRangeReduce", results[0].key);
375+
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
376+
Assert.Equal(new TimeSeriesLabel("__reducer__", "std.p"), results[0].labels[1]);
377+
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
378+
for (int i = 0; i < results[0].values.Count; i++)
379+
{
380+
Assert.Equal(0, results[0].values[i].Val);
381+
}
382+
}
383+
384+
[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
385+
public void TestMRangeReduceStdS()
386+
{
387+
IDatabase db = redisFixture.Redis.GetDatabase();
388+
db.Execute("FLUSHALL");
389+
var ts = db.TS();
390+
foreach (var key in _keys)
391+
{
392+
var label = new TimeSeriesLabel("key", "MRangeReduce");
393+
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
394+
}
395+
396+
var tuples = CreateData(ts, 50);
397+
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.StdS));
398+
Assert.Equal(1, results.Count);
399+
Assert.Equal("key=MRangeReduce", results[0].key);
400+
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
401+
Assert.Equal(new TimeSeriesLabel("__reducer__", "std.s"), results[0].labels[1]);
402+
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
403+
for (int i = 0; i < results[0].values.Count; i++)
404+
{
405+
Assert.Equal(0, results[0].values[i].Val);
406+
}
407+
}
408+
409+
[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
410+
public void TestMRangeReduceVarP()
411+
{
412+
IDatabase db = redisFixture.Redis.GetDatabase();
413+
db.Execute("FLUSHALL");
414+
var ts = db.TS();
415+
foreach (var key in _keys)
416+
{
417+
var label = new TimeSeriesLabel("key", "MRangeReduce");
418+
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
419+
}
420+
421+
var tuples = CreateData(ts, 50);
422+
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.VarP));
423+
Assert.Equal(1, results.Count);
424+
Assert.Equal("key=MRangeReduce", results[0].key);
425+
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
426+
Assert.Equal(new TimeSeriesLabel("__reducer__", "var.p"), results[0].labels[1]);
427+
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
428+
for (int i = 0; i < results[0].values.Count; i++)
429+
{
430+
Assert.Equal(0, results[0].values[i].Val);
431+
}
432+
}
433+
434+
[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
435+
public void TestMRangeReduceVarS()
436+
{
437+
IDatabase db = redisFixture.Redis.GetDatabase();
438+
db.Execute("FLUSHALL");
439+
var ts = db.TS();
440+
foreach (var key in _keys)
441+
{
442+
var label = new TimeSeriesLabel("key", "MRangeReduce");
443+
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
444+
}
445+
446+
var tuples = CreateData(ts, 50);
447+
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.VarS));
448+
Assert.Equal(1, results.Count);
449+
Assert.Equal("key=MRangeReduce", results[0].key);
450+
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
451+
Assert.Equal(new TimeSeriesLabel("__reducer__", "var.s"), results[0].labels[1]);
452+
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
453+
for (int i = 0; i < results[0].values.Count; i++)
454+
{
455+
Assert.Equal(0, results[0].values[i].Val);
456+
}
457+
}
458+
284459
[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
285460
public void TestMRangeFilterBy()
286461
{

0 commit comments

Comments
 (0)