Interrogation de données protégées par la confidentialité différentielle¶
Cette rubrique aide un analyste à exécuter des requêtes sur des données protégées par la confidentialité différentielle (c’est-à-dire des tables et des vues protégées par la confidentialité) et à comprendre et ajuster les résultats renvoyés par les requêtes.
Pour exécuter une requête sur une table protégée par la confidentialité, un utilisateur doit disposer du privilège SELECT sur la table.
Limitations
La confidentialité différentielle prend en charge un sous-ensemble de types de données, d’opérateurs, de syntaxe de requête et de fonctions Snowflake. Pour connaître la liste des fonctions SQL que vous pouvez utiliser dans une requête, voir Référence SQL de confidentialité différentielle.
Les requêtes sur les tables protégées par la confidentialité prennent plus de temps car Snowflake doit exécuter des calculs supplémentaires pour déterminer la quantité de bruit à ajouter. Pour les requêtes de base, cette latence est d’au moins 7 secondes. Les requêtes complexes, telles que les suivantes, peuvent prendre beaucoup plus de temps :
Requêtes avec de nombreuses jointures et sous-requêtes.
Requêtes qui génèrent plusieurs lignes dans le résultat, par exemple, lors de l’utilisation de clauses GROUP BY qui donnent lieu à des centaines ou des milliers de groupes.
Principes fondamentaux des requêtes¶
Cette section décrit les composants de base d’une requête qui réussira lorsqu’elle sera exécutée sur une table protégée par la confidentialité. Cela comprend :
Agrégation de données¶
Toutes les requêtes sur une table protégée par la confidentialité doivent regrouper les résultats plutôt que récupérer des enregistrements individuels. Toutes les parties d’une requête n’ont pas besoin d’utiliser une fonction d’agrégation tant que le résultat final est agrégé.
À l’exception d’une fonction COUNT, une requête ne peut pas agréger une colonne à moins que la colonne n’ait un domaine de confidentialité.
Pour connaître la liste des agrégations prises en charge, voir Fonctions d’agrégation.
Utilisation des jointures¶
Les sections suivantes fournissent des indications pour l’utilisation des jointures dans une requête différentiellement privée :
Pour en savoir plus concernant les implications de la jonction de deux tables protégées par la confidentialité sur les domaines de confidentialité, voir Domaines et jointures de confidentialité.
Opérateurs de jointure¶
Chaque jointure doit être une jointure équivalente qui utilise un seul opérateur. Par exemple, t1.c1 == t2.c1
est pris en charge, mais col1 > col2
et col1 + 10 = col2
ne le sont pas. Les jointures inconditionnelles ne sont pas prises en charge.
Les jointures doivent utiliser l’opérateur JOIN. La syntaxe WHERE pour les jointures n’est pas prise en charge. Pour plus d’informations sur la syntaxe de jointure, voir Mise en œuvre des jointures.
Jointures prises en charge¶
Les jointures d’une requête différentiellement privée doivent être l’une des suivantes :
INNER
{ LEFT | RIGHT | FULL } OUTER
NATURAL
Les deux côtés de la jointure doivent avoir le même modèle de requête. Par exemple, les jointures suivantes sont prises en charge :
Les deux côtés sont des identificateurs
SELECT COUNT(*) FROM t1 INNER JOIN t2 ON t1.a=t2.a;
Les deux côtés sont des sous-requêtes
SELECT COUNT(*) FROM (SELECT a, SUM(b) FROM t1 GROUP BY a) AS g1 INNER JOIN (SELECT * FROM t2) AS g2 ON g1.a=g2.a;
La jonction d’un identificateur avec une sous-requête n’est actuellement pas prise en charge.
Pour plus d’informations sur la syntaxe de requête prise en charge liée aux jointures, voir Syntaxe de requête.
Utilisation des clés d’entité dans les jointures¶
Lorsque vous travaillez avec des tables protégées par une confidentialité au niveau de l’entité, vous pouvez minimiser la quantité de bruit en incluant la colonne de clé d’entité dans le cadre de la clé de jointure, en particulier si elle ne modifie pas sémantiquement la requête.
Par exemple, considérons les tables suivantes où l’entité correspond aux clients :
Table
Description
customers
Répertoire des clients, où chaque ligne correspond à un client et comporte un
customer_id
.
transactions
Transactions clients, où chaque client peut avoir plusieurs transactions.
transaction_lines
Articles uniques qui ont été achetés lors d’une transaction. Il peut y avoir plusieurs lignes dans une seule transaction.
Si les meilleures pratiques sont suivies, le fournisseur de données a structuré les données de sorte que chacune de ces tables possède la clé d’entité customer_id
. Pour ce schéma de données, chaque ligne de transaction ne peut appartenir qu’à une seule transaction et chaque transaction ne peut appartenir qu’à un seul client. Cette relation n’est pas évidente à partir des données elles-mêmes ; de ce fait, sans informations supplémentaires, la quantité de bruit ajoutée pour la confidentialité différentielle sera plus élevée que nécessaire.
Vous pouvez minimiser la quantité de bruit en incluant la clé d’entité customer_id
dans le cadre de la clé de jointure, même si elle est redondante. Par exemple, joindre la table transactions
avec transaction_lines
nécessite, en général, uniquement la clé de jointure transaction_id
. Cependant, joindre des tables sur transaction_id
et customer_id
entraînera une diminution du bruit.
Types de données et domaines de confidentialité¶
Lors de la jonction de deux tables, les types de données des colonnes clés de jointure de chaque côté doivent être identiques. Pour la confidentialité différentielle, le type de données d’une colonne indique si elle possède ou non un domaine de confidentialité.
Par exemple, si vous aviez une table protégée par la confidentialité transactions
et une table non protégée product_lookup
, et que vous vouliez les joindre sur product_id
, la colonne product_id
des deux tables doit être du même type de données (par exemple, une chaîne) et doit chacune avoir un domaine de confidentialité.
Pour répondre à cette exigence, l’administrateur de l’analyste devra peut-être définir un domaine de confidentialité tout comme le fournisseur de données le définit. Pour plus d’informations sur la façon de définir un domaine de confidentialité pour une table, voir Définition d’un domaine de confidentialité.
Condition d’unicité¶
Les jointures peuvent potentiellement dupliquer des lignes de données, ce qui peut entraîner une quantité illimitée de bruit ajouté au résultat d’une requête. Pour garantir que les données protégées par la confidentialité ne sont pas dupliquées dans une jointure, la clé de jointure (c’est-à-dire les colonnes sur lesquelles les tables sont jointes) des tables protégées par la confidentialité doit correspondre à un seul enregistrement de l’autre table. Cela signifie que lors de la jointure avec une table protégée par la confidentialité, la clé de jointure du côté opposé doit être dédupliquée.
Important
L’exigence d’unicité pour les jointures ne s’applique pas toujours aux requêtes sur les tables protégées par confidentialité au niveau de l’entité. Pour la confidentialité au niveau de l’entité, les requêtes doivent être dédupliquées sur la clé d’entité avant l’agrégation. Tant que cela est effectué après une jointure mais avant l’agrégation, la jointure n’a pas besoin d’être sur des données dédupliquées. Pour plus d’informations sur la manière de se conformer à ces exigences, voir Interrogation des données protégées par la confidentialité au niveau de l’entité.
Pour satisfaire à l’exigence d’unicité des jointures, la requête peut utiliser GROUP BY sur un sous-ensemble des colonnes de jointure pour regrouper les lignes en double en un seul résultat.
Par exemple, supposons que la table patients
est protégée par la confidentialité différentielle, contrairement à la table geo_lookup
. L’analyste souhaite joindre ces deux tables sur zip_code
afin qu’ils puissent filtrer la table patients
sur State
. Afin de garantir que les enregistrements dans la table patients
protégée par la confidentialité ne sont pas dupliqués, la requête doit dédupliquer la table zip_code
sur la clé de jointure. Cela doit être fait explicitement même si la table geo_lookup
est déjà unique sur zip_code
. Cela garantit que Snowflake peut correctement prendre en compte la confidentialité.
SELECT COUNT(*)
FROM patients
LEFT JOIN (SELECT zip_code, ANY_VALUE(state) AS residence_state
FROM geo_lookup
GROUP BY zip_code)
USING zip_code
WHERE birth_state = residence_state;
df_patients = session.table("patients")
df_geo = session.table("geo_lookup")
df_geo_deduped = df_geo.group_by("zip_code").agg(f.any_value("state").as_("state"))
df_patients.join(df_geo_deduped, on="zip_code", join_type="left")\
.where(f.col("birth_state") == f.col("residence_state")).select(f.count("*"))
Interrogation des données protégées par la confidentialité au niveau de l’entité¶
La plupart des fournisseurs de données utilisent une clé d’entité pour mettre en œuvre la confidentialité au niveau de l’entité lors de la configuration de la confidentialité différentielle. Lorsqu’une table est protégée par la confidentialité au niveau de l’entité, Snowflake n’autorise pas les agrégats sur les champs s’il peut y avoir un nombre illimité de lignes par entité. Cela signifie que les requêtes doivent répondre aux exigences suivantes :
À un moment donné de la requête, la table protégée par la confidentialité doit être dédupliquée sur la clé d’entité. Les opérations qui peuvent être utilisées pour dédupliquer les données sont :
COUNT ( DISTINCT < colonne_clé_entité> )
GROUP BY <colonne_clé_entité>
UNION (mais pas UNION ALL) lorsque seule la clé d’entité est projetée.
Si une jointure utilise une clé de jointure autre que la colonne de clé d’entité, cette jointure ne peut pas se produire entre la déduplication et la clause finale SELECT avec agrégation.
Note
Si le fournisseur de données a implémenté la confidentialité au niveau des lignes, l’exigence de déduplication pour les jointures est différente. Pour plus d’informations sur ces exigences, voir Condition d’unicité.
Pour illustrer les exigences en matière de confidentialité au niveau de l’entité, supposons que vous ayez une table protégée par la confidentialité patients
avec la colonne de clé d’entité patient_id
. Vous avez également une table non sensible et non protégée geo_lookup
. Les exemples suivants montrent une requête qui échoue suivie d’une version réécrite qui réussit.
- Exemple : déduplication
La requête suivante échoue car elle ne répond pas à l’exigence de déduplication. Même si la table
patients
pourrait déjà être unique surpatient_id
, la requête échoue car elle ne déduplique pas explicitement.SELECT COUNT(*) FROM patients WHERE insurance_type = 'Commercial';
Pour réécrire la requête afin qu’elle réussisse, incluez un nombre distinct sur la colonne de clé d’entité afin de dédupliquer explicitement la clé d’entité. Par exemple :
SELECT COUNT(DISTINCT patient_id) FROM patients WHERE insurance_type = 'Commercial';
- Exemple : emplacement de la jointure
La requête suivante échoue même si elle utilise une clause GROUP BY visant à répondre à l’exigence de déduplication. L’opération échoue car la table est jointe à une autre table à l’aide d’une colonne qui n’est pas la colonne de clé d’entité.
SELECT AVG(bmi) FROM (SELECT patient_id, ANY_VALUE(zip_code) AS zip_code FROM patients GROUP BY patient_id) AS p JOIN geo_lookup AS g ON p.zip_code = g.zip_code WHERE state='CA';
Pour réécrire la requête afin qu’elle réussisse, utilisez la clause GROUP BY après la jointure. La jointure ne peut pas se produire entre la déduplication et la clause SELECT avec agrégation.
SELECT AVG(bmi) FROM (SELECT patient_id, ANY_VALUE(bmi) as bmi, ANY_VALUE(state) as state FROM patients AS p JOIN geo_lookup AS g ON p.zip_code = g.zip_code GROUP BY patient_id) WHERE state='CA';
Exécution de requêtes au niveau des transactions¶
L’exigence de déduplication pour la confidentialité différentielle au niveau de l’entité ne vous empêche pas d’exécuter des requêtes au niveau des transactions. Cependant, vous devez d’abord regrouper les données au niveau de l’entité, puis les agréger sur ces groupes.
Par exemple, supposons que vous ayez une table doctor_visits
et que le fournisseur de données a défini une clé d’entité patient_id
pour mettre en œuvre la confidentialité au niveau de l’entité. Une requête au niveau de la transaction pourrait être : « Combien de visites chez le médecin n’étaient pas pour un suivi régulier ? » Voici un exemple de la manière d’écrire cette requête :
SELECT SUM(num_visits)
FROM (SELECT SUM((visit_reason<>'Regular checkup')::INT) AS num_visits
WHERE visit_reason IS NOT NULL
GROUP BY patient_id)
WHERE num_visits > 0 AND num_visits < 20;
Les sous-requêtes se regroupent par patient_id
pour dédupliquer les données. La colonne agrégée num_visits
capture le nombre de visites par patient qui n’étaient pas pour un contrôle régulier. La requête s’agrège ensuite à nouveau sur cette colonne par patient pour obtenir le nombre total de visites. Notez que la clause WHERE sur la requête externe est requise pour spécifier un domaine de confidentialité sur les données.
Note
Bien que cela ne soit pas une exigence, une bonne pratique lors de la jointure de tables protégées par la confidentialité différentielle au niveau de l’entité consiste à inclure la colonne de clé d’entité dans le cadre de la clé de jointure (si cela ne modifie pas sémantiquement la requête). Pour plus d’informations, voir Utilisation des clés d’entité dans les jointures.
Comprendre les résultats de la requête¶
Les requêtes sur une table protégée par la confidentialité ne renvoient pas la valeur exacte d’une agrégation. La confidentialité différentielle introduit du bruit dans le résultat afin qu’il devienne une approximation de la valeur réelle. La valeur renvoyée diffère suffisamment de la valeur réelle pour masquer si les données d’un individu sont incluses dans l’agrégation. Cela s’applique à toutes les requêtes, à l’exception d’une requête qui renvoie le nombre total de lignes dans la table protégée par la confidentialité, par exemple SELECT COUNT(*) FROM t
.
Un analyste doit être en mesure de déterminer si le bruit introduit dans le résultat a diminué l’utilité de la requête. Snowflake utilise un intervalle de bruit pour aider les analystes à interpréter les résultats. Un intervalle de bruit est un intervalle mathématique fermé qui, dans la plupart des cas, inclut la valeur réelle de l’agrégation. Il y a 95 % de chances que le résultat réel d’une requête se situe dans l’intervalle de bruit.
L’ajout des fonctions suivantes à une requête permet à l’analyste d’utiliser l’intervalle de bruit pour prendre des décisions sur l’utilité d’une requête :
DP_INTERVAL_LOW — Renvoie la limite inférieure de l’intervalle de bruit. La valeur réelle est très probablement égale ou supérieure à ce nombre.
DP_INTERVAL_HIGH — Renvoie la limite supérieure de l’intervalle de bruit. La valeur réelle est très probablement égale ou inférieure à ce nombre.
Pour utiliser ces fonctions, transmettez l’alias d’une colonne agrégée dans la requête principale. Par exemple, la requête suivante renvoie la somme de la colonne num_claims
avec l’intervalle de bruit pour cette agrégation :
SELECT SUM(num_claims) AS sum_claims,
DP_INTERVAL_LOW(sum_claims),
DP_INTERVAL_HIGH(sum_claims)
FROM t1;
dp_interval_low = f.function('dp_interval_low')
dp_interval_high = f.function('dp_interval_high')
dpdf_cohort.group_by().agg(f.sum("num_claims").alias("sum_claims"),
dp_interval_low("sum_claims"),
dp_interval_low("sum_claims")
).show()
Le résultat pourrait être :
+--------------+--------------------------------+----------------------------------+
| sum_claims | dp_interval_low("sum_claims") | dp_interval_high("sum_claims") |
|--------------+--------------------------------+----------------------------------+
| 50 | 35 | 75 |
+--------------+--------------------------------+----------------------------------+
Dans ce cas, la valeur de retour est une somme de 50. Mais l’analyste a également déterminé avec 95 % de certitude que la valeur réelle de l’agrégation se situe entre 35 et 75.
Astuce
Pour plus d’informations sur les techniques qui peuvent potentiellement réduire le bruit dans les résultats, voir
Suivi des dépenses du budget de confidentialité¶
Vous pouvez utiliser la fonction ESTIMATE_REMAINING_DP_AGGREGATES permettant d’estimer le nombre de requêtes supplémentaires que vous pouvez exécuter dans la fenêtre budgétaire actuelle (c’est-à-dire jusqu’à ce que la perte de confidentialité cumulée soit réinitialisée à 0). L’estimation est basée sur le nombre d’agrégats et non sur les requêtes. Par exemple, la requête SELECT SUM(age), COUNT(age) FROM T
contient deux fonctions d’agrégation : SUM(age)
et COUNT(age)
.
Lors de l’exécution de la fonction ESTIMATE_REMAINING_DP_AGGREGATES, assurez-vous d’utiliser les conditions exactes que vous utilisez pour exécuter les requêtes, par exemple le même utilisateur, rôle et compte.
Si vous exécutez une requête qui utilise plusieurs tables, vous devez exécuter ESTIMATE_REMAINING_DP_AGGREGATES une fois par table, puis utilisez la valeur la plus basse NUMBER_OF_REMAINING_DP_AGGREGATES
comme plafond d’utilisation estimé.
L’exemple suivant montre comment une série de requêtes affecte la part de la limite du budget de confidentialité dépensée (c’est-à-dire la perte de confidentialité cumulée des requêtes) et le nombre estimé d’agrégats restants.
1. Contrôle initial
Regardons les chiffres du budget de confidentialité sur la table my_table
. Vous n’avez jamais exécuté de requêtes sur cette table.
SELECT * FROM TABLE(SNOWFLAKE.DATA_PRIVACY.ESTIMATE_REMAINING_DP_AGGREGATES('my_table'));
Aucun budget utilisé jusqu’à présent :
+-----------------------------------+--------------+---------------+--------------+
| NUMBER_OF_REMAINING_DP_AGGREGATES | BUDGET_LIMIT | BUDGET_WINDOW | BUDGET_SPENT |
|-----------------------------------+--------------+---------------+--------------|
| 996 | 233 | WEEKLY | 0.0 |
+-----------------------------------+--------------+---------------+--------------+
2. Exécuter une requête
Exécutons une requête avec une fonction d’agrégation et vérifions à nouveau nos chiffres :
SELECT SUM(salary) FROM my_table;
-- results omitted ...
SELECT * FROM TABLE(SNOWFLAKE.DATA_PRIVACY.ESTIMATE_REMAINING_DP_AGGREGATES('my_table'));
L’estimation du nombre total d’appels agrégés restants a diminué d’un et la perte cumulée de confidentialité (budget dépensé) a augmenté.
+-----------------------------------+--------------+---------------+--------------+
| NUMBER_OF_REMAINING_DP_AGGREGATES | BUDGET_LIMIT | BUDGET_WINDOW | BUDGET_SPENT |
|-----------------------------------+--------------+---------------+--------------|
| 995 | 233 | WEEKLY | 0.6 |
+-----------------------------------+--------------+---------------+--------------+
3. Exécutez une autre requête avec deux fonctions d’agrégation
SELECT SUM(age), COUNT(age) FROM my_table GROUP BY STATE;
-- results omitted ...
SELECT * FROM TABLE(SNOWFLAKE.DATA_PRIVACY.ESTIMATE_REMAINING_DP_AGGREGATES('my_table'));
Le nombre estimé de requêtes restantes a diminué de deux. N’oubliez pas qu’il s’agit d’une estimation.
+-----------------------------------+--------------+---------------+--------------+
| NUMBER_OF_REMAINING_DP_AGGREGATES | BUDGET_LIMIT | BUDGET_WINDOW | BUDGET_SPENT |
|-----------------------------------+--------------+---------------+--------------|
| 993 | 233 | WEEKLY | 1.8 |
+-----------------------------------+--------------+---------------+--------------+
4. Réexécuter une requête
Réexécutons une requête précédente pour montrer que le budget de confidentialité est toujours facturé, même sur des requêtes identiques. Une requête en double entraîne la même perte de confidentialité à chaque exécution (c’est-à-dire qu’elle dépense le même montant de budget de confidentialité).
SELECT SUM(age), COUNT(age) FROM T GROUP BY STATE;
-- results omitted ...
SELECT * FROM TABLE(SNOWFLAKE.DATA_PRIVACY.ESTIMATE_REMAINING_DP_AGGREGATES('my_table'));
Mêmes frais pour la requête qu’avant : 1,2 unité de perte de confidentialité.
+-----------------------------------+--------------+---------------+--------------+
| NUMBER_OF_REMAINING_DP_AGGREGATES | BUDGET_LIMIT | BUDGET_WINDOW | BUDGET_SPENT |
|-----------------------------------+--------------+---------------+--------------|
| 991 | 233 | WEEKLY | 3.0 |
+-----------------------------------+--------------+---------------+--------------+