Comments (6)
@shaunsales great input, as always.
Let's iterate over the design as I would like to have the IEnumerable
also implemented. This will cause it to be an implementation of IReadOnlyList
for an example
using System;
using System.Collections;
using System.Collections.Generic;
namespace NRedisTimeSeries.DataTypes
{
public class TimeSeriesCollection : IReadOnlyList<(long, double)>
{
public TimeSeriesCollection()
{
}
public (long, double) this[int index] => throw new NotImplementedException();
public int Count => throw new NotImplementedException();
public IEnumerator<(long, double)> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
}
What do you think?
Thanks for your inputs
from nredistimeseries.
Here's a first cut of a timeseries collection class that I think would meet our requirements;
public class TsCollection : IEnumerator<(long TimeStamp, double Value)>
{
private int _index = -1;
private RedisResult[] _redisResults;
public TsCollection(RedisResult redisResult)
{
_redisResults = (RedisResult[])redisResult;
}
public (long TimeStamp, double Value) this[int index]
{
get
{
var item = (RedisResult[])_redisResults[index];
return ((long)item[0], (double)item[1]);
}
}
public int Count => _redisResults.Length;
public IEnumerator<(long TimeStamp, double Value)> GetEnumerator() => this;
public (long TimeStamp, double Value) Current => (_index > -1 && _index <= _redisResults.Length) ? this[_index] : throw new IndexOutOfRangeException();
object IEnumerator.Current => Current;
public bool MoveNext() => ++_index < _redisResults.Length;
public void Dispose() => Reset();
public void Reset() => _index = -1;
}
I've not implemented it as a readonly or immutable collection as that adds quite a bit of overhead that I didn't feel was necessary. If there's a good reason to make the collection immutable, I suggest we use ImmutableArray<T>
or ImmutableList<T>
but given the underlying RedisResult[] is not immutable or readonly it seems better to follow the same pattern.
from nredistimeseries.
@shaunsales
Let's split the logic between the enumerator and the direct access functionality
something like
using System;
using System.Collections;
using System.Collections.Generic;
using StackExchange.Redis;
namespace NRedisTimeSeries.DataTypes
{
public class TsCollection : IReadOnlyList<(long TimeStamp, double Value)>
{
private static (long, double) ResultAsTuple(RedisResult result)
{
var item = (RedisResult[])result;
return ((long)item[0], (double)item[1]);
}
private class TsCollectionEnumerator : IEnumerator<(long TimeStamp, double Value)>
{
private int _index = -1;
RedisResult[] _results;
public TsCollectionEnumerator(TsCollection collection)
{
_results = collection._redisResults;
}
public (long TimeStamp, double Value) Current => (_index > -1 && _index <= _results.Length) ? ResultAsTuple(_results[_index]) : throw new IndexOutOfRangeException();
object IEnumerator.Current => Current;
public bool MoveNext() => ++_index < _results.Length;
public void Reset() => _index = -1;
public void Dispose() => Reset();
}
private RedisResult[] _redisResults;
public TsCollection(RedisResult redisResult)
{
_redisResults = (RedisResult[])redisResult;
}
public (long, double) this[int index]
{
get => ResultAsTuple(_redisResults[index]);
}
public int Count => _redisResults.Length;
public IEnumerator<(long, double)> GetEnumerator() => new TsCollectionEnumerator(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
WDYT?
from nredistimeseries.
Looking good. I've made a few (quick and dirty) updates to include MRANGE
as a collection of ranges with Name
and Label
support.
public class TsMRangeResults : IReadOnlyList<TsMRangeResult>
{
private class TsMRangeEnumerator : IEnumerator<TsMRangeResult>
{
private int _index = -1;
private IReadOnlyList<TsMRangeResult> _tsMRangeResults;
public TsMRangeEnumerator(TsMRangeResults collection) => _tsMRangeResults = collection._tsMRangeResults;
public TsMRangeResult Current => (_index > -1 && _index <= _tsMRangeResults.Count) ? _tsMRangeResults[_index] : throw new IndexOutOfRangeException();
object IEnumerator.Current => Current;
public bool MoveNext() => ++_index < _tsMRangeResults.Count;
public void Reset() => _index = -1;
public void Dispose() => Reset();
}
private IReadOnlyList<TsMRangeResult> _tsMRangeResults;
public int Count { get; }
public TsMRangeResults(RedisResult redisResult)
{
var redisResults = (RedisResult[])redisResult;
Count = redisResults.Length;
if (redisResults.Length > 0)
{
var list = new List<UserQuery.TsMRangeResult>(redisResults.Length);
for (int i = 0; i < redisResults.Length; i++)
{
list.Add(new TsMRangeResult(redisResults[i]));
}
_tsMRangeResults = list;
}
}
public TsMRangeResult this[int index] => _tsMRangeResults[index];
public IEnumerator<TsMRangeResult> GetEnumerator() => new TsMRangeEnumerator(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class TsMRangeResult : TsRangeResult
{
public string Name { get; }
public IList<(string, string)> Labels { get; }
public TsMRangeResult(RedisResult redisResult) : base((RedisResult[])redisResult)
{
var redisResults = (RedisResult[])redisResult;
Name = (string)redisResults[0];
var labels = (RedisResult[])redisResults[1];
if (labels.Length > 0)
{
Labels = new List<(string, string)>(labels.Length);
for (int i = 0; i < labels.Length; i++)
{
var labelValue = (RedisResult[])labels[i];
Labels.Add(((string)labelValue[0], (string)labelValue[1]));
}
}
}
}
public class TsRangeResult : IReadOnlyList<(long TimeStamp, double Value)>
{
private static (long TimeStamp, double Value) ResultAsTuple(RedisResult result)
{
var item = (RedisResult[])result;
return ((long)item[0], (double)item[1]);
}
private class TsRangeResultEnumerator : IEnumerator<(long TimeStamp, double Value)>
{
private int _index = -1;
RedisResult[] _redisResults;
public TsRangeResultEnumerator(TsRangeResult collection) => _redisResults = collection._redisResults;
public (long TimeStamp, double Value) Current => (_index > -1 && _index <= _redisResults.Length) ? ResultAsTuple(_redisResults[_index]) : throw new IndexOutOfRangeException();
object IEnumerator.Current => Current;
public bool MoveNext() => ++_index < _redisResults.Length;
public void Reset() => _index = -1;
public void Dispose() => Reset();
}
private RedisResult[] _redisResults;
public int Count { get; }
public TsRangeResult(RedisResult redisResult)
{
// TODO: Add some data shape checks
_redisResults = (RedisResult[])redisResult;
Count = _redisResults.Length;
}
protected TsRangeResult(RedisResult[] redisResults)
{
_redisResults = (RedisResult[])redisResults[2];
}
public (long TimeStamp, double Value) this[int index] => ResultAsTuple(_redisResults[index]);
public IEnumerator<(long TimeStamp, double Value)> GetEnumerator() => new TsRangeResultEnumerator(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
This will allow users to access the timeseries results with fairly simply syntax. Here's a couple of examples;
var tsMRangeResults = new TsMRangeResults(db.Execute("TS.MRANGE", new[] { "-", "+", "WITHLABELS", "FILTER", "lbl=abc" }));
foreach (var mRange in tsMRangeResults)
{
foreach (var item in mRange)
{
$"{mRange.Name} {item.TimeStamp}:{item.Value} {mRange.Labels.Count}".Dump();
}
}
var tsRange = new TsRangeResult(db.Execute("TS.RANGE", new[] { key, "-", "+" }));
foreach (var item in tsRange)
{
$"{item.TimeStamp}:{item.Value}".Dump();
}
from nredistimeseries.
Nice approach
I think that you can apply the iterator approach everywhere here so you will not have to allocate lists at all
Let's first finish with PR #35 and continue with this
from nredistimeseries.
Nice approach
I think that you can apply the iterator approach everywhere here so you will not have to allocate lists at all
Let's first finish with PR #35 and continue with this
Agreed - the labels implementation was a bit quick and dirty. I think we can optimise and improve this once we turn it into a PR.
from nredistimeseries.
Related Issues (20)
- Missing TS.REVRANGE and TS.MREVRANGE commands HOT 6
- Add support for CHUNK_SIZE optional parameter on TS.CREATE command
- Refactor TimeStamp class to UNIXTimeStamp HOT 6
- Simplify the Aggregation type HOT 2
- Support for DUPLICATE_POLICY on TS.CREATE and TS.ADD
- Pipelining of TS.ADD HOT 2
- Support TS.MRANGE/MREVRANGE GROUPBY <label> REDUCE <reducer>
- Support for OSS Cluster HOT 1
- Add examples and further notes about duplicate policy HOT 3
- [question] When release 1.4 will be available? HOT 1
- Add support for FILTER_BY_TIME/VALUE
- Add zrevrangebyts ? HOT 2
- Add support for TS.DEL
- Add GROUPBY and REDUCE support HOT 2
- Add aggregation ALIGN option
- SELECTED_LABELS label1 ... support for TS.MRANGE and TS.MREVRANGE
- How to store/retrieve multivariate time series HOT 1
- ON_DUPLICATE appears as a label when duplicatePolicy argument has value
- How to remove a time series entry? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nredistimeseries.