Le bucketing (ou segmentation) est une technique d'optimisation qui modifie la structure de stockage d'une table Hive. Contrairement au partitionnement qui découpe la table en sous-répertoires, le bucketing répartit les données dans plusieurs fichiers distincts.
Le principe est de distribuer les enregistrements de manière aléatoire et uniforme entre un nombre défini de seaux (buckets). Pour cela, on applique une fonction de hachage sur la clé de bucketing, puis on prend le modulo du nombre de seaux. Par exemple, si l'on choisit un champ id comme clé et que l'on souhaite 3 seaux, les valeurs de id sont réparties comme suit :
- Bucket 0 : ids 3, 6, 9
- Bucket 1 : ids 1, 4, 7, 10
- Bucket 2 : ids 2, 5, 8
Chaque seau est stocké dans un fichier distinct.
Objectifs du bucketing
Le bucketing améliore les performances pour les requêtes, les échantillonnages et les jointures. En effet, lors d'une requête avec un filtre sur la clé de bucketing, Hive peut directement localiser le fichier concerné via le hachage modulo, réduisant ainsi le volume de données à traiter. Pour l'échantillonnage, il suffit de lire quelqeus seaux au lieu de la table entière.
Lorsque deux tables sont bucketées sur la même clé et avec le même nombre de seaux (ou un multiple), les jointures deviennent plus efficaces car les données correspondantes se trouvent dans les mêmes fichiers, évitant l'étape coûteuse de shuffle lors de l'exécution MapReduce ou Spark.
Il est possible de combiner partitionnement et bucketing : on partitionne d'abord la table (sous-répertoires), puis on bucket les données de chaque partition (fichiers multiples).
Création d'une table bucketée
Prenons le'xemple d'une table employes avec les colonnes id, nom, age. On choisit l'identifiant comme clé de bucketing et 3 seaux.
Avant toute chose, il faut activer le bucketing :
set hive.enforce.bucketing=true;
set mapreduce.job.reduces=4;
Remarque : Ce paramètre force le nombre de reducers à correspondre au nombre de seaux. Dans les versions antérieures à Hive 2.x, il n'était pas nécessaire.
Création de la table :
CREATE TABLE employes (
id INT,
nom STRING,
age INT
)
CLUSTERED BY (id) INTO 3 BUCKETS
STORED AS TEXTFILE;
Insertion de données :
-- Activation du bucketing
SET hive.enforce.bucketing=true;
-- Insertions
INSERT INTO employes VALUES (1, 'Alice', 25);
INSERT INTO employes VALUES (2, 'Bob', 30);
INSERT INTO employes VALUES (3, 'Charlie', 22);
INSERT INTO employes VALUES (4, 'David', 28);
Vérification :
SELECT * FROM employes;
Le concept de bucket est analogue à celui de partition dans MapReduce : chaque bucket correspond à un fichier, et le nombre de fichiers produits égale le nombre de reduce tasks. En revanche, le partitionnement Hive est une notion différente qui organise les données en dossiers.
Pour insérer des données déjà bucketées et triées, on peut utiliser DISTRIBUTE BY et SORT BY, ou CLUSTER BY lorsque la clé de bucketing et de tri sont les mêmes :
INSERT INTO employes
SELECT id, nom, age FROM autres_tables
DISTRIBUTE BY id
SORT BY id ASC;
L'option CLUSTER BY équivaut à DISTRIBUTE BY + SORT BY sur la même colonne.