Warp10 tutorial - 2025/11/10

Table of Contents

We will study here the basic usage of a Time Series Database. We will base our work on the Warp10 database, and study how to use it from the command line and through its web interface. We will query existing data, inject custom data and build some queries against it, illustrating some features of Warp10.

You are expected to give back a report (1 per pair group), where you will copy the queries and results - do not forget to include the question number. Text content should be inserted as text, not as an image.

Key concepts

Warp10 stores points as GTS (GeoTime Series). A data point is composed of a timestamp, optional geolocation as latitude:longitude, optional elevation information (as millimeters), then a class and different labels to identify the series, then the value. Values can be strings (with single quotes), floats, longs, or booleans, or even multivalued.

Classnames and labels are indexed: Warp10 will quickly query data based on them. They should contain appropriate metadata (source of measurement, sensor id…). In querying, classnames can be queried by extract name, or by regexp - keep that in mind when defining you classnames.

The database can be queried using a query language named WarpScript, which is a RPN (Reverse Polish Notation) language, based on heavy stack usage for both passing parameters or outputting/pushing values. See this Warp10 documentation for illustrated examples. There is also a more conventional language called FLoWS that we will not use in the context of this tutorial.

Data is produced by a producer for an owner by an application. Owner and Producer are 128 bits UUIDs. Application is a string. Data is consumed by an owner within an application.

Setup

We will use the standalone Warp10 version, which only requires java, using basic instructions (more info on the warp10 website).

For settings things up, download static binaries from https://www.warp10.io/download (direct link)

Uncompress the archives, move the directory to $HOME/warp10, and run the server in a terminal (again: make sure you are in the right directory):

./bin/warp10.sh init standalone to initialize the server structure. Data are stored in LevelDB in the leveldb directory

./bin/warp10.sh start to start the server. It should listen on http://localhost:8080/api/v0

Windows users Note that this is a shell script, not powershell or cmd, so use WSL.

Token generation

Warp10 uses tokens to grant read and write access (with more fine grained control possible). A token is generated from a .mc2 file in the tokens directory, that defines the application name (equivalent to a database - different applications do not see each other's data), expiry period, etc.

Copy demo-tokengen.mc2 to polytech.mc2 and edit this last file to change the application name from demo.CHANGEME to tp.polytech

Run ./bin/warp10.sh tokengen tokens/polytech.mc2 to generate access tokens. They will be printed as JSON on stdout, with 1 token for reading and 1 for writing. These tokens should be specified for the different queries/updates that we can do on the server, and are associated with the given application name.

[Question 1] Copy in the report the generated JSON (actually it is more so that you keep it as a reference)

Note that Tokens are valid for a fixed period of time (configurable in the .mc2 file).

WarpStudio interface

All interaction can be done through the HTTP API (see available endpoints), but it requires to URL-encode the parameters, which is not convenient (but can be useful to automate things). In this tutorial, we will use the WarpStudio web application. Access it through https://studio.senx.io/ (note: this is the hosted version, you could also run the studio interface locally).

In the top-left selector, make sure that you are referencing the http://localhost:8080/api/v0 instance (and not the sandbox one). As described in the 00-Welcome tutorial, configure the interface to have the tokens available in every request:

Go to settings (⚙ gear icon) / Warp 10 instances / Click "Edit" on the localhost endpoint and insert the code that stores your tokens as RT (Read Token) and WT (Write Token) in the WarpScript Bootstrap field. This code will be executed before each query to the given server, and give a convenient access to the token values.

'XXX..XX' 'RT' STORE

'YYY..YY' 'WT' STORE

Note These commands simply define the RT and WT variables so that their values - the tokens - are easily accessible in the queries that you will do, with the $RT syntax.

Have a look and experiment for 10 minutes with the 01-Basic file to get a feel of the WarpScript syntax. The book icon (top right) in the studio gives access to the WarpLib reference guide which gives detailed information about each function. There is also a CheatSheet for quick reference.

You can save (Save icon in top right toolbar) your current editor content into the browser storage - do not hesitate to do it frequently with different names for the different steps.

Exploring existing data

We want to analyse the water levels of the Loire river, in Nantes and in Tours. The https://www.hydro.eaufrance.fr/ website presents the river water levels. We will get data for the Loire river in Nantes: https://www.hydro.eaufrance.fr/stationhydro/M800001010/series and in Tours: https://www.hydro.eaufrance.fr/stationhydro/K490003010/series

We want the water levels ("Hauteur instantanée") for the period 01/01/2020 to 01/01/2023. Use the form to query for the data, then in the result page, select "Tableau" and "Export des données au format CSV".

We will need to convert the CSV files to the GTS ingest format (text file, 1 record per line). Write a script (python is the easy choice, but you can pick the language you prefer) to convert from CSV to the appropriate GTS format, described in https://www.warp10.io/content/03_Documentation/03_Interacting_with_Warp_10/03_Ingesting_data/02_GTS_input_format https://www.warp10.io/content/03_Documentation/015_What_is_a_GTSQMk

We will use the classname water.level with the labels station (containing the id of the station, e.g. M800001010) and the city label containing the name of the city (Nantes, Tours).

Pay attention to:

  • the time unit
  • the location information can be found on the website ("Fiche d'identité") but in Lambert93 projection format. Find out the format used by Warp10 and use the https://geofree.fr/gf/coordinateconv.asp website to convert the locations in the appropriate format
  • the elevation information should be expressed as a long, in millimeters.

[Question 2] What are the coordinates in the Warp10 format for each station?

If you write the convert script in python, you should use the csv and datetime modules.

[Question 3] Give the source of the conversion script (embedded in the report, or as a separate file in a .tar.gz/.zip file).

Ingest the data into the Warp10 db using curl. Note that you will have to specify the -X POST option to use the POST method. Use also the -v option to get a more verbose output and see the response code (which is 200 if everything went fine).

[Question 4] What is the curl command you used to ingest a GTS file?

Global exploration

To get a first confirmation that you actually uploaded data, go to the Explore tab in the Studio interface, make sure that the localhost server is selected, enter the read token, and check if Explore gives an output.

After reading the 02-find-and-fetch-data tutorial, list the defined data series (classname+label).

[Question 5] Give the WarpScript query, and its output (hint: FINDSETS)

[Question 6] Give the WarpScript query to fetch the different timeseries for the class water.level between 2020-01-01T00:00:00 and 2023-01-01T00:00:00 and store it in a ts variable. Add also $ts as last command to push the GTS on the stack, so that you can visualize it.

Note: when your output is a GTS or a list of GTS, then the DataViz and Tabular View are available to display the data in different forms.

Since there is a huge number of datapoints, the DataViz component has trouble processing it properly. Notice however the global characteristics for both GTS, and have a look at the timestamps for some datapoints.

Warp10 provides the LTTB / TLTTB functions for downsampling using the Largest Triangle Three Buckets algorithm (trying to preserve the overall shape of the data). Try to apply the TLTTB algorithm with a number of samples of 100, then 1000, then 2000. Observe the differences in perception of the nature of the data.

You can also explore the different types of chart types that are available (see selector on the right) and also the visualisation of the map along the chart - not very useful here, except to check that your geolocation conversion is OK.

[Question 7] Determine the size (number of points) of each GTS in number of elements as a list (hint: LMAP - you will have to use a macro and pay attention to parameters). Give the result and the query.

The number of samples is different between both GTS. To be able to compare them more easily, we will bucketize the data (to align on the same intervals) and fill the missing indexes between both series.

Bucketize the data using 1h interval, using the bucketizer.mean function. Notice how the timestamps of the datapoints are now aligned on hour values.

[Question 8] Give the query for bucketizing the list of GTS.

The timestamps are now aligned, but there are many missing values. To align both series, we may drop the non-matching points (see this blog post), or fill them with interpolated values. We will try to interpolate using the filler.spline interpolator.

Note: the FILL command expects 2 GTS on the stack (and not a list of GTS). To convert from the list of GTS to its components, use LIST-> DROP (because LIST-> outputs the list contents and the number of elements). Then you can apply the FILL command, and convert the result back to a list using 2 ->LIST.

[Question 9] Give the query for filling the missing values using the filler.spline interpolator. Once filling is done, give the number of samples in each GTS.

Building a dashboard

Warp10 defines a dashboard building stack in the form of web components. The Dashboard components can combine multiple visualizations into a single-page dashboard.

Extend the provided dashboard.html (Right click/Save As) template to build a dashboard displaying water levels in Nantes and Tours, one above the other. Add a statistics panel for each city displaying the min and max values of the data.

[Question 10] Provide the updated dashboard file.

Note that we are only using static data here, but the dashboard components are able to update regularly in order to provide a real-time dashboard.

Bonus question

Until then, we used the default parameters of Warp10, which limits heap size to 1GB, in order to be able to run on low-end devices (like Raspberry). For some analyses, we will need more memory. Run ./bin/warp10.sh stop to stop the server, edit the etc/warp-end.sh file to raise WARP10_HEAP and WARP10_HEAP_MAX to 8g (or more depending on your available memory). Then restart the server.

The pattern for Nantes looks seasonal - especially compared with Tours, which is upstream. Do you have an idea why?

[Question 12] Use the STL function (Seasonal Trend decomposition) on the Nantes GTS to determine its different seasonality parameters.

To go further

We only saw here some basic features of the Warp10 stack. We did not address complex queries, continuous queries, triggering alerts, anomaly detection, forecasting … Feel free to explore.

You can also experiment with more features using the Warp10 Cyclones tutorial to analyze cyclone trajectories and characteristics.

On forecasting, you may want to explore the current trendy LLM models (but beware that for some use cases, they will be less efficient than more traditional approaches) like NeuralForecast or TimesFM.

Author: Olivier Aubert

Validate