Lorsque votre jeu de données atteint des centaines de millions de lignes, COUNT(DISTINCT ...) devient lent. Toutes les valeurs distinctes de chaque nœud sont transférées vers un unique nœud de niveau supérieur pour la fusion finale, ce qui crée un goulot d'étranglement proportionnel au volume de données et à la taille du bitmap. ApsaraDB for SelectDB résout ce problème grâce aux bitmaps orthogonaux : les données sont réparties en buckets afin que chaque nœud calcule indépendamment ses propres intersections ou unions. Seuls les résultats réduits transitent ensuite vers le nœud de niveau supérieur.
Fonctionnement des bitmaps orthogonaux
L'exécution standard de COUNT(DISTINCT ...) se déroule en deux étapes :
Scan (Node 1) Scan (Node 2)
+---------+---------+ +---------+---------+
| user_id | tag | | user_id | tag |
+---------+---------+ +---------+---------+
| 1 | A | | 3 | A |
| 2 | B | | 4 | C |
+---------+---------+ +---------+---------+
| |
+----------+ +-----------+
| |
Top-level node
Receives ALL distinct values
from every node, merges them
(bottleneck: I/O + single-node compute)
Dès qu'un bitmap dépasse 1 Go, cette étape de fusion finale devient le principal goulot d'étranglement, tant pour les E/S réseau que pour la charge de calcul sur un nœud unique.
ApsaraDB for SelectDB contourne cette limitation en utilisant une colonne hid (hash ID). Lors de la création de la table, un algorithme de hachage attribue les ID utilisateur à des buckets. Les valeurs de bitmap situées dans des buckets différents sont orthogonales (sans chevauchement), ce qui permet à chaque bucket de calculer son propre résultat de manière autonome :
Stage 1 (distributed): each bucket computes intersection/union locally
Stage 2 (merge): top-level node combines per-bucket results (small data only)
Cette approche élimine le goulot d'étranglement du nœud unique et permet de traiter des milliards de lignes.
Limites
Avant de commencer, prenez en compte les contraintes suivantes :
Modèle Aggregate Key obligatoire : La colonne bitmap doit appartenir à une table utilisant le modèle Aggregate Key, avec
BITMAP_UNIONcomme fonction d'agrégation.Tables partitionnées non prises en charge : Les fonctions de bitmap orthogonal ne s'appliquent pas aux tables partitionnées. Les limites de partition rompent la garantie d'orthogonalité entre les buckets, rendant les résultats peu fiables.
Cardinalité de
hidrequise : La cardinalité de la colonnehiddoit être au moins cinq fois supérieure au nombre de buckets afin d'assurer une distribution équilibrée des données après le hachage.
Configuration de la déduplication par bitmap
Étape 1 : Création de la table
Créez une table basée sur le modèle Aggregate Key, incluant un champ Value de type bitmap ainsi qu'une colonne hid pour le hachage par buckets.
CREATE TABLE `user_tag_bitmap` (
`tag` BIGINT(20) NULL COMMENT "User tag",
`hid` SMALLINT(6) NULL COMMENT "Bucket ID",
`user_id` BITMAP BITMAP_UNION NULL COMMENT "User bitmap"
) ENGINE=OLAP
AGGREGATE KEY(`tag`, `hid`)
COMMENT "OLAP"
DISTRIBUTED BY HASH(`hid`) BUCKETS 3;
La colonne hid divise la plage des user_id en groupes, chacun étant attribué à un bucket spécifique. Cela garantit l'orthogonalité des valeurs de bitmap entre les différents buckets.
Définissez la cardinalité de hid à au moins cinq fois le nombre de buckets. Par exemple, pour 3 buckets, hid doit comporter au minimum 15 valeurs distinctes.
Étape 2 : Importation des données
Utilisez une instruction LOAD LABEL pour charger les données. L'expression ceil(tmp_user_id/500) calcule la valeur hid pour chaque ligne, tandis que to_bitmap(tmp_user_id) convertit l'entier brut en une entrée bitmap.
LOAD LABEL user_tag_bitmap_test
(
DATA INFILE('hdfs://abc')
INTO TABLE user_tag_bitmap
COLUMNS TERMINATED BY ','
(tmp_tag, tmp_user_id)
SET (
tag = tmp_tag,
hid = ceil(tmp_user_id/500),
user_id = to_bitmap(tmp_user_id)
)
)
Le diviseur 500 n'est pas fixe. Ajustez-le selon la plage prévue des ID utilisateur et le nombre cible de valeurs hid distinctes souhaité.
Les données source se présentent sous la forme de deux colonnes séparées par des virgules : le tag et l'ID utilisateur.
11111111,1
11111112,2
11111113,3
11111114,4
Lors de l'importation, SelectDB attribue la même valeur hid aux ID utilisateur compris dans la plage [1, 5000000) et les place dans le même bucket. Les valeurs de bitmap restent orthogonales d'un bucket à l'autre, ce qui réduit le coût de calcul des opérations d'intersection et d'union.
Étape 3 : Interrogation avec les fonctions de bitmap orthogonal
Une fois les données importées, utilisez les fonctions de bitmap orthogonal décrites dans la section suivante. Pour consulter la liste complète des fonctions bitmap standard, reportez-vous à la référence SQL.
Fonctions de bitmap orthogonal
Les cinq fonctions suivantes prennent en charge les requêtes bitmap dans des contextes orthogonaux. Celles qui renvoient un comptage remplacent directement les modèles COUNT(DISTINCT ...) correspondants, tout en s'exécutant de manière distribuée.
| Fonction | Retourne | Cas d'usage |
|---|---|---|
bitmap_orthogonal_intersect |
Bitmap | Calcul du bitmap d'intersection entre plusieurs tags |
orthogonal_bitmap_intersect_count |
Count | Dénombrement des utilisateurs à l'intersection de plusieurs tags |
orthogonal_bitmap_union_count |
Count | Comptage total des utilisateurs distincts sur l'ensemble des tags |
orthogonal_bitmap_expr_calculate |
Bitmap | Évaluation d'expressions ensemblistes complexes (AND, OR, NOT) |
orthogonal_bitmap_expr_calculate_count |
Count | Dénombrement des résultats d'expressions ensemblistes complexes |
Les fonctions de bitmap orthogonal ne s'appliquent pas aux tables partitionnées. Comme les partitions sont orthogonales entre elles, l'orthogonalité des données n'est pas garantie d'une partition à l'autre, ce qui rendrait les résultats peu fiables.
bitmap_orthogonal_intersect
Calcule l'intersection des valeurs de bitmap pour les valeurs de filtre spécifiées et renvoie le résultat sous forme de bitmap.
Syntaxe
bitmap_orthogonal_intersect(bitmap_column, column_to_filter, filter_values)
Paramètres
| Paramètre | Description |
|---|---|
bitmap_column |
Colonne bitmap à agréger. |
column_to_filter |
Colonne de dimension utilisée pour le filtrage. |
filter_values |
Liste de longueur variable de valeurs servant à filtrer la colonne de dimension. |
Exemple
SELECT BITMAP_COUNT(bitmap_orthogonal_intersect(user_id, tag, 13080800, 11110200))
FROM user_tag_bitmap
WHERE tag IN (13080800, 11110200);
Équivalent à :
-- Returns the count of users who appear in ALL specified tags
SELECT COUNT(DISTINCT user_id)
FROM user_tag_bitmap
WHERE tag IN (13080800, 11110200)
AND <user_id appears in every tag>;
Lors de l'exécution, l'étape 1 filtre les lignes selon les tags spécifiés, puis calcule l'intersection des bitmaps pour tous les tags correspondants au sein de chaque bucket. L'étape 2 fusionne itérativement les bitmaps d'intersection de chaque bucket pour obtenir le résultat final.
orthogonal_bitmap_intersect_count
Calcule l'intersection des valeurs de bitmap et renvoie directement le décompte. La sémantique correspond à celle de intersect_count, mais l'exécution est distribuée entre les buckets.La syntaxe est identique à celle de la fonction intersect_count, mais l'implémentation diffère.La syntaxe est identique à celle de la fonction bitmap_union_count, mais l'implémentation diffère.
Syntaxe
orthogonal_bitmap_intersect_count(bitmap_column, column_to_filter, filter_values)
Paramètres
| Paramètre | Description |
|---|---|
bitmap_column |
Colonne bitmap à agréger. |
column_to_filter |
Colonne de dimension utilisée pour le filtrage. |
filter_values |
Liste de longueur variable de valeurs servant à filtrer la colonne de dimension. |
Exemple
SELECT orthogonal_bitmap_intersect_count(user_id, tag, 1150000, 1150001, 390006)
FROM user_tag_bitmap
WHERE tag IN (1150000, 1150001, 390006);
Durant l'exécution, l'étape 1 applique le filtre sur les tags spécifiés, calcule l'intersection des bitmaps pour tous les tags correspondants, puis effectue le décompte par bucket. L'étape 2 additionne tous les comptes partiels pour produire le total final.
orthogonal_bitmap_union_count
Calcule l'union des valeurs de bitmap et renvoie le décompte. Bien que la sémantique soit identique à BITMAP_UNION_COUNT, l'exécution est ici distribuée entre les buckets.
Syntaxe
orthogonal_bitmap_union_count(bitmap_column)
Paramètres
| Paramètre | Description |
|---|---|
bitmap_column |
Colonne bitmap dont les valeurs font l'objet d'une union et d'un comptage. |
Exemple
SELECT orthogonal_bitmap_union_count(user_id)
FROM user_tag_bitmap
WHERE tag IN (1150000, 1150001, 390006);
Équivalent à :
SELECT COUNT(DISTINCT user_id)
FROM user_tag_bitmap
WHERE tag IN (1150000, 1150001, 390006);
Pendant l'exécution, l'étape 1 réalise l'union des bitmaps par bucket et compte le résultat obtenu. L'étape 2 somme ensuite l'ensemble des comptes partiels pour fournir le total définitif.
orthogonal_bitmap_expr_calculate
Évalue une expression ensembliste sur des colonnes bitmap et retourne le résultat sous forme de bitmap. Privilégiez cette fonction lorsque vous avez besoin du bitmap lui-même pour un traitement ultérieur, plutôt que d'un simple décompte.
Syntaxe
orthogonal_bitmap_expr_calculate(bitmap_column, filter_column, input_string)
Paramètres
| Paramètre | Description |
|---|---|
bitmap_column |
Colonne bitmap à agréger. |
filter_column |
Colonne de dimension utilisée pour le filtrage (colonne clé pour le calcul). |
input_string |
Chaîne d'expression ensembliste appliquée aux valeurs de la colonne clé. |
input_string prend en charge les opérateurs suivants :
| Opérateur | Opération | |
|---|---|---|
& |
Intersection | |
` |
` |
Union |
- |
Différence | |
^ |
XOR exclusif | |
\ |
Caractère d'échappement |
Exemple
SELECT orthogonal_bitmap_expr_calculate(
user_id,
tag,
'(833736|999777)&(1308083|231207)&(1000|20000-30000)'
)
FROM user_tag_bitmap
WHERE tag IN (833736, 999777, 130808, 231207, 1000, 20000, 30000);
Au cours de l'exécution, l'étape 1 analyse input_string pour déterminer le filtre de tags, filtre les données, puis applique l'expression bitmap aux lignes filtrées de chaque bucket. L'étape 2 calcule l'union de tous les résultats bitmap par bucket et renvoie le bitmap final.
orthogonal_bitmap_expr_calculate_count
Évalue une expression ensembliste sur des colonnes bitmap et renvoie le décompte. La syntaxe et les paramètres sont strictement identiques à ceux de orthogonal_bitmap_expr_calculate.
Syntaxe
orthogonal_bitmap_expr_calculate_count(bitmap_column, filter_column, input_string)
Paramètres
| Paramètre | Description | |
|---|---|---|
bitmap_column |
Colonne bitmap à agréger. | |
filter_column |
Colonne de dimension utilisée pour le filtrage (colonne clé pour le calcul). | |
input_string |
Chaîne d'expression ensembliste appliquée aux valeurs de la colonne clé. Prend en charge &, ` |
`, |
Exemple
SELECT orthogonal_bitmap_expr_calculate_count(
user_id,
tag,
'(833736|999777)&(1308083|231207)&(1000|20000-30000)'
)
FROM user_tag_bitmap
WHERE tag IN (833736, 999777, 130808, 231207, 1000, 20000, 30000);
Lors de l'exécution, l'étape 1 analyse input_string, filtre les données, applique l'expression bitmap et compte le résultat pour chaque bucket. L'étape 2 calcule l'union de tous les résultats bitmap par bucket et retourne le décompte final.
Étapes suivantes
Référence SQL — liste complète des fonctions bitmap dans la section dédiée