Skip to content

Commit

Permalink
Support reducers in RedisTimeSeries 1.8 GA (redis#348)
Browse files Browse the repository at this point in the history
Add new reducers in RedisTimeSeries 1.8 GA
  • Loading branch information
atakavci authored Nov 22, 2024
1 parent dd11910 commit aed3c93
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 1 deletion.
7 changes: 7 additions & 0 deletions src/NRedisStack/TimeSeries/Extensions/ReduceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ internal static class ReduceExtensions
TsReduce.Sum => "SUM",
TsReduce.Min => "MIN",
TsReduce.Max => "MAX",
TsReduce.Avg => "AVG",
TsReduce.Range => "RANGE",
TsReduce.Count => "COUNT",
TsReduce.StdP => "STD.P",
TsReduce.StdS => "STD.S",
TsReduce.VarP => "VAR.P",
TsReduce.VarS => "VAR.S",
_ => throw new ArgumentOutOfRangeException(nameof(reduce), "Invalid Reduce type"),
};
}
Expand Down
35 changes: 35 additions & 0 deletions src/NRedisStack/TimeSeries/Literals/Enums/Reduce.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,40 @@ public enum TsReduce
/// A maximum sample of all samples in the group
/// </summary>
Max,

/// <summary>
/// Arithmetic mean of all non-NaN values (since RedisTimeSeries v1.8)
/// </summary>
Avg,

/// <summary>
/// Difference between maximum non-NaN value and minimum non-NaN value (since RedisTimeSeries v1.8)
/// </summary>
Range,

/// <summary>
/// Number of non-NaN values (since RedisTimeSeries v1.8)
/// </summary>
Count,

/// <summary>
/// Population standard deviation of all non-NaN values (since RedisTimeSeries v1.8)
/// </summary>
StdP,

/// <summary>
/// Sample standard deviation of all non-NaN values (since RedisTimeSeries v1.8)
/// </summary>
StdS,

/// <summary>
/// Population variance of all non-NaN values (since RedisTimeSeries v1.8)
/// </summary>
VarP,

/// <summary>
/// Sample variance of all non-NaN values (since RedisTimeSeries v1.8)
/// </summary>
VarS
}
}
177 changes: 176 additions & 1 deletion tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public void TestMRangeGroupby()
}

[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
public void TestMRangeReduce()
public void TestMRangeReduceSum()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
Expand All @@ -281,6 +281,181 @@ public void TestMRangeReduce()
}
}

[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
public void TestMRangeReduceAvg()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
var ts = db.TS();
foreach (var key in _keys)
{
var label = new TimeSeriesLabel("key", "MRangeReduce");
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
}

var tuples = CreateData(ts, 50);
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.Avg));
Assert.Equal(1, results.Count);
Assert.Equal("key=MRangeReduce", results[0].key);
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
Assert.Equal(new TimeSeriesLabel("__reducer__", "avg"), results[0].labels[1]);
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
for (int i = 0; i < results[0].values.Count; i++)
{
Assert.Equal(tuples[i].Val, results[0].values[i].Val);
}
}

[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
public void TestMRangeReduceRange()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
var ts = db.TS();
foreach (var key in _keys)
{
var label = new TimeSeriesLabel("key", "MRangeReduce");
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
}

var tuples = CreateData(ts, 50);
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.Range));
Assert.Equal(1, results.Count);
Assert.Equal("key=MRangeReduce", results[0].key);
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
Assert.Equal(new TimeSeriesLabel("__reducer__", "range"), results[0].labels[1]);
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
for (int i = 0; i < results[0].values.Count; i++)
{
Assert.Equal(0, results[0].values[i].Val);
}
}

[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
public void TestMRangeReduceCount()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
var ts = db.TS();
foreach (var key in _keys)
{
var label = new TimeSeriesLabel("key", "MRangeReduce");
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
}

var tuples = CreateData(ts, 50);
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.Count));
Assert.Equal(1, results.Count);
Assert.Equal("key=MRangeReduce", results[0].key);
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
Assert.Equal(new TimeSeriesLabel("__reducer__", "count"), results[0].labels[1]);
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
for (int i = 0; i < results[0].values.Count; i++)
{
Assert.Equal(2, results[0].values[i].Val);
}
}

[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
public void TestMRangeReduceStdP()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
var ts = db.TS();
foreach (var key in _keys)
{
var label = new TimeSeriesLabel("key", "MRangeReduce");
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
}

var tuples = CreateData(ts, 50);
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.StdP));
Assert.Equal(1, results.Count);
Assert.Equal("key=MRangeReduce", results[0].key);
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
Assert.Equal(new TimeSeriesLabel("__reducer__", "std.p"), results[0].labels[1]);
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
for (int i = 0; i < results[0].values.Count; i++)
{
Assert.Equal(0, results[0].values[i].Val);
}
}

[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
public void TestMRangeReduceStdS()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
var ts = db.TS();
foreach (var key in _keys)
{
var label = new TimeSeriesLabel("key", "MRangeReduce");
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
}

var tuples = CreateData(ts, 50);
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.StdS));
Assert.Equal(1, results.Count);
Assert.Equal("key=MRangeReduce", results[0].key);
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
Assert.Equal(new TimeSeriesLabel("__reducer__", "std.s"), results[0].labels[1]);
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
for (int i = 0; i < results[0].values.Count; i++)
{
Assert.Equal(0, results[0].values[i].Val);
}
}

[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
public void TestMRangeReduceVarP()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
var ts = db.TS();
foreach (var key in _keys)
{
var label = new TimeSeriesLabel("key", "MRangeReduce");
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
}

var tuples = CreateData(ts, 50);
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.VarP));
Assert.Equal(1, results.Count);
Assert.Equal("key=MRangeReduce", results[0].key);
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
Assert.Equal(new TimeSeriesLabel("__reducer__", "var.p"), results[0].labels[1]);
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
for (int i = 0; i < results[0].values.Count; i++)
{
Assert.Equal(0, results[0].values[i].Val);
}
}

[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
public void TestMRangeReduceVarS()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
var ts = db.TS();
foreach (var key in _keys)
{
var label = new TimeSeriesLabel("key", "MRangeReduce");
ts.Create(key, labels: new List<TimeSeriesLabel> { label });
}

var tuples = CreateData(ts, 50);
var results = ts.MRange("-", "+", new List<string> { "key=MRangeReduce" }, withLabels: true, groupbyTuple: ("key", TsReduce.VarS));
Assert.Equal(1, results.Count);
Assert.Equal("key=MRangeReduce", results[0].key);
Assert.Equal(new TimeSeriesLabel("key", "MRangeReduce"), results[0].labels[0]);
Assert.Equal(new TimeSeriesLabel("__reducer__", "var.s"), results[0].labels[1]);
Assert.Equal(new TimeSeriesLabel("__source__", string.Join(",", _keys)), results[0].labels[2]);
for (int i = 0; i < results[0].values.Count; i++)
{
Assert.Equal(0, results[0].values[i].Val);
}
}

[SkipIfRedis(Is.OSSCluster, Is.Enterprise)]
public void TestMRangeFilterBy()
{
Expand Down

0 comments on commit aed3c93

Please sign in to comment.