Dans les entreprises et administrations, un nombre croissant de données sont
disponibles depuis un système de stockage
nommé S3.
Le système S3 (Simple Storage System) est un système de stockage développé
par Amazon et qui est maintenant devenu une référence pour le stockage en ligne.
Il s’agit d’une architecture à la fois
sécurisée (données cryptées, accès restreints) et performante.
Le concept central du système S3 est le bucket.
Un bucket est un espace (privé ou partagé) où on peut stocker une
arborescence de fichiers. Pour accéder aux fichiers figurant
dans un bucket privé, il fournit des jetons d’accès (l’équivalent d’un mot de passe)
reconnus par le serveur de stockage. On peut alors lire et écrire dans le bucket.
Le SSP cloud
repose par exemple sur cette infrastructure technique.
Comment faire avec Python ?
Les librairies principales
L’interaction entre ce système distant de fichiers et une session locale de Python
est possible grâce à des API. Les deux principales librairies sont les suivantes:
boto3, une librairie créée et maintenue par Amazon ;
s3fs, une librairie qui permet d’interagir avec les fichiers stockés à l’instar d’un filesystem classique.
Ces deux librairies offrent toutes deux la possibilité de se connecter depuis Python,
à un dépôt de fichiers distant, de lister les fichiers disponibles dans un
bucket, d’en télécharger un ou plusieurs ou de faire de l’upload
Note
Les exemples suivants seront réplicables pour les utilisateurs de la plateforme
SSP-cloud
Personnellement, j’ai une petite préférence pour boto3 que je trouve plus
intuitif.
Quelques cas spéciaux
La librairie ultra-performante arrow
propose également un accès à des fichiers sur
S3 comme s’ils étaient disponibles sur un filesystem
local. Un exemple, assez court, est disponible
dans la documentation officielle
Les utilisateurs de
Snakemake
peuvent également
lire ou écrire des tables intermédiaires sur S3
comme s’ils utilisaient un
système de fichier local. En arrière-plan, snakemake
va utiliser boto3 pour communiquer avec le système
de stockage
Un outil très performant utilisant la ligne de commande est également
disponible. Son nom est mc pour
Minio Client.
Il propose les mêmes
opérations que la ligne de commande linux mais avec un système distant.
Connexion à un bucket
Par la suite, on va utiliser des alias pour les trois valeurs suivantes, qui servent
à s’authentifier.
Ces valeurs peuvent être également disponibles dans
les variables d’environnement de Python. Comme il s’agit d’une information
d’authentification personnelle, il ne faut pas stocker les vraies valeurs de ces
variables dans un projet, sous peine de partager des traits d’identité sans le
vouloir lors d’un partage de code.
Avec boto3, on créé d’abord un client puis on exécute des requêtes dessus.
Pour initialiser un client, il suffit, en supposant que l’url du dépôt S3 est
"https://minio.lab.sspcloud.fr", de faire:
La logique d’Arrow est proche de celle de s3fs. Seuls les noms
d’arguments changent
Si on a des jetons d’accès à jour et dans les variables d’environnement
adéquates:
from pyarrow import fs
s3 = fs.S3FileSystem(endpoint_override="http://"+"minio.lab.sspcloud.fr")
La logique de Snakemake est, quant à elle,
plus proche de celle de boto3. Seuls les noms
d’arguments changent
Si on a des jetons d’accès à jour et dans les variables d’environnement
adéquates:
from snakemake.remote.S3 import RemoteProvider as S3RemoteProvider
S3 = S3RemoteProvider(host ="https://"+ os.getenv('AWS_S3_ENDPOINT'))
Il se peut que la connexion à ce stade soit refusée (HTTP error 403).
Cela peut provenir
d’une erreur dans l’URL utilisé. Cependant, cela reflète plus généralement
des paramètres d’authentification erronés.
Les paramètres d’authentification sont des arguments supplémentaires:
La logique est la même, seuls les noms d’arguments diffèrent
from snakemake.remote.S3 import RemoteProvider as S3RemoteProvider
S3 = S3RemoteProvider(host ="https://"+ os.getenv('AWS_S3_ENDPOINT'), access_key_id=key_id, secret_access_key=access_key)
Notes
Dans le SSP-cloud,
lorsque l’initialisation du service Jupyter du SSP-cloud est récente
(moins de 12 heures), il est possible d’utiliser
automatiquement les jetons stockés automatiquement à la création du dépôt.
Si on désire accéder aux données du SSP-cloud depuis une session python du
datalab (service VSCode, Jupyter…),
il faut remplacer l’url par http://minio.lab.sspcloud.fr
Lister les fichiers
S’il n’y a pas d’erreur à ce stade, c’est que la connexion est bien effective.
Pour le vérifier, on peut essayer de faire la liste des fichiers disponibles
dans un bucket auquel on désire accéder.
Par exemple, on peut vouloir
tester l’accès aux bases FILOSOFI (données de revenu localisées disponibles
sur https://www.insee.fr) au sein du bucket donnees-insee.
Pour cela,
la méthode list_objects offre toutes les options nécessaires:
for key in s3.list_objects(Bucket='donnees-insee', Prefix='FILOSOFI')['Contents']:
print(key['Key'])
Pour lister les fichiers, c’est la méthode ls (celle-ci ne liste pas par
défaut les fichiers de manière récursive comme boto3):
fs.ls("donnees-insee")
from pyarrow import fs
s3 = fs.S3FileSystem(endpoint_override='http://'+'minio.lab.sspcloud.fr')
s3.get_file_info(fs.FileSelector('donnees-insee', recursive=True))
mc ls -r
Télécharger un fichier depuis s3 pour l’enregistrer en local
Cette méthode n’est en général pas recommandée car, comme on va le voir
par la suite, il est possible de lire à la volée des fichiers. Cependant,
télécharger un fichier depuis le cloud pour l’écrire sur le disque
local peut parfois être utile (par exemple, lorsqu’il est nécessaire
de dézipper un fichier).
mc cp "donnees-insee/FILOSOFI/2014/FILOSOFI_COM.csv"'data.csv'
Lire un fichier directement
La méthode précédente n’est pas optimale. En effet, l’un des intérêts des API
est qu’on peut traiter un fichier sur S3 comme s’il s’agissait d’un fichier
sur son PC. Cela est d’ailleurs une manière plus sécurisée de procéder puisqu’on
lit les données à la volée, sans les écrire dans un filesystem local.
from snakemake.remote.S3 import RemoteProvider as S3RemoteProvider
S3 = S3RemoteProvider(host ="https://"+ os.getenv('AWS_S3_ENDPOINT'))
bucket ="mon-bucket"rule ma_super_regle_s3:
input:
fichier = S3.remote(f'{bucket}/moninput.csv')
run:
import pandas as pd
df = pd.read_csv(input.fichier)
# PLUS D'OPERATIONS
Arrow est une librairie qui permet de lire des CSV.
Il est néanmoins
beaucoup plus pratique d’utiliser le format parquet avec arrow.
Dans un premier temps, on configure le filesystem avec les
fonctionalités d’Arrow (cf. précédemment).
from pyarrow import fs
s3 = fs.S3FileSystem(endpoint_override='http://'+'minio.lab.sspcloud.fr')
Pour lire un csv, on fera:
from pyarrow import csv
with s3.open_input_file("donnees-insee/FILOSOFI/2014/FILOSOFI_COM.csv") as file:
df = csv.read_csv(file, parse_options=csv.ParseOptions(delimiter=";")).to_pandas()
df.head(2)
Pour un fichier au format parquet, on privilégiera:
import pyarrow.parquet as pq
#bucket = ""#parquet_file=""df = pq.ParquetDataset(f'{bucket}/{parquet_file}', filesystem=s3).read_pandas().to_pandas()