VT2020-QuestDB-Demo

From air
Revision as of 23:06, 5 December 2020 by Tom.Graugnard (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Installation

Il n'y a pas d'installation préalable à faire, si ce n'est celle QuestDB disponible ici. Il est également nécessaire de disposer d'un navigateur web tel que Firefox.

Vous pouvez également tester QuestDB en vous rendant sur leur démo en ligne, disponible ici.

Démonstration

Pour rappel, pour lancer la base de données, placez vous dans le dossier bin/ et effectuez la commande

./questdb.sh start

Rendez vous maintenant dans votre navigateur favori et accédez à l'adresse http://localhost:9000 . Vous devriez voir l'interface web de QuestDB.

Si vous souhaitez générez les mêmes données que moi

Si vous ne voulez pas exactement les mêmes données que moi, vous pouvez passer cette étape

Pour avoir le même rendu que pendant ma présentation, il vous faudra récupérer le programme par lequel j'ai généré mes données. Vous pouvez exécuter ce code python qui vous génère 10,000 entrées au format csv, en pensant a changer le chemin du PATH :

import random

PATH = '/home/tom/Documents/vt/data' # entrez ici le chemin vers votre fichier résultat
NB = 10000 # nombre d'entrées que l'on souhaite générer

# retourne le plus petit de 2 entiers.
def mini(a,b):
    if a>b:
        return a
    return b

# Renvoie 2 float tronquées au 4ème chiffre après la virgule.
# Les nouvelles valeurs générés ont un écart d'au plus 0.05 avec la valeur généré
# dans la boucle d'avant.
def valAlea(oldv1, oldv2): 
    v1 = str(random.uniform(mini(oldv1-0.05,0),oldv1+0.05))
    v2 = str(random.uniform(mini(oldv2-0.05,0),oldv2+0.05))
    v1 = float(v1[:6])
    v2 = float(v2[:6])
    return v1, v2

# Renvoie un entier entre min et max sous la forme d'un string.
# Si l'entier est compris entre 0 et 9, rajoute un 0 deavant.
def getRandString(minimum, maximum):
    tmp = random.randint(minimum, maximum)
    if tmp >= 0 and tmp <= 9:
        return '0' + str(tmp)
    return str(tmp)

# Pour que la date soit reconnue, il faut qu'il y ait 6 chiffres
# après la virgule. On rajoute donc des zéros jusqu'a obtenir
# 6 chiffres.
def toSize(reste):
    while len(reste) < 6:
        reste = '0' + reste
    return reste

# Renvoie une timestamp générée aléatoirement au format de QuestDB
def getRandTimestamp():
    jour = getRandString(1,30)
    heure = getRandString(0,23)
    minute = getRandString(0,59)
    seconde = getRandString(0,59)
    reste = toSize(getRandString(000000,999999))
    res = '2020-11-' + jour + 'T' + heure + ':' + minute + ':' + seconde + '.' + reste + 'Z\n'
    return res

# On initialise les valeurs de départs de v1 et v2
oldv1 = random.random()
oldv2 = random.random()
lv1 = []
lv2 = []
lvdate = []

f = open(PATH,'w')

f.write('euro|dollar|dateP\n') # entête du fichier csv

for i in range(NB):
    v1, v2 = valAlea(oldv1, oldv2)
    oldv1 = v1
    oldv2 = v2

    lv1.append(v1)
    lv2.append(v2)

    date = getRandTimestamp()
    lvdate.append(date)

# On trie les dates afin de les avoir de les insérer dans l'ordre croissant.
lvdate.sort()


for i in range(NB):
    s = str(lv1.pop(0))+'|'+str(lv2.pop(0))+'|'+lvdate.pop(0)
    f.write(s)


f.close()

Importation

Retournez sur l'interface web

Sur la barre de gauche, rendez vous dans la page d'import. Choisissez le fichier où vous avez généré vos données au format csv et importez le.

Attention : le nom de votre fichier sera le nom de votre table. Pensez a choisir un nom simple.

Vous pouvez maintenant revenir dans la console, toujours avec la barre de gauche. Vous pouvez faire une requête pour voir si votre fichier a bien été importé simplement en tapant le nom de la table et en appuyant sur Run.

Si la table n'apparait pas, vous pouvez recharger les tables depuis le disque en appuyant sur le bouton Refresh.

Attention : Il existe un bug encore non résolu lors de l'importation de données en csv qui empêche l'ajout d'une contrainte designated timestamp. Nous allons donc devoir procéder en 2 étapes.

Une fois cette table crée, nous allons créer notre table finale avec une requête SQL. On part du principe que la table que vous avez importé s'appelle dataTest :

CREATE TABLE euroDollar AS
(dataTest)
TIMESTAMP(dateP)
PARTITION BY DAY;

On se retrouve avec une table disposant d'un designated timestamp et partitionné en jour. Vous pouvez supprimer la table dataTest avec :

DROP TABLE dataTest;

La table livre a été crée de la même manière en modifiant légèrement le programme python.

Générer des données dans la console

Vous pouvez à pressent créer une table directement depuis cette console grâce à cette requête :

CREATE TABLE readings
AS(
    SELECT
        x ID,
        timestamp_sequence(to_timestamp('2019-10-17T00:00:00', 'yyyy-MM-ddTHH:mm:ss'), rnd_long(1,10,2) * 100000L) ts,
        rnd_double(0)*8 + 15 temp,
        rnd_long(0, 10000, 0) sensorId,
        rnd_symbol(4, 1, 2, 0) symb
    FROM long_sequence(10000000) x),
    Index(symb)
TIMESTAMP(ts)
PARTITION BY MONTH;

Si vous n'avez pas suivi la première étape, vous pouvez recréer une table en changeant readings par un autre nom.

Exécution

On part maintenant du principe que vous avez 2 tables avec des valeurs temporelles proches, soient grâce au fichier python, soit directement avec les requêtes SQL. Par la suite les tables utilisés seront euroDollar et livres. Si les votre ont des noms différents, remplacez les dans les requêtes.

Vous pouvez échantillonner les données de cette manière :

SELECT avg(euro)
FROM euroDollar
SAMPLE BY 1D;

Le résultat sera la moyenne des valeurs contenus dans la colonne euro par jour.

Vous pouvez tester les comparaisons simplifié de timestamp avec :

SELECT *
FROM livres
WHERE dateE='2020-11-23';

ou bien simplement :

livres
WHERE dateE='2020-11-23';

avec l'amélioration de ANSI SQL.

Vous pouvez essayer d'insérer une donnée temporelle plus ancienne que la dernière valeur dans un designated timestamp avec :

INSERT INTO euroDollar
VALUES (2.987, 3.456, to_timestamp('2019-10-17T00:00:00', 'yyyy-MM-ddTHH:mm:ss'));

QuestDB vous renvoie une erreur.

Vous pouvez joindre des tables avec des données temporelles non exactes :

SELECT euro, livre, dateP
FROM euroData
ASOF JOIN livres

Vous pouvez tenter de faire des requêtes lourdes sur la table readings qui a 10 millions de ligne, et remarquer que les temps d'éxécutions sont courts.