RGPD, pseudonimització i deduplicació a escala
Contingut d'ampliació
Aquesta pàgina amplia la Qualitat de dades d'aquest bloc amb continguts que no formen part del repartiment oficial de les 99 hores del currículum. El professorat el pot tractar com a activitat de reforç o ampliació.
El repte del dret a l'oblit en un Data Lake
El RGPD (Reglament General de Protecció de Dades) obliga a eliminar les dades personals d'una persona quan aquesta ho sol·licita. En un sistema Big Data distribuït això és tècnicament complex: les dades d'un client poden estar replicades en múltiples nodes, en un log immutable (Kafka), en múltiples versions per time travel (Delta Lake) i en backups.
Esborrat RGPD amb Delta Lake
from delta.tables import DeltaTable
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.appName("GDPR_Delete") \
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
.getOrCreate()
deltaTable = DeltaTable.forPath(spark, "/data/delta/vendes")
# Eliminacio de les files (operacio ACID)
deltaTable.delete("id_client = 'C045'")
# El time travel encara permet accedir a les dades anteriors!
# Per a un esborrat RGPD complet, cal executar VACUUM
deltaTable.vacuum(retentionHours=0) # Eliminacio permanent
VACUUM 0 hores en producció
vacuum(retentionHours=0) elimina permanentment tots els fitxers que no formen part de la versió actual, inclosos els que permetrien el time travel. Cal desactivar prèviament la comprovació de seguretat de Delta Lake (spark.databricks.delta.retentionDurationCheck.enabled = false) i usar-ho només per a peticions RGPD documentades.
Pseudonimització en streaming
from pyspark.sql import functions as F
import hashlib
SALT = "iabd2026-salt-secret"
@F.udf(returnType="string")
def pseudonimitzar(valor):
if valor is None:
return None
return hashlib.sha256(f"{SALT}:{valor}".encode()).hexdigest()[:16]
df_pseudonim = df_stream \
.withColumn("email_hash", pseudonimitzar(F.col("email"))) \
.drop("email")
Deduplicació a escala
Bloom Filters
Un Bloom Filter és una estructura de dades probabilística que respon "ha aparegut mai aquest valor?" amb molt poca memòria. Accepta falsos positius (pot dir "sí" quan la resposta és "no") però mai falsos negatius. Cas d'ús habitual: en un pipeline que rep milions d'events, descartar ràpidament els que ja s'han processat.
df_nous_ids = df_stream.select("id_event") \
.filter(~F.expr("might_contain(bloom_filter, id_event)"))
MinHash LSH: deduplicació de text
Locality-Sensitive Hashing (LSH) permet trobar parells de registres "similars" en un dataset gran sense comparar-los tots entre si. Especialment útil per deduplicar noms de clients o adreces ("Joan Garcia" ≈ "J. Garcia"; "Carrer Major 5" ≈ "C/ Major, 5").
from pyspark.ml.feature import MinHashLSH, Tokenizer, HashingTF
tokenizer = Tokenizer(inputCol="nom_client", outputCol="tokens")
hashingTF = HashingTF(inputCol="tokens", outputCol="features", numFeatures=1000)
minhash = MinHashLSH(inputCol="features", outputCol="hashes", numHashTables=5)
df_features = hashingTF.transform(tokenizer.transform(df_clients))
model = minhash.fit(df_features)
df_transformed = model.transform(df_features)
similars = model.approxSimilarityJoin(
df_transformed, df_transformed, threshold=0.3, distCol="distancia_jaccard"
).filter("datasetA.id_client < datasetB.id_client")
Schema Registry: validar el format en temps real
Quan múltiples equips produeixen missatges a Kafka, un missatge mal format pot trencar el pipeline del consumidor. El Schema Registry de Confluent ho evita: valida l'esquema Avro abans que el missatge s'accepti.
from confluent_kafka.schema_registry import SchemaRegistryClient
from confluent_kafka.schema_registry.avro import AvroSerializer
schema_registry_client = SchemaRegistryClient({'url': 'http://schema-registry:8081'})
schema_str = """
{
"type": "record", "name": "Venda", "namespace": "cat.sapalomera.iabd",
"fields": [
{"name": "id_venda", "type": "string"},
{"name": "preu", "type": {"type": "bytes", "logicalType": "decimal", "precision": 10, "scale": 2}}
]
}
"""
avro_serializer = AvroSerializer(schema_registry_client, schema_str, lambda obj, ctx: obj)
Si el productor envia un missatge que no compleix l'esquema registrat, el Schema Registry en rebutja la publicació abans que arribi a cap consumidor.
Miniactivitat — AC5074/05/06
Explica amb les teves paraules per què vacuum(retentionHours=0) és necessari per complir el RGPD però perillós en producció, i quina precaució caldria prendre abans d'executar-lo sobre una taula Delta Lake real.
Bloc 5 | Mòdul M5074 Sistemes de Big Data | Institut Sa Palomera (Blanes) | Curs CEIABD 2026-2027