Contexte

Il est assez commun qu’on aie besoin de travailler avec le temps dans R.

Dans le cas de l’analyse de log le temps reste le fil conducteur de l’analyse pour étudier l’évolution des activités, détecter des comportements et des tendances chronologiques, mettre en évidence la corrélation entre les messages d’un log avec ceux d’un autre etc.

Plusieurs sites et blogs discutent du sujet de la manipulation des dates et du temps en utilisant R. Une liste de liens intéressants est proposée dans le dernier paragraphe. Voici la documentation officielle : https://stat.ethz.ch/R-manual/R-devel/library/base/html/DateTimeClasses.html qui décrit les classes POSIXlt et POSIXct qui permettent de manipuler dates et temps.

Dans ce blog nous allons faire un tour d’horizon de quelques méthodes qui peuvent être utiles quand on manipule le temps avec R. Nous aborderons le cas où les données sont lue dans une table Cassandra. Plus généralement vous verrez comment transformer les formats de date “int” et “String” en objets date facilement manipulables par R.

Lecture avec Cassandra

Soit une table Cassandra qui s’appelle “messages” qui se trouve dans un keyspace qui s’appelle “leuville”. Avant de commencer vous devez télécharger le driver jdbc: cassandra-jdbc-2.1.1.jar (http://www.java2s.com/Code/Jar/c/Downloadcassandrajdbc125jar.htm), mais aussi:

  • apache-cassandra-clientutil-1.2.6.jar
  • apache-cassandra-thrift-1.2.6.jar
  • cassandra-all-1.2.9.jar
  • guava-15.0.jar
  • jackson-core-asl-1.9.2.jar
  • jackson-mapper-asl-1.9.2.jar
  • libthrift-0.7.0.jar
  • log4j-1.2.15.jar
  • slf4j-api-1.5.2.jar
  • slf4j-log4j12-1.5.2.jar
  • slf4j-simple-1.5.2.jar

Une fois les .jar téléchargés et mis dans un dossier “/cheminVersLaLibrairie/cassandra-jdbc-2.1.1”:

Lister les .jar dans la librairie cassandra jdbc

libraryFiles <- list.files("/cheminVersLaLibrairie/cassandra-jdbc-2.1.1", pattern="jar$", full.names=T)

Utiliser la librairie et le driver cassandra jdbc pour créer le driver Cassandra

cassdrv <- JDBC("org.apache.cassandra.cql.jdbc.CassandraDriver", libraryFiles)

Lancer une connexion sur la base Cassandra et le keyspace ‘leuville’

casscon <- dbConnect(cassdrv, "jdbc:cassandra://adresseIP:portCassandra/leuville")

Recuperer les colonnes voulues de la table “messages” et les stocker dans “dataAll”

dataAll <- dbGetQuery(casscon, "select application_id, uuid, direction, client_ip, data, blobAsBigint(timestampAsBlob(datetime)), headers, host, hostname, ip, method, parameters, status_code, uri from messages")

La table “messages” contient entre autre une colonne datetime qui est un timestamp. Une façon de le lire, est de le transformer en “blob” puis en en int que nous allons transformer plus tard. (voir paragraphe “Transformation de format”)

Il est aussi possible de lire la table tel qu’elle est:

tableAll <- dbReadTable(casscon, "messages")

Dans ce cas la colonne datetime sera lue comme des Strings qu’on pourra transformer plus tard (voir paragraphe “Transformation de format”)

Transformation de format

int => date

Voici une fonction qui va permettre de transformer le format int sorti de la table Cassandra en une date. Noter que ce format est de type “epoch”: un int calculé avec comme origine la date du 1er Janvier 1970.

epochToDate <- function(x){
  options(digits.secs=6) # pour avoir les millisecondes
  as.POSIXct(x/1000, origin="1970-01-01")
}

La division par 1000 est nécessaire pour le format en sortie de Cassandra. Cette division n’est pas forcément nécessaire pour d’autre méthodes de lecture.

Cette fonction dans notre exemple pourra être utilisée comme suit: R datetime <- as.data.frame(epochToDate(messages$datetime))

Precision jusqu’à la milliseconde

Pour pouvoir garder une précision jusqu’aux millisecondes il est nécessaire à un moment dans votre code d’utiliser cette ligne de code:

options(digits.secs=6)

Dans notre exemple nous l’avons inclu dans la fonction de transformation. Ainsi la date Wed Apr 27 12:57:02 UTC 2016 dans Cassandra, devient 1.461762e+12 en int, et 2016-04-27 12:57:02.733 en date.

String => date

Pour pouvoir transformer une chaîne de caractère en une date il faut lui donner le pattern du format de cette chaîne de caractères.
Voici un exemple

```R
timeFormat <- "%a %b %d %H:%M:%S UTC %Y"
datetime <- strptime(messages$datetime, timeFormat)

Dans notre exemple le String lu avait cette forme : Wed Apr 27 12:57:02 UTC 2016. D’ou le timeFormat. Voici le résultat "2016-04-27 12:57:02 UTC"

Voici une page qui vous donne les briques pour trouver le pattern qui correpond à vos données:

Utilisation

Une fois transformées ces données peuvent être utilisée facilement par R.

On peut ainsi appliquer des transformations mathématiques à ces dates:

> dataAll$datetime[3]
[1] "2016-04-27 12:57:08.749 UTC"
> dataAll$datetime[1]
[1] "2016-04-27 12:57:02.733 UTC"
> dataAll$datetime[3] - dataAll$datetime[1]
Time difference of 6.015 secs

On peut faire directement des plots

plot(dataAll$datetime, dataAll$dataToAnalyse, type ="l", xlab = "Temps", ylab = "Données à analyser")

image

D’autres méthodes de manipulations de temps et de dates existent en R, voici quelques liens intéressants: