Skip to content
Back to top
View this page
Edit this page

# Timeseries

`valkey-py` supports RedisTimeSeries which is a time-series-database module for Valkey.

This example shows how to handle timeseries data with `valkey-py`.

## Health check

    [1]:

    import valkey

    r = valkey.Valkey(decode_responses=True)
    ts = r.ts()

    r.ping()

    [1]:

    True

## Simple example

### Create a timeseries

    [2]:

    ts.create("ts_key")

    [2]:

    True

### Add samples to the timeseries

We can either set the timestamp with an UNIX timestamp in milliseconds or use * to set the timestamp based en server’s clock.

    [3]:

    ts.add("ts_key", 1657265437756, 1)
    ts.add("ts_key", "1657265437757", 2)
    ts.add("ts_key", "*", 3)

    [3]:

    1657272304448

### Get the last sample

    [4]:

    ts.get("ts_key")

    [4]:

    (1657272304448, 3.0)

### Get samples between two timestamps

The minimum and maximum possible timestamps can be expressed with respectfully - and +.

    [5]:

    ts.range("ts_key", "-", "+")

    [5]:

    [(1657265437756, 1.0), (1657265437757, 2.0), (1657272304448, 3.0)]

    [6]:

    ts.range("ts_key", 1657265437756, 1657265437757)

    [6]:

    [(1657265437756, 1.0), (1657265437757, 2.0)]

### Delete samples between two timestamps

    [7]:

    print("Before deletion: ", ts.range("ts_key", "-", "+"))
    ts.delete("ts_key", 1657265437756, 1657265437757)
    print("After deletion:  ", ts.range("ts_key", "-", "+"))

    Before deletion:  [(1657265437756, 1.0), (1657265437757, 2.0), (1657272304448, 3.0)]
    After deletion:   [(1657272304448, 3.0)]

## Multiple timeseries with labels

    [8]:

    ts.create("ts_key1")
    ts.create("ts_key2", labels={"label1": 1, "label2": 2})

    [8]:

    True

### Add samples to multiple timeseries

    [9]:

    ts.madd([("ts_key1", "*", 1), ("ts_key2", "*", 2)])

    [9]:

    [1657272306147, 1657272306147]

### Add samples with labels

    [10]:

    ts.add("ts_key2", "*", 2,  labels={"label1": 1, "label2": 2})
    ts.add("ts_key2", "*", 2,  labels={"label1": 3, "label2": 4})

    [10]:

    1657272306457

### Get the last sample matching specific label

Get the last sample that matches “label1=1”, see Valkey documentation to see the posible filter values.

    [11]:

    ts.mget(["label1=1"])

    [11]:

    [{'ts_key2': [{}, 1657272306457, 2.0]}]

Get also the label-value pairs of the sample:

    [12]:

    ts.mget(["label1=1"], with_labels=True)

    [12]:

    [{'ts_key2': [{'label1': '1', 'label2': '2'}, 1657272306457, 2.0]}]

## Retention period

You can specify a retention period when creating timeseries objects or when adding a sample timeseries object. Once the retention period has elapsed, the sample is removed from the timeseries.

    [13]:

    retention_time = 1000
    ts.create("ts_key_ret", retention_msecs=retention_time)

    [13]:

    True

    [14]:

    import time
    # this will be deleted in 1000 milliseconds
    ts.add("ts_key_ret", "*", 1, retention_msecs=retention_time)
    print("Base timeseries:                     ", ts.range("ts_key_ret", "-", "+"))
    # sleeping for 1000 milliseconds (1 second)
    time.sleep(1)
    print("Timeseries after 1000 milliseconds:  ", ts.range("ts_key_ret", "-", "+"))

    Base timeseries:                      [(1657272307670, 1.0)]
    Timeseries after 1000 milliseconds:   [(1657272307670, 1.0)]

The two lists are the same, this is because the oldest values are deleted when a new sample is added.

    [15]:

    ts.add("ts_key_ret", "*", 10)

    [15]:

    1657272308849

    [16]:

    ts.range("ts_key_ret", "-", "+")

    [16]:

    [(1657272308849, 10.0)]

Here the first sample has been deleted.

## Specify duplicate policies

By default, the policy for duplicates timestamp keys is set to “BLOCK”, we cannot create two samples with the same timestamp:

    [17]:

    ts.add("ts_key", 123456789, 1)
    try:
        ts.add("ts_key", 123456789, 2)
    except Exception as err:
        print(err)

    TSDB: Error at upsert, update is not supported when DUPLICATE_POLICY is set to BLOCK mode

You can change this default behaviour using `duplicate_policy` parameter, for instance:

    [18]:

    # using policy "LAST", we keep the last added sample
    ts.add("ts_key", 123456789, 2, duplicate_policy="LAST")
    ts.range("ts_key", "-", "+")

    [18]:

    [(123456789, 2.0), (1657272304448, 3.0)]

For more informations about duplicate policies, see Valkey documentation.

## Using Valkey TSDB to keep track of a value

    [19]:

    ts.add("ts_key_incr", "*", 0)

    [19]:

    1657272310241

Increment the value:

    [20]:

    for _ in range(10):
        ts.incrby("ts_key_incr", 1)
        # sleeping a bit so the timestamp are not duplicates
        time.sleep(0.01)

    [21]:

    ts.range("ts_key_incr", "-", "+")

    [21]:

    [(1657272310241, 0.0),
     (1657272310533, 1.0),
     (1657272310545, 2.0),
     (1657272310556, 3.0),
     (1657272310567, 4.0),
     (1657272310578, 5.0),
     (1657272310589, 6.0),
     (1657272310600, 7.0),
     (1657272310611, 8.0),
     (1657272310622, 9.0),
     (1657272310632, 10.0)]

## How to execute multi-key commands on Open Source Valkey Cluster

    [4]:

    import valkey

    r = valkey.ValkeyCluster(host="localhost", port=46379)

    # This command should be executed on all cluster nodes after creation and any re-sharding
    # Please note that this command is internal and will be deprecated in the future
    r.execute_command("timeseries.REFRESHCLUSTER", target_nodes="primaries")

    # Now multi-key commands can be executed
    ts = r.ts()
    ts.add("ts_key1", "*", 2,  labels={"label1": 1, "label2": 2})
    ts.add("ts_key2", "*", 10,  labels={"label1": 1, "label2": 2})
    ts.mget(["label1=1"])

    [4]:

    [{'ts_key1': [{}, 1670927124746, 2.0]}, {'ts_key2': [{}, 1670927124748, 10.0]}]