La plataforma de dades d'AlpinaShop funciona. Les comandes entren soles, Dataflow les neteja, Spark calcula la cistella mitjana, Data Fusion porta el fitxer del transportista i Workflows ho coordina tot cada nit amb la seva comprovació de qualitat. Tècnicament és un èxit.
I tanmateix, tres coses continuen sense funcionar.
Ningú no sap què hi ha. A alpinashop_analitica hi ha setze taules, sis vistes, dues vistes materialitzades i una anomenada pedidos_evento que ningú no recorda per què existeix. Quan algú de màrqueting pregunta "on és la dada de conversió?", la resposta és "pregunta-ho a la Lucía". I si la Lucía se'n va de vacances, la resposta és "no ho sé".
Ningú no sap què significa. La columna ventas_eur apareix en quatre taules. Inclou IVA? Descompta devolucions? Compta les comandes cancel·lades? La Marta creu que sí, la Lucía creu que no, i l'informe que va a direcció fa servir una de les dues definicions sense dir quina. Ningú no ho ha escrit mai.
Ningú no sap qui pot veure què. A 04-01 es va protegir email_cliente amb una etiqueta de política. Però des de llavors han passat sis lliçons: Dataflow escriu a pedidos_streaming, la subscripció de Pub/Sub bolca a pedidos_evento, l'arxiu d'esdeveniments va a Cloud Storage i Data Fusion va portar el CSV del transportista amb el nom del destinatari. Hi ha correus de clients en algun d'aquests llocs sense protecció? Ningú no ho ha comprovat.
I hi ha una quarta cosa que falta, la que direcció porta demanant des del mòdul 3: el tauler de control. Les dades són impecables i ningú no les veu.
En aquesta lliçó tanquem el mòdul resolent les quatre. Veuràs què és el govern de les dades i per què una pime el necessita tant com una multinacional, organitzaràs i documentaràs la plataforma amb Dataplex, definiràs regles de qualitat que es comproven soles, descobriràs i desidentificaràs les dades personals amb Sensitive Data Protection, i construiràs per fi a Looker Studio el tauler de control d'AlpinaShop, evitant l'error de permisos que converteix un informe compartit en una fuga de dades.
Contingut
- Què és el govern de les dades i per què també en una pime
- Dataplex: llacs, zones i actius
- El catàleg universal i la cerca de dades
- Etiquetes i plantilles: documentar
alpinashop_analitica - Perfils de dades: què hi ha realment a les teves taules
- Regles de qualitat i què fer quan fallen
- Llinatge automàtic d'extrem a extrem
- Sensitive Data Protection: descobrir on són les dades personals
- Desidentificació: emmascarament i tokenització
- Looker Studio: connectar i modelar
- El tauler de control de direcció d'AlpinaShop
- Cost i rendiment: extracció, consulta en directe i BI Engine
- Permisos: l'error clàssic de les credencials del propietari
- Looker i LookML: quan justifica el seu preu
- Checklist d'una plataforma de dades sana
- Què és el govern de les dades i per què també en una pime
El govern de les dades és el conjunt de pràctiques que garanteixen que les dades d'una organització siguin trobables, comprensibles, fiables, segures i gestionades al llarg de la seva vida. Cinc potes:
| Pota | Pregunta que respon | Eina a Google Cloud |
|---|---|---|
| Catàleg | Quines dades tenim i on són? | Dataplex Universal Catalog |
| Llinatge | D'on ve aquesta dada i què en depèn? | Dataplex Lineage |
| Qualitat | Em puc refiar d'aquest número? | Dataplex Data Quality |
| Classificació | Quines dades són sensibles i qui les veu? | Sensitive Data Protection + etiquetes de política |
| Cicle de vida | Quant de temps ho guardem i quan s'esborra? | Polítiques de retenció, TTL, cicle de vida de Cloud Storage |
L'objecció habitual és que això és cosa de bancs i multinacionals. És exactament al revés, i val la pena argumentar-ho:
El RGPD no distingeix per mida. Una empresa de 40 persones que tracta dades de clients europeus té les mateixes obligacions que una de 40.000: saber quines dades personals té, on són, amb quina base legal, quant de temps les conserva, i poder atendre un dret de supressió. Si no se sap on és el correu d'un client, no es pot esborrar quan ho demani.
El cost del desconeixement és proporcionalment més gran. En una empresa gran hi ha redundància: si algú se'n va, un altre ho sap. A AlpinaShop, si la Lucía se'n va, el coneixement de la plataforma se'n va amb ella. La documentació no és burocràcia, és continuïtat.
Els errors arriben abans a direcció. Amb tres persones i un tauler de control, una dada mal calculada no passa per cap filtre intermedi. Va directa a una decisió.
I el moment correcte és ara. Governar setze taules és una feina d'una tarda. Governar-ne dues-centes, després de tres anys de creixement desordenat, és un projecte de mesos. El deute de govern s'acumula amb interessos.
- Dataplex: llacs, zones i actius
Dataplex és la capa de gestió unificada de dades de Google Cloud. La seva idea central: les dades d'una organització estan repartides entre BigQuery, Cloud Storage i altres sistemes, i cal una capa lògica per sobre que les organitzi, les descrigui i els apliqui polítiques comunes sense moure-les.
La seva jerarquia:
| Nivell | Què és | A AlpinaShop |
|---|---|---|
| Llac (lake) | Domini de dades; agrupa tot el d'un àmbit | alpinashop-lago-comercial |
| Zona (zone) | Subdivisió per grau de refinament | zona-cruda, zona-curada |
| Actiu (asset) | Recurs concret: un bucket o un dataset | El bucket del llac, el dataset analític |
Les zones tenen dos tipus amb semàntica diferent:
- Raw: dades en el seu format original, sense validar. Qualsevol format.
- Curated: dades ja netes i estructurades, amb esquema. Només formats estructurats (Parquet, Avro, ORC) o taules de BigQuery. Dataplex valida que el que s'hi registra ho compleix.
flowchart TD
L["Llac: alpinashop-lago-comercial"]
Z1["Zona RAW: zona-cruda<br/>dades tal com arriben"]
Z2["Zona CURATED: zona-curada<br/>dades netes i modelades"]
A1["Actiu: gs://alpinashop-datalake<br/>esdeveniments, exportacions, quarantena"]
A2["Actiu: gs://alpinashop-catalogo<br/>imatges i exportacions"]
A3["Actiu: BQ alpinashop_analitica<br/>pedidos, lineas, productos, visitas"]
A4["Actiu: gs://alpinashop-datalake/resultados<br/>Parquet de Spark"]
L --> Z1 --> A1
Z1 --> A2
L --> Z2 --> A3
Z2 --> A4
Creació:
gcloud config set project alpinashop-datos
gcloud services enable dataplex.googleapis.com \
datacatalog.googleapis.com datalineage.googleapis.com
# 1) El llac: el domini de dades comercial d AlpinaShop
gcloud dataplex lakes create alpinashop-lago-comercial \
--location=europe-west1 \
--display-name="Llac comercial d AlpinaShop" \
--description="Comandes, cataleg, navegacio i logistica" \
--labels=entorno=produccion,equipo=datos,centro-coste=analitica
# 2) Zona crua: el que arriba tal qual
gcloud dataplex zones create zona-cruda \
--location=europe-west1 --lake=alpinashop-lago-comercial \
--type=RAW \
--resource-location-type=SINGLE_REGION \
--display-name="Dades en cru" \
--discovery-enabled \
--discovery-schedule="0 3 * * *"
# 3) Zona curada: el que ja esta net i modelat
gcloud dataplex zones create zona-curada \
--location=europe-west1 --lake=alpinashop-lago-comercial \
--type=CURATED \
--resource-location-type=SINGLE_REGION \
--display-name="Dades curades" \
--discovery-enabled \
--discovery-schedule="0 4 * * *"
# 4) Actius
gcloud dataplex assets create activo-datalake \
--location=europe-west1 --lake=alpinashop-lago-comercial --zone=zona-cruda \
--resource-type=STORAGE_BUCKET \
--resource-name=projects/alpinashop-datos/buckets/alpinashop-datalake \
--discovery-enabled
gcloud dataplex assets create activo-analitica \
--location=europe-west1 --lake=alpinashop-lago-comercial --zone=zona-curada \
--resource-type=BIGQUERY_DATASET \
--resource-name=projects/alpinashop-datos/datasets/alpinashop_analitica \
--discovery-enabledL'opció --discovery-enabled és la que aporta valor immediat: Dataplex rastreja automàticament els actius, infereix esquemes dels fitxers del bucket, detecta particions per l'estructura de carpetes, i crea taules externes de BigQuery perquè aquests fitxers siguin consultables amb SQL sense que ningú les declari.
Per a AlpinaShop això significa que els Parquet que la feina de Spark deixa a gs://alpinashop-datalake/resultados/cesta/ apareixen com a taula consultable sense feina addicional. És descobriment automàtic de dades, i és la raó pràctica de registrar els buckets encara que el govern formal no interessi.
- El catàleg universal i la cerca de dades
L'Universal Catalog de Dataplex —hereu de Data Catalog— indexa automàticament les metadades de BigQuery, Cloud Storage, Pub/Sub, Spanner i Bigtable de tota l'organització. I sobre aquest índex hi ha un cercador.
La sintaxi de cerca:
# Tot el que esmenti 'pedido' pedido # Nomes taules de BigQuery type=TABLE system=BIGQUERY pedido # Per columna: on hi ha un camp que es digui email column:email # Per etiqueta de negoci tag:sensibilidad.nivel=alto # Per projecte i dataset parent:alpinashop-datos.alpinashop_analitica # Combinat: taules amb columna d import al dataset analitic type=TABLE parent:alpinashop_analitica column:importe
Des de la línia de comandes:
# Cercar totes les columnes anomenades 'email' a l organitzacio
gcloud data-catalog search "column:email" \
--include-project-ids=alpinashop-datos,alpinashop-prod \
--format="table(relativeResourceName, searchResultSubtype)"Aquesta consulta respon en segons a una pregunta que sense catàleg requereix obrir taula per taula: on hi ha correus? És el primer pas de l'apartat 8.
La resposta a la pregunta de màrqueting —"on és la dada de conversió?"— passa de "pregunta-ho a la Lucía" a buscar conversion al catàleg i trobar agg_embudo_dia amb la seva descripció. Aquest canvi és tot el valor del catàleg.
- Etiquetes i plantilles: documentar
alpinashop_analitica
alpinashop_analiticaEl catàleg indexa el que existeix, però no sap què significa. Per a això hi ha les etiquetes (tags), que afegeixen metadades de negoci a taules i columnes, estructurades segons una plantilla.
Primer la plantilla, que defineix quins camps es documenten i amb quins valors permesos:
cat > plantilla-gobierno.json <<'EOF'
{
"displayName": "Govern de les dades AlpinaShop",
"fields": {
"propietario": {
"displayName": "Propietari de la dada",
"type": {"primitiveType": "STRING"},
"isRequired": true,
"description": "Persona o equip responsable d aquest conjunt de dades"
},
"dominio": {
"displayName": "Domini de negoci",
"type": {"enumType": {"allowedValues": [
{"displayName": "ventas"},
{"displayName": "catalogo"},
{"displayName": "logistica"},
{"displayName": "marketing"},
{"displayName": "finanzas"}
]}},
"isRequired": true
},
"sensibilidad": {
"displayName": "Nivell de sensibilitat",
"type": {"enumType": {"allowedValues": [
{"displayName": "publico"},
{"displayName": "interno"},
{"displayName": "confidencial"},
{"displayName": "datos-personales"}
]}},
"isRequired": true
},
"frescura_esperada": {
"displayName": "Frescor esperada",
"type": {"enumType": {"allowedValues": [
{"displayName": "tiempo-real"},
{"displayName": "diaria"},
{"displayName": "semanal"},
{"displayName": "mensual"}
]}},
"isRequired": true
},
"retencion_meses": {
"displayName": "Retencio en mesos",
"type": {"primitiveType": "DOUBLE"},
"isRequired": true
},
"apto_para_informes": {
"displayName": "Apte per a informes de direccio",
"type": {"primitiveType": "BOOL"},
"isRequired": true,
"description": "Fals en taules de staging, temporals o experimentals"
},
"definicion_negocio": {
"displayName": "Definicio de negoci",
"type": {"primitiveType": "STRING"},
"isRequired": false,
"description": "Que significa exactament aquesta dada, en llenguatge de negoci"
}
}
}
EOF
gcloud data-catalog tag-templates create gobierno_alpinashop \
--location=europe-west1 \
--display-name="Govern de les dades AlpinaShop" \
--field-file=plantilla-gobierno.jsonI ara s'etiqueta cada taula:
# Taula de comandes: dada personal, diaria, apta per a informes
gcloud data-catalog tags create \
--entry-group=@bigquery \
--entry="//bigquery.googleapis.com/projects/alpinashop-datos/datasets/alpinashop_analitica/tables/pedidos" \
--tag-template=gobierno_alpinashop \
--tag-template-location=europe-west1 \
--tag-file=- <<'EOF'
{
"propietario": "[email protected]",
"dominio": "ventas",
"sensibilidad": "datos-personales",
"frescura_esperada": "diaria",
"retencion_meses": 84,
"apto_para_informes": true,
"definicion_negocio": "Capcalera de comanda confirmada. total_pedido INCLOU IVA i despeses d enviament, i NO descompta devolucions posteriors; per a vendes netes fer servir agg_ventas_categoria_dia."
}
EOFAquest camp definicion_negocio és la solució al segon problema de l'inici de la lliçó. Una frase escrita una vegada elimina per sempre la discussió sobre si total_pedido porta IVA. I queda on es busca, no en un document que ningú no obre.
La disciplina d'etiquetatge que AlpinaShop adopta:
| Taula | Sensibilitat | Apta per a informes | Nota |
|---|---|---|---|
pedidos |
datos-personales | Sí | Conté email_cliente |
lineas_pedido |
interno | Sí | Sense dades personals |
productos |
confidencial | Sí | coste_compra és marge comercial |
visitas |
datos-personales | Sí | cliente_id és pseudònim |
pedidos_staging |
interno | No | Taula de treball del DAG |
pedidos_evento |
datos-personales | No | Bolcat cru de Pub/Sub |
agg_* |
interno | Sí | Agregats, sense identificació |
La columna apta per a informes és la més útil en el dia a dia: distingeix el que pot alimentar un tauler de control del que és lampisteria. Sense ella, algú acabarà construint un informe de direcció sobre pedidos_staging, que es buida cada nit.
- Perfils de dades: què hi ha realment a les teves taules
Abans de definir regles de qualitat cal saber com són les dades. El perfilatge de Dataplex analitza una taula i produeix estadístiques per columna: valors nuls, diferents, mínims, màxims, mitjanes, percentils i els valors més freqüents.
gcloud dataplex datascans create data-profile perfil-pedidos \
--location=europe-west1 \
--data-source-resource="//bigquery.googleapis.com/projects/alpinashop-datos/datasets/alpinashop_analitica/tables/pedidos" \
--display-name="Perfil de la taula de comandes" \
--on-demand \
--data-profile-spec-sampling-percent=100
gcloud dataplex datascans run perfil-pedidos --location=europe-west1
gcloud dataplex datascans describe perfil-pedidos --location=europe-west1 --view=FULLUn perfil típic revela coses que ningú no sospitava:
| Columna | Nuls | Diferents | Troballa |
|---|---|---|---|
pedido_id |
0 % | 100 % | Correcte: identificador únic |
cliente_id |
12 % | 8.400 | Compres com a convidat. Se sabia? |
email_cliente |
0 % | 8.900 | Dada personal a totes les files |
canal |
0 % | 5 | Hi ha 5 valors, no 3: apareixen WEB i Web |
estado |
0 % | 6 | Correcte |
total_pedido |
0 % | — | mín. -45,00; màx. 4.120,00 |
envio.pais |
3 % | 14 | Hi ha comandes sense país |
Tres troballes accionables en una sola passada: el 12 % de compres sense client identificat (que pot ser normal o pot ser una fallada del registre), la inconsistència de majúscules a canal que trenca qualsevol GROUP BY, i un total_pedido negatiu, que probablement sigui un abonament mal modelat i que està distorsionant totes les mitjanes.
Aquest últim és l'exemple perfecte de per què el perfilatge va abans que les regles: la regla "total mai negatiu" no s'inventa, es descobreix.
- Regles de qualitat i què fer quan fallen
Amb el perfil a la mà es defineixen les regles. Un escaneig de qualitat executa un conjunt de comprovacions i dóna un resultat d'aprovat o fallit amb el detall per regla.
# calidad-pedidos.yaml
rules:
# --- Completesa ---
- column: pedido_id
nonNullExpectation: {}
dimension: COMPLETENESS
threshold: 1.0 # el 100 % de les files ho ha de complir
name: pedido-id-obligatorio
description: "Tota comanda ha de tenir identificador"
- column: fecha_pedido
nonNullExpectation: {}
dimension: COMPLETENESS
threshold: 1.0
name: fecha-obligatoria
# --- Unicitat ---
- column: pedido_id
uniquenessExpectation: {}
dimension: UNIQUENESS
threshold: 1.0
name: pedido-id-unico
description: "Detecta duplicats per reprocessos mal fets"
# --- Validesa de rang ---
- column: total_pedido
rangeExpectation:
minValue: "0"
maxValue: "10000"
strictMinEnabled: false
dimension: VALIDITY
threshold: 0.999 # es tolera un 0,1 % d excepcions
name: total-en-rango
description: "Imports no negatius i per sota de 10.000 EUR"
# --- Conjunt de valors permesos ---
- column: estado
setExpectation:
values: ["confirmado", "enviado", "entregado", "devuelto", "cancelado"]
dimension: VALIDITY
threshold: 1.0
name: estado-valido
- column: canal
setExpectation:
values: ["web", "movil", "telefono"]
dimension: VALIDITY
threshold: 1.0
name: canal-normalizado
description: "Detecta 'WEB' i 'Web' sense normalitzar"
# --- Format amb expressio regular ---
- column: email_cliente
regexExpectation:
regex: "^[^@\\s]+@[^@\\s]+\\.[a-zA-Z]{2,}$"
dimension: VALIDITY
threshold: 0.99
name: email-con-formato-valido
ignoreNull: true
# --- Regla SQL a nivell de fila ---
- sqlAssertion:
sqlStatement: |
SELECT pedido_id, subtotal, descuento, iva, total_pedido
FROM ${data()}
WHERE ABS(total_pedido - (subtotal - IFNULL(descuento,0)
+ IFNULL(iva,0))) > 0.01
dimension: ACCURACY
name: cuadre-de-importes
description: "El total ha de quadrar amb els seus components (tolerancia 1 centim)"
# --- Regla SQL agregada: frescor ---
- sqlAssertion:
sqlStatement: |
SELECT 1 FROM (
SELECT MAX(fecha_pedido) AS ultima FROM ${data()}
) WHERE DATE_DIFF(CURRENT_DATE(), ultima, DAY) > 2
dimension: FRESHNESS
name: datos-frescos
description: "Hi ha d haver comandes dels ultims 2 dies"gcloud dataplex datascans create data-quality calidad-pedidos \
--location=europe-west1 \
--data-source-resource="//bigquery.googleapis.com/projects/alpinashop-datos/datasets/alpinashop_analitica/tables/pedidos" \
--display-name="Qualitat de la taula de comandes" \
--data-quality-spec-file=calidad-pedidos.yaml \
--schedule="0 6 * * *" \
--export-results-table="//bigquery.googleapis.com/projects/alpinashop-datos/datasets/alpinashop_analitica/tables/resultados_calidad"Les sis dimensions de qualitat estàndard, amb la seva interpretació a AlpinaShop:
| Dimensió | Pregunta | Exemple |
|---|---|---|
| Completesa | Falta alguna cosa? | Comandes sense sku |
| Unicitat | Hi ha duplicats? | El mateix pedido_id dues vegades després d'un reprocés |
| Validesa | Els valors són possibles? | estado fora de la llista, import negatiu |
| Exactitud | Quadren entre si? | total ≠ subtotal - descuento + iva |
| Consistència | Coincideixen entre sistemes? | Comandes a BigQuery davant de Cloud SQL |
| Frescor | Estan actualitzades? | Sense comandes noves des de fa 3 dies |
Què fer quan una regla falla. Aquesta és la part que més es descuida, i sense ella l'escaneig és decoratiu:
| Gravetat | Exemple | Acció |
|---|---|---|
| Crítica | Duplicats, frescor trencada | Bloquejar: el tauler de control no s'ha d'actualitzar amb aquestes dades |
| Alta | Imports que no quadren | Alerta immediata al propietari, investigació en el dia |
| Mitjana | canal sense normalitzar |
Tiquet de correcció a l'origen; el pipeline ho normalitza mentrestant |
| Baixa | Un 0,3 % de correus amb format estrany | Informe setmanal; pot ser acceptable |
La integració amb l'orquestrador de 04-06 tanca el cercle:
from airflow.providers.google.cloud.operators.dataplex import (
DataplexRunDataQualityScanOperator,
)
qualitat = DataplexRunDataQualityScanOperator(
task_id="escaneo_calidad_pedidos",
project_id="alpinashop-datos",
region="europe-west1",
data_scan_id="calidad-pedidos",
asynchronous=False,
fail_on_dq_failure=True, # si falla la qualitat, FALLA EL DAG
)
consolidar_comandes >> qualitat >> llancar_dataflowAmb fail_on_dq_failure=True, una fallada de qualitat atura el procés nocturn abans de propagar dades dolentes al tauler de control. És la versió industrialitzada de la comprovació de qualitat que vam escriure a mà a 04-06.
- Llinatge automàtic d'extrem a extrem
A 04-05 vam veure el llinatge de Data Fusion, limitat als seus pipelines. Dataplex Lineage ho fa de manera transversal: captura automàticament el llinatge de BigQuery (cada consulta que escriu en una taula), Dataflow, Data Fusion, Composer i Dataproc.
I ja està: a partir d'aquí, cada feina registra el seu llinatge sola.
El graf complet d'AlpinaShop, que Dataplex construeix sense que ningú el dibuixi:
flowchart LR
CS["Cloud SQL<br/>alpinashop-pedidos"]
GCS["gs://alpinashop-datalake<br/>exportacions"]
PS["Pub/Sub<br/>pedidos-nuevos"]
ERP["MySQL ERP<br/>Sabadell"]
ST["BQ pedidos_staging"]
PE["BQ pedidos"]
LP["BQ lineas_pedido"]
CE["BQ costes_producto_erp"]
AG["BQ agg_ventas_categoria_dia"]
MV["MV mv_ventas_diarias_sku"]
LS["Looker Studio<br/>Tauler de control"]
CS -->|export| GCS -->|GCSToBigQuery| ST -->|MERGE| PE
PS -->|Dataflow| PE
PS -->|subscripcio BQ| PE
ERP -->|Datastream| CE
PE --> LP
LP --> AG
CE --> AG
AG --> MV --> LS
Les preguntes que aquest graf respon en un clic:
- "El marge de l'informe surt estrany. D'on ve?" →
agg_ventas_categoria_dia←lineas_pedido+costes_producto_erp← Datastream ← MySQL de l'ERP. En quatre salts s'arriba a l'origen. - "Canviarem l'esquema de l'ERP. Què es trenca?" → Tot el que penja de
costes_producto_erp, inclòs el tauler de control de direcció. - "Un client exerceix el seu dret de supressió. On és la seva dada?" → Es rastreja
pedidoscap endavant i apareixen totes les taules derivades. - "Podem apagar l'exportació nocturna de Cloud SQL?" → El graf mostra que
pedidos_stagingen depèn. No.
Aquesta última pregunta és la que més diners estalvia a la pràctica: saber què es pot apagar. Tota plataforma de dades amb dos anys acumula processos que ja no alimenten res, i sense llinatge ningú no s'atreveix a tocar-los.
- Sensitive Data Protection: descobrir on són les dades personals
Avís de RGPD. Aquest apartat i el següent tracten dades personals. Les eines que s'hi descriuen són controls tècnics, no un dictamen jurídic. Determinar la base legal d'un tractament, els terminis de conservació, la necessitat d'una avaluació d'impacte o si una pseudonimització és suficient correspon a un professional de compliance o al delegat de protecció de dades, i s'ha de fer abans de posar res en producció. Totes les dades d'aquest curs són fictícies.
Sensitive Data Protection —el servei abans conegut com a Cloud DLP— fa dues coses: inspeccionar per descobrir on hi ha dades sensibles, i desidentificar perquè deixin de ser-ho.
Comencem per la inspecció, que respon al tercer problema de l'inici de la lliçó: hi ha correus de clients en llocs on no n'hi hauria d'haver?
Una feina d'inspecció sobre tot el dataset:
{
"inspectJob": {
"storageConfig": {
"bigQueryOptions": {
"tableReference": {
"projectId": "alpinashop-datos",
"datasetId": "alpinashop_analitica",
"tableId": "pedidos_evento"
},
"sampleMethod": "RANDOM_START",
"rowsLimitPercent": 10
}
},
"inspectConfig": {
"infoTypes": [
{"name": "EMAIL_ADDRESS"},
{"name": "PHONE_NUMBER"},
{"name": "STREET_ADDRESS"},
{"name": "PERSON_NAME"},
{"name": "IBAN_CODE"},
{"name": "CREDIT_CARD_NUMBER"},
{"name": "ES_NIF_NUMBER"},
{"name": "IP_ADDRESS"}
],
"minLikelihood": "LIKELY",
"includeQuote": false,
"limits": {"maxFindingsPerRequest": 1000}
},
"actions": [
{
"saveFindings": {
"outputConfig": {
"table": {
"projectId": "alpinashop-datos",
"datasetId": "alpinashop_analitica",
"tableId": "hallazgos_dlp"
}
}
}
},
{"publishSummaryToCscc": {}}
]
}
}curl -X POST -H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
"https://dlp.googleapis.com/v2/projects/alpinashop-datos/locations/europe-west1/dlpJobs" \
-d @inspeccion-pedidos-evento.jsonDues decisions deliberades en aquesta configuració:
includeQuote: false: les troballes no inclouen el valor trobat. Si ho posessis atrue, la taula de troballes contindria els correus reals, és a dir, hauries creat una còpia sense protegir de les dades que intentes protegir. És un error clàssic i greu.rowsLimitPercent: 10: per descobrir si hi ha dades sensibles no cal escanejar el 100 %. Un mostreig del 10 % troba el problema i costa la desena part.
I una consulta sobre les troballes:
-- On hi ha dades personals i de quin tipus
SELECT
info_type.name AS tipo_dato,
location.container_name AS tabla,
location.content_locations[SAFE_OFFSET(0)]
.record_location.field_id.name AS columna,
likelihood,
COUNT(*) AS hallazgos
FROM `alpinashop-datos.alpinashop_analitica.hallazgos_dlp`
GROUP BY tipo_dato, tabla, columna, likelihood
ORDER BY hallazgos DESC;Resultat típic a AlpinaShop, i per què fa mal:
| Tipus | Taula | Columna | Comentari |
|---|---|---|---|
EMAIL_ADDRESS |
pedidos |
email_cliente |
Esperat: ja protegit amb etiqueta de política a 04-01 |
EMAIL_ADDRESS |
pedidos_evento |
payload |
No esperat: la subscripció de Pub/Sub bolca el JSON cru |
PERSON_NAME |
envios |
incidencia |
No esperat: el transportista escriu noms en text lliure |
PHONE_NUMBER |
opiniones |
texto |
No esperat: clients que deixen el seu telèfon a la ressenya |
IP_ADDRESS |
visitas |
dispositivo |
No esperat: una IP és dada personal segons el RGPD |
Quatre de les cinc troballes són sorpreses. Cap no és fruit de mala fe: són conseqüències naturals de moure dades. La subscripció de BigQuery de 04-04 bolca el missatge sencer. El transportista escriu el que vol al camp d'incidència. Els clients posen el seu telèfon en una ressenya. I una IP, que sembla tècnica, és dada personal.
Això és exactament el que cap organització no sap sense inspeccionar. I és la raó per la qual aquest apartat existeix.
Per fer-ho continu, Dataplex ofereix perfilatge de dades sensibles a nivell d'organització, que escaneja automàticament tot BigQuery i manté un inventari actualitzat d'on hi ha dades sensibles i amb quin nivell de risc, sense llançar feines a mà.
- Desidentificació: emmascarament i tokenització
Descobert el problema, cal actuar. Les tècniques, de menor a major utilitat conservada:
| Tècnica | Què fa | Reversible? | Quan utilitzar-la |
|---|---|---|---|
| Supressió | Elimina el valor | No | La dada no es necessita per a res |
| Emmascarament | [email protected] → ***@correo.com |
No | Es necessita el domini, no la persona |
| Substitució | Reemplaça per una constant | No | Només cal saber que hi havia alguna cosa |
| Hash cripto | HMAC-SHA256 amb clau a KMS | No | Comptar clients diferents sense saber qui són |
| Tokenització determinista (FPE) | Testimoni amb el format original | Sí, amb la clau | Creuar entre sistemes i poder revertir |
| Generalització | 34 anys → 30-39; 08013 → 08 |
No | Anàlisi demogràfica o geogràfica |
| Desplaçament de dates | Desplaça totes les dates d'un subjecte | Sí | Sèries temporals sense dates reals |
La distinció crítica és entre hash i tokenització determinista:
- El hash amb clau produeix el mateix resultat per al mateix valor, així que permet comptar i agrupar clients diferents, però no es pot tornar enrere. És el correcte per a analítica pura.
- La tokenització determinista amb preservació de format produeix un testimoni que sembla un correu i es pot revertir amb la clau. És el correcte quan un sistema autoritzat necessita recuperar el valor original.
Configuració de desidentificació per a AlpinaShop:
{
"deidentifyTemplate": {
"displayName": "Desidentificacio analitica AlpinaShop",
"description": "Aplica a les taules exposades a analisi i a Looker Studio",
"deidentifyConfig": {
"recordTransformations": {
"fieldTransformations": [
{
"fields": [{"name": "email_cliente"}],
"primitiveTransformation": {
"cryptoHashConfig": {
"cryptoKey": {
"kmsWrapped": {
"wrappedKey": "CiQA...",
"cryptoKeyName": "projects/alpinashop-prod/locations/europe-west1/keyRings/alpinashop-keyring/cryptoKeys/clave-pedidos"
}
}
}
}
},
{
"fields": [{"name": "codigo_postal"}],
"primitiveTransformation": {
"characterMaskConfig": {
"maskingCharacter": "X",
"numberToMask": 3,
"reverseOrder": true
}
}
},
{
"fields": [{"name": "texto_opinion"}],
"infoTypeTransformations": {
"transformations": [
{
"infoTypes": [
{"name": "EMAIL_ADDRESS"},
{"name": "PHONE_NUMBER"},
{"name": "PERSON_NAME"}
],
"primitiveTransformation": {
"replaceWithInfoTypeConfig": {}
}
}
]
}
}
]
}
}
}
}Què fa cada transformació:
email_cliente→ hash amb clau embolcallada a KMS. Reutilitzaclave-pedidosdel keyringalpinashop-keyringcreat a 03-06. La clau no surt mai de KMS, així que ni tan sols qui tingui accés a la taula pot revertir el hash. La Lucía continua podent comptar clients únics ambCOUNT(DISTINCT email_hash).codigo_postal→ emmascarament dels 3 últims.08013es converteix en08XXX. Es conserva la província, que és el que serveix per a l'anàlisi geogràfica, i es perd el carrer, que és el que identifica.texto_opinion→ substitució per tipus dins del text lliure. "Truqueu-me al 611223344, soc l'Ana" es converteix en "Truqueu-me al [PHONE_NUMBER], soc l'[PERSON_NAME]". La ressenya continua sent analitzable —inclosa l'anàlisi de sentiment del mòdul 5— sense dades personals a dins.
L'última és la més valuosa i la que cap altra eina no fa bé: desidentificar dins de text lliure, on la dada personal no és en una columna sinó incrustada en una frase.
I la vista que exposa la Lucía i el tauler de control:
-- Vista desidentificada: es la UNICA que es connecta a Looker Studio
CREATE OR REPLACE VIEW `alpinashop-datos.alpinashop_analitica.v_pedidos_analitica` AS
SELECT
pedido_id,
fecha_pedido,
momento_pedido,
cliente_id,
canal,
estado,
-- Provincia si, adreca no
envio.pais AS pais,
SUBSTR(envio.codigo_postal, 1, 2) AS provincia_cp,
metodo_pago,
subtotal, descuento, iva, total_pedido
FROM `alpinashop-datos.alpinashop_analitica.pedidos`;
-- Sense email_cliente, sense ciutat, sense codi postal complet.
-- Es una VISTA AUTORITZADA (04-01): qui la consulta NO necessita
-- permis sobre la taula base, i per tant no se la pot saltar.El principi operatiu: les dades personals existeixen a la taula base, protegida i amb accés restringit a gcp-seguridad@; tota la resta —analítica, taulers de control, exploració— consumeix vistes desidentificades. La minimització no és una neteja puntual, és una arquitectura.
- Looker Studio: connectar i modelar
Looker Studio (abans Data Studio) és l'eina gratuïta de visualització de Google. Es connecta a BigQuery i a desenes d'orígens, i permet construir informes interactius sense codi.
Hi ha tres maneres de connectar-lo a BigQuery, i triar bé determina el cost i el rendiment:
| Mode | Què fa | Cost | Quan |
|---|---|---|---|
| Taula/vista | Consulta en directe contra la taula | Cada interacció costa | Dades que canvien i es filtren molt |
| Consulta personalitzada | SQL propi com a origen | Cada interacció executa aquest SQL | Modelatge complex; compte amb el cost |
| Extracció | Copia les dades a la memòria cau de Looker Studio | Gairebé zero | Volums petits, refresc diari |
La regla d'or: no connectis mai Looker Studio directament a una taula de detall gran. Connecta'l a una taula agregada o a una vista materialitzada. Un tauler de control amb sis gràfics que consulta lineas_pedido executa sis consultes cada vegada que algú canvia un filtre, i amb deu usuaris refrescant, la factura de BigQuery es dispara —exactament l'escenari de l'exercici 3 de 04-01.
Per a AlpinaShop, l'origen del tauler de control serà una taula preparada pel procés nocturn:
-- Taula base del tauler de control: petita, agregada, llesta per consumir
CREATE OR REPLACE TABLE `alpinashop-datos.alpinashop_analitica.bi_resumen_diario`
PARTITION BY dia
CLUSTER BY canal, pais AS
SELECT
p.fecha_pedido AS dia,
p.canal,
p.envio.pais AS pais,
pr.categoria,
COUNT(DISTINCT p.pedido_id) AS pedidos,
COUNT(DISTINCT p.cliente_id) AS clientes,
SUM(l.cantidad) AS unidades,
ROUND(SUM(l.importe_linea), 2) AS ventas_eur,
ROUND(SUM(l.cantidad * c.coste_medio_eur), 2) AS coste_eur,
COUNTIF(p.estado = 'devuelto') AS pedidos_devueltos
FROM `alpinashop-datos.alpinashop_analitica.pedidos` AS p
JOIN `alpinashop-datos.alpinashop_analitica.lineas_pedido` AS l
ON l.pedido_id = p.pedido_id AND l.fecha_pedido = p.fecha_pedido
JOIN `alpinashop-datos.alpinashop_analitica.productos` AS pr USING (sku)
LEFT JOIN `alpinashop-datos.alpinashop_analitica.costes_producto_erp` AS c USING (sku)
WHERE p.fecha_pedido >= DATE_SUB(CURRENT_DATE(), INTERVAL 800 DAY)
AND p.estado NOT IN ('cancelado')
GROUP BY dia, p.canal, pais, pr.categoria;Aquesta taula té uns pocs milers de files —dos anys × 3 canals × 14 països × 6 categories— davant dels milions de lineas_pedido. Consultar-la és pràcticament gratis.
Els camps calculats de Looker Studio es defineixen sobre l'origen i es comporten com a columnes:
# Tiquet mitja
SUM(ventas_eur) / NULLIF(SUM(pedidos), 0)
# Marge brut en euros
SUM(ventas_eur) - SUM(coste_eur)
# Marge percentual
100 * (SUM(ventas_eur) - SUM(coste_eur)) / NULLIF(SUM(ventas_eur), 0)
# Taxa de devolucio
100 * SUM(pedidos_devueltos) / NULLIF(SUM(pedidos), 0)
# Agrupacio de canals per a una vista simplificada
CASE
WHEN canal IN ('web','movil') THEN 'Digital'
ELSE 'Altres'
ENDConsell de modelatge: defineix els camps calculats a la vista de BigQuery, no a Looker Studio, sempre que puguis. Un camp definit en SQL està versionat a Git, és reutilitzable per altres informes i per Spark, i no es perd si algú duplica l'informe. Un camp definit a Looker Studio viu dins d'aquest informe i ningú més no el veu.
- El tauler de control de direcció d'AlpinaShop
Dissenyem l'informe que direcció porta demanant des del mòdul 3.
Estructura en tres pàgines:
Pagina 1 — RESUM EXECUTIU +----------------------------------------------------------+ | [Selector de dates] [Canal] [Pais] [Categoria] | +----------------------------------------------------------+ | Vendes mes | Comandes | Tiquet mitja | Marge % | | 42.180 EUR | 387 | 108,99 EUR | 38,2 % | | ^ +12,4 % | ^ +8,1 % | ^ +4,0 % | v -1,2 pp | +----------------------------------------------------------+ | Evolucio de vendes (linia, 13 mesos, amb any anterior) | +----------------------------------------------------------+ | Top 10 productes (barres) | Vendes per categoria (anell)| +----------------------------------------------------------+ Pagina 2 — EMBUT I CONVERSIO +----------------------------------------------------------+ | Embut: sessions > vist > cistella > pagament > compra | +----------------------------------------------------------+ | Taxa de conversio (linia) | Cost d adquisicio (linia) | +----------------------------------------------------------+ | Conversio per canal i dispositiu (taula amb barres) | +----------------------------------------------------------+ Pagina 3 — PRODUCTE I LOGISTICA +----------------------------------------------------------+ | Marge per categoria (barres) | Productes sense vendes | +----------------------------------------------------------+ | Taxa de devolucio per categoria | Termini lliurament | +----------------------------------------------------------+
Els indicadors clau, amb la seva definició explícita —que és el que evita la discussió de "aquest número no és el que jo tenia":
| Indicador | Fórmula | Definició que cal escriure a l'informe |
|---|---|---|
| Vendes del mes | SUM(ventas_eur) |
Import de línies de comanda, IVA inclòs, sense comandes cancel·lades |
| Evolució | Comparació amb el període anterior | Mateix nombre de dies, no mes natural complet |
| Tiquet mitjà | ventas / pedidos |
Per comanda, no per línia |
| Top de productes | SUM(unidades) per SKU |
Per unitats venudes, no per import |
| Taxa de conversió | compras / sesiones |
Sessions amb activitat, no visites totals |
| Cost d'adquisició | inversió / clients nous |
Requereix la dada d'inversió en màrqueting |
| Marge | (ventas - coste) / ventas |
Cost de l'ERP; sense despeses generals ni logística |
El cost d'adquisició mereix una nota honesta: requereix una dada que AlpinaShop encara no té a la plataforma —la inversió mensual en publicitat—. Hi ha dues opcions: carregar-la com una taula manual mantinguda per màrqueting, o integrar-la des de l'API de la plataforma publicitària. La primera és la sensata per començar. I cal mostrar-la a l'informe indicant d'on surt, perquè un indicador l'origen del qual ningú no coneix acaba desacreditant la resta.
Bones pràctiques de disseny, que són les que separen un informe que s'utilitza d'un que s'obre una vegada:
- El més important a dalt a l'esquerra. És on va la vista.
- Quatre targetes d'indicador, no dotze. Un tauler de control amb vint xifres no es llegeix: s'ignora.
- Comparació sempre. Un número sense context no informa. 42.180 € no diu res;
+12,4 % davant del mes anteriorsí. - Un tipus de gràfic per pregunta: línia per a evolució, barres per comparar categories, taula per al detall. Res de gràfics de pastís amb dotze porcions.
- Filtres a dalt i comuns a la pàgina, no repartits pels gràfics.
- Colors amb significat i accessibles: verd i vermell tenen sentit per a bo i dolent, però cal assegurar-se que es distingeixen també per a daltònics, afegint fletxes o signes a més del color.
- Data de darrera actualització visible. Un informe sense ella genera desconfiança i trucades.
- Una nota metodològica al peu. On es defineix cada indicador. És la diferència entre un informe i una discussió.
- Cost i rendiment: extracció, consulta en directe i BI Engine
Els tres mecanismes, en ordre de cost creixent:
1. Extracció de dades. Looker Studio copia fins a un límit de dades a la seva pròpia memòria cau i les serveix des d'allà. Refresc programable de fins a una vegada al dia. Cost de BigQuery pràcticament nul, rendiment excel·lent. És l'opció per defecte per a un informe amb dades agregades que no necessita ser d'avui mateix.
2. Consulta en directe amb memòria cau. Looker Studio guarda a la memòria cau els resultats durant un temps configurable (fins a 12 hores). Amb la memòria cau activada, deu persones mirant el mateix informe generen una consulta, no deu. És el que s'ha d'utilitzar en un tauler de control compartit.
3. BI Engine. Un servei d'acceleració en memòria de BigQuery. Es reserva una capacitat i les consultes que hi caben es responen en mil·lisegons i sense cost de bytes escanejats.
# Reserva de BI Engine de 2 GB per al tauler de control
bq update --reservation --project_id=alpinashop-datos \
--location=europe-west1 \
--bi_reservation_size=2147483648Amb la taula bi_resumen_diario, que ocupa uns pocs megabytes, 2 GB de BI Engine hi caben de sobres: el tauler de control sencer se serveix des de memòria, amb latència de mil·lisegons i sense facturar escaneig. El cost de la reserva és de l'ordre d'uns pocs euros al mes, i sol sortir més barat que pagar les consultes que evita.
Comprovar que BI Engine s'està utilitzant:
SELECT
job_id,
bi_engine_statistics.bi_engine_mode AS modo,
ROUND(total_bytes_billed / POW(1024,2), 2) AS mb_facturados,
TIMESTAMP_DIFF(end_time, start_time, MILLISECOND) AS ms
FROM `region-europe-west1`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY)
AND job_type = 'QUERY'
AND bi_engine_statistics IS NOT NULL
ORDER BY creation_time DESC
LIMIT 20;Si modo és FULL, la consulta es va resoldre íntegrament en memòria. Si és DISABLED o PARTIAL, el camp bi_engine_statistics.acceleration_mode explica per què —normalment perquè la consulta utilitza una funció no admesa o la taula no hi cap.
La recepta completa d'AlpinaShop, resumida: taula agregada petita + memòria cau activada + BI Engine + informe connectat a la vista desidentificada. Cost mensual del tauler de control: uns pocs euros. Sense aquesta disciplina, els mateixos gràfics costarien centenars.
- Permisos: l'error clàssic de les credencials del propietari
Aquí hi ha l'error més perillós de tota la lliçó, i passa constantment perquè la interfície ho posa fàcil.
Quan es crea un origen de dades a Looker Studio cal triar amb quines credencials s'executen les consultes:
| Mode | Com funciona | Conseqüència |
|---|---|---|
| Credencials del propietari | Totes les consultes utilitzen els permisos de qui va crear l'origen | Qui veu l'informe accedeix a les dades amb els permisos del propietari, encara que ell no en tingui cap |
| Credencials de l'espectador | Cada consulta utilitza els permisos de qui mira | Cada persona veu el que els seus permisos de BigQuery li permeten |
L'escenari del desastre, pas a pas:
- La Lucía crea el tauler de control connectat a BigQuery amb credencials del propietari. És el còmode, i és el que la interfície suggereix.
- La Lucía té, a més d'accés als agregats, permís de lectura sobre
pedidoscomplet. - La Lucía comparteix l'informe amb "qualsevol persona amb l'enllaç" perquè un proveïdor extern vegi un gràfic.
- Aquest proveïdor —o qualsevol a qui reenviïn l'enllaç— pot explorar les dades amb els permisos de la Lucía. Pot afegir camps, canviar dimensions i, si l'origen és una taula amb dades personals, veure-les.
- Ningú a BigQuery no ha donat cap permís a aquesta persona. Els permisos de BigQuery no la protegeixen, perquè les consultes no es fan en nom seu.
Això és una bretxa de dades personals amb obligació de notificació sota el RGPD.
Les regles que AlpinaShop adopta, sense excepció:
- L'origen apunta sempre a una vista desidentificada i autoritzada, mai a una taula amb dades personals. Encara que el mode de credencials sigui l'equivocat, no hi ha res sensible al darrere. Aquesta és la defensa que no depèn que ningú se'n recordi.
- Credencials de l'espectador en qualsevol informe que surti de l'equip de dades.
- Mai "qualsevol persona amb l'enllaç" per a informes amb dades de negoci. Compartir sempre amb persones o grups concrets (
gcp-datos@,direccion@). - Revisió trimestral de amb qui estan compartits els informes. Els permisos s'acumulen sols.
- Si calen credencials del propietari —perquè els espectadors no tenen ni han de tenir permisos de BigQuery—, aleshores l'origen ha de ser una vista agregada sense cap dada personal ni confidencial. Sense negociació.
Verificació des de BigQuery de qui està consultant des de Looker Studio:
SELECT
user_email,
COUNT(*) AS consultas,
ROUND(SUM(total_bytes_billed)/POW(1024,3), 2) AS gb,
MIN(creation_time) AS primera,
MAX(creation_time) AS ultima
FROM `region-europe-west1`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
AND job_type = 'QUERY'
AND (labels.requestor = 'looker_studio'
OR STRPOS(IFNULL(query, ''), 'Looker Studio') > 0)
GROUP BY user_email
ORDER BY consultas DESC;Si en aquesta llista apareix una sola adreça de correu —la de la Lucía— quan l'informe el miren quinze persones, ets en mode credencials del propietari. És la comprovació de trenta segons que convé fer avui.
- Looker i LookML: quan justifica el seu preu
Looker (sense "Studio") és un producte diferent i molt més car. La seva diferència essencial és LookML, un llenguatge de modelatge on es defineix una sola vegada què significa cada mètrica i cada dimensió, i tots els informes de l'empresa consumeixen aquestes definicions.
# modelo.lkml — la definicio viu en UN lloc, versionada a Git
view: pedidos {
sql_table_name: `alpinashop-datos.alpinashop_analitica.bi_resumen_diario` ;;
dimension_group: dia {
type: time
timeframes: [date, week, month, quarter, year]
sql: ${TABLE}.dia ;;
}
dimension: canal { type: string sql: ${TABLE}.canal ;; }
measure: ventas_eur {
type: sum
sql: ${TABLE}.ventas_eur ;;
value_format_name: eur
description: "Import de linies de comanda, IVA inclos, sense cancel·lades"
}
measure: pedidos { type: sum sql: ${TABLE}.pedidos ;; }
measure: ticket_medio {
type: number
sql: ${ventas_eur} / NULLIF(${pedidos}, 0) ;;
value_format_name: eur
description: "Vendes dividit entre nombre de comandes"
}
}| Criteri | Looker Studio | Looker |
|---|---|---|
| Cost | Gratuït (Pro té cost) | Milers de € al mes |
| Modelatge centralitzat | No: cada informe defineix el seu | Sí, LookML |
| Versionat a Git | No | Sí, natiu |
| Coherència de mètriques | Depèn de la disciplina | Garantida per disseny |
| Permisos per fila | Via BigQuery | Natiu al model |
| API i contingut incrustat | Limitat | Complet |
| Corba d'aprenentatge | Hores | Setmanes |
Quan justifica el seu preu: quan el cost de la incoherència supera el cost de la llicència. És a dir, quan hi ha desenes d'analistes creant informes, quan "vendes" significa coses diferents en tres departaments i les reunions es dediquen a discutir de qui és el número bo, o quan es necessita govern del model semàntic amb revisió per pull request.
Per a AlpinaShop, Looker Studio és la resposta òbvia: tres persones, un tauler de control, pressupost de pime. La coherència es garanteix amb la disciplina de l'apartat 10 —definir les mètriques en vistes de BigQuery versionades a Git— que és el 80 % del valor de LookML pel 0 % del preu.
- Checklist d'una plataforma de dades sana
Organització i descobriment
- [ ] Tots els datasets i buckets registrats en un llac de Dataplex amb les seves zones.
- [ ] Descobriment automàtic activat als actius de Cloud Storage.
- [ ] Tota taula amb
descriptioni amb etiquetes de govern. - [ ] Distinció explícita entre taules aptes per a informes i taules de lampisteria.
- [ ] Cada taula amb un propietari nomenat.
Qualitat
- [ ] Perfilatge executat sobre les taules principals.
- [ ] Regles de qualitat definides per a completesa, unicitat, validesa, exactitud i frescor.
- [ ] Escaneigs programats diàriament.
- [ ] L'orquestrador bloqueja el procés si falla una regla crítica.
- [ ] Resultats històrics exportats a BigQuery per veure la tendència.
Llinatge
- [ ] API de llinatge activada.
- [ ] Graf revisat després de cada canvi d'arquitectura.
- [ ] Processos sense consumidors identificats i apagats.
Seguretat i privacitat
- [ ] Inspecció de dades sensibles executada sobre tot el dataset, no només on se sospita.
- [ ] Columnes amb dades personals etiquetades amb política d'accés.
- [ ] Vistes desidentificades com a única superfície d'exposició analítica.
- [ ] Cap eina de BI connectada a una taula amb dades personals.
- [ ] Claus de hash i tokenització a KMS, mai al codi.
- [ ] Revisió per un professional de compliance o el DPD abans de producció.
Cost
- [ ] Taules particionades i clusteritzades;
require_partition_filtera les grans. - [ ] Taulers de control connectats a agregats, mai a taules de detall.
- [ ] Memòria cau d'informes activada; BI Engine si compensa.
- [ ] Pressupostos i alertes per etiqueta de centre de cost.
- [ ] Res permanentment encès que no ho necessiti: sense clústers de Dataproc oblidats, sense instàncies de Data Fusion enceses, sense pipelines de streaming orfes.
- [ ] Auditoria periòdica de consultes cares amb
INFORMATION_SCHEMA.
Operació
- [ ] Tots els processos orquestrats, cap en un
crond'una VM. - [ ] Tasques idempotents; reprocessos segurs.
- [ ] Alertes que arriben a una persona concreta, no a un correu genèric.
- [ ] Codi —DDL, DAG, pipelines, fluxos— versionat a Git.
- [ ] Documentació de què fa cada procés i a qui avisar.
Errors Habituals i Consells
Documentar només al principi. Un catàleg amb etiquetes de fa un any és pitjor que cap, perquè genera confiança injustificada. Documentar ha de ser part de crear la taula, no un projecte a part.
Posar regles de qualitat sense perfilar abans. S'acaben definint llindars inventats que fallen a diari, tothom ignora les alertes, i el sistema deixa de servir. Perfila, mira les dades reals, i després defineix.
Regles de qualitat que no bloquegen res. Si una fallada de qualitat no atura el procés ni avisa ningú, és decoració.
Inspeccionar amb includeQuote: true. Es crea una taula de troballes que conté les dades sensibles que es volien protegir. És empitjorar el problema.
Confondre hash amb anonimització. Un hash sense sal ni clau d'un correu és reversible per força bruta —l'espai de correus plausibles no és tan gran—. Continua sent dada personal a efectes del RGPD. La clau ha d'estar a KMS.
Connectar Looker Studio a una taula de detall. Cada filtre dispara consultes sobre milions de files. És el camí directe a una factura sorpresa.
Credencials del propietari més enllaç públic. L'error més greu de la lliçó. Qualsevol amb l'enllaç consulta amb els permisos del propietari.
No posar la data d'actualització a l'informe. Genera desconfiança, trucades i decisions basades en dades de la setmana passada creient que són d'avui.
Definir les mètriques a Looker Studio en comptes de a BigQuery. Queden tancades en aquest informe, no es versionen, i en duplicar-lo divergeixen.
Consell: escriu la definició de negoci de cada mètrica i publica-la. La meitat de les discussions sobre dades són discussions sobre definicions, no sobre números.
Consell: posa un enllaç al catàleg al peu del tauler de control. Qui vulgui saber què significa un número, que hi pugui arribar sol.
Consell: fes la inspecció de dades sensibles avui, no quan hi hagi un incident. Costa una tarda i gairebé sempre troba alguna cosa que ningú no sabia.
Exercicis
Exercici 1: governar la taula de ressenyes
Per a la taula alpinashop_analitica.opiniones: (a) escriu la comanda que la registra com a actiu a la zona curada del llac; (b) crea l'etiqueta de govern indicant propietari, domini, sensibilitat, frescor, retenció, aptitud per a informes i una definició de negoci precisa; (c) defineix un escaneig de qualitat amb almenys cinc regles que cobreixin completesa, unicitat, validesa de rang, conjunt de valors i una regla SQL pròpia; (d) explica quina acció prendries davant de la fallada de cada regla.
Exercici 2: inspecció i desidentificació de ressenyes
El camp texto d'opiniones és text lliure escrit per clients. Dissenya: (a) la feina d'inspecció que descobreixi quins tipus de dades personals conté, amb les opcions correctes per no crear una còpia de les dades sensibles; (b) la plantilla de desidentificació que permeti conservar el text analitzable —per a l'anàlisi de sentiment del mòdul 5— eliminant les dades personals; (c) la vista que s'exposaria a Looker Studio; (d) l'advertiment de RGPD que acompanyaria la proposta abans de portar-la a producció.
Exercici 3: redissenyar un tauler de control problemàtic
El tauler de control de direcció porta dos mesos funcionant i hi ha quatre problemes. Un: triga 40 segons a carregar i el cost de BigQuery del projecte ha passat de 12 € a 310 € al mes. Dos: INFORMATION_SCHEMA mostra que totes les consultes de l'informe les fa [email protected], encara que el miren dotze persones. Tres: l'informe està compartit com a "qualsevol persona amb l'enllaç" perquè es va haver d'ensenyar a un consultor extern. Quatre: direcció diu que el número de vendes de l'informe no coincideix amb el de comptabilitat.
Diagnostica cada problema, indica la seva gravetat relativa i proposa la solució concreta amb l'ordre d'actuació.
Solucions
Solució 1
(a) Registrar l'actiu. La taula ja és dins del dataset alpinashop_analitica, que es va registrar complet com a actiu activo-analitica a zona-curada. Per tant no cal registrar la taula individualment: Dataplex la descobreix en rastrejar el dataset. Si es volgués un actiu separat —per exemple, per a un dataset diferent— seria:
gcloud dataplex assets create activo-opiniones \
--location=europe-west1 \
--lake=alpinashop-lago-comercial --zone=zona-curada \
--resource-type=BIGQUERY_DATASET \
--resource-name=projects/alpinashop-datos/datasets/alpinashop_opiniones \
--discovery-enabled
gcloud dataplex assets describe activo-opiniones \
--location=europe-west1 --lake=alpinashop-lago-comercial --zone=zona-curada(b) Etiqueta de govern.
gcloud data-catalog tags create \
--entry-group=@bigquery \
--entry="//bigquery.googleapis.com/projects/alpinashop-datos/datasets/alpinashop_analitica/tables/opiniones" \
--tag-template=gobierno_alpinashop \
--tag-template-location=europe-west1 \
--tag-file=- <<'EOF'
{
"propietario": "[email protected]",
"dominio": "catalogo",
"sensibilidad": "datos-personales",
"frescura_esperada": "diaria",
"retencion_meses": 36,
"apto_para_informes": false,
"definicion_negocio": "Ressenyes de clients sobre productes. puntuacion es de 1 a 5, entera. El camp texto es LLIURE i pot contenir dades personals incrustades (noms, telefons): NO exposar directament; fer servir la vista v_opiniones_analitica, ja desidentificada. Una ressenya correspon a un client i un SKU; un client pot opinar diverses vegades del mateix producte."
}
EOFsensibilidad: datos-personales i apto_para_informes: false són les dues decisions clau: encara que el camp texto sembli innocu, és text lliure i per tant imprevisible.
(c) Escaneig de qualitat.
# calidad-opiniones.yaml
rules:
- column: opinion_id
nonNullExpectation: {}
dimension: COMPLETENESS
threshold: 1.0
name: opinion-id-obligatorio
- column: opinion_id
uniquenessExpectation: {}
dimension: UNIQUENESS
threshold: 1.0
name: opinion-id-unico
- column: puntuacion
rangeExpectation:
minValue: "1"
maxValue: "5"
dimension: VALIDITY
threshold: 1.0
name: puntuacion-de-1-a-5
- column: pais
setExpectation:
values: ["ES","FR","PT","IT","DE","AD","BE","NL","AT","CH","GB","IE","LU","PL"]
dimension: VALIDITY
threshold: 0.99
name: pais-en-lista
- column: sku
nonNullExpectation: {}
dimension: COMPLETENESS
threshold: 1.0
name: sku-obligatorio
# Regla SQL: integritat referencial contra el cataleg
- sqlAssertion:
sqlStatement: |
SELECT o.opinion_id, o.sku
FROM ${data()} AS o
LEFT JOIN `alpinashop-datos.alpinashop_analitica.productos` AS p
ON p.sku = o.sku
WHERE p.sku IS NULL
dimension: CONSISTENCY
name: sku-existe-en-catalogo
# Regla SQL: frescor
- sqlAssertion:
sqlStatement: |
SELECT 1 FROM (SELECT MAX(fecha) AS ultima FROM ${data()})
WHERE DATE_DIFF(CURRENT_DATE(), ultima, DAY) > 7
dimension: FRESHNESS
name: opiniones-recientesgcloud dataplex datascans create data-quality calidad-opiniones \
--location=europe-west1 \
--data-source-resource="//bigquery.googleapis.com/projects/alpinashop-datos/datasets/alpinashop_analitica/tables/opiniones" \
--data-quality-spec-file=calidad-opiniones.yaml \
--schedule="0 6 * * *" \
--export-results-table="//bigquery.googleapis.com/projects/alpinashop-datos/datasets/alpinashop_analitica/tables/resultados_calidad"(d) Acció davant de cada fallada:
| Regla | Gravetat | Acció |
|---|---|---|
opinion-id-obligatorio |
Crítica | Bloquejar el procés. Un identificador nul trenca la idempotència del MERGE |
opinion-id-unico |
Crítica | Bloquejar i investigar: indica reprocés mal fet, exactament la fallada de 04-06 |
puntuacion-de-1-a-5 |
Alta | Alerta i quarantena d'aquestes files. Una puntuació de 9 falseja totes les mitjanes |
pais-en-lista |
Mitjana | Tiquet a l'equip web. Pot ser un país nou legítim: revisar i ampliar la llista |
sku-obligatorio |
Alta | Alerta: una ressenya sense producte no és analitzable |
sku-existe-en-catalogo |
Mitjana | Investigar: producte descatalogat i esborrat del mestre, o error d'escriptura |
opiniones-recientes |
Alta | Alerta a l'equip de plataforma: probablement el pipeline d'ingesta està trencat i ningú no ho sap |
Solució 2
(a) Inspecció.
{
"inspectJob": {
"storageConfig": {
"bigQueryOptions": {
"tableReference": {
"projectId": "alpinashop-datos",
"datasetId": "alpinashop_analitica",
"tableId": "opiniones"
},
"identifyingFields": [{"name": "opinion_id"}],
"sampleMethod": "RANDOM_START",
"rowsLimitPercent": 20
}
},
"inspectConfig": {
"infoTypes": [
{"name": "EMAIL_ADDRESS"},
{"name": "PHONE_NUMBER"},
{"name": "PERSON_NAME"},
{"name": "STREET_ADDRESS"},
{"name": "ES_NIF_NUMBER"},
{"name": "IBAN_CODE"},
{"name": "CREDIT_CARD_NUMBER"},
{"name": "URL"}
],
"minLikelihood": "POSSIBLE",
"includeQuote": false,
"limits": {"maxFindingsPerRequest": 3000}
},
"actions": [
{"saveFindings": {"outputConfig": {"table": {
"projectId": "alpinashop-datos",
"datasetId": "alpinashop_analitica",
"tableId": "hallazgos_dlp_opiniones"
}}}}
]
}
}Les tres decisions que s'avaluen:
includeQuote: false: sense això, la taulahallazgos_dlp_opinionescontindria els telèfons i noms reals trobats. S'hauria creat una segona còpia sense protegir d'exactament el que es vol protegir.minLikelihood: POSSIBLEen comptes deLIKELY: en text lliure escrit per persones, les dades apareixen en formats irregulars ("truqueu-me al sis onze..."). Un llindar baix genera més falsos positius, cosa que és preferible a no detectar una dada real. En una columna estructurada s'utilitzariaLIKELY.identifyingFields: permet saber quina ressenya conté la troballa sense guardar el valor, cosa que fa el resultat accionable.
(b) Plantilla de desidentificació.
{
"deidentifyTemplate": {
"displayName": "Desidentificacio de ressenyes",
"deidentifyConfig": {
"recordTransformations": {
"fieldTransformations": [
{
"fields": [{"name": "texto"}],
"infoTypeTransformations": {
"transformations": [
{
"infoTypes": [
{"name": "PERSON_NAME"}, {"name": "PHONE_NUMBER"},
{"name": "EMAIL_ADDRESS"}, {"name": "STREET_ADDRESS"},
{"name": "ES_NIF_NUMBER"}, {"name": "IBAN_CODE"},
{"name": "CREDIT_CARD_NUMBER"}
],
"primitiveTransformation": {
"replaceWithInfoTypeConfig": {}
}
}
]
}
}
]
}
}
}
}Per què replaceWithInfoTypeConfig i no supressió. Substitueix cada troballa pel seu tipus entre claudàtors:
- Original:
"Molt comoda. Si teniu dubtes escriviu-me a [email protected] o al 611223344, soc Ana Ruiz" - Resultat:
"Molt comoda. Si teniu dubtes escriviu-me a [EMAIL_ADDRESS] o al [PHONE_NUMBER], soc [PERSON_NAME]"
El text continua sent analitzable. La ressenya conserva la seva estructura, la seva longitud aproximada i —el que importa per al mòdul 5— el seu sentiment: "Molt còmoda" continua sent-hi. Amb supressió pura es perdria la coherència sintàctica i l'anàlisi de sentiment es degradaria.
(c) Vista exposada.
CREATE OR REPLACE VIEW `alpinashop-datos.alpinashop_analitica.v_opiniones_analitica` AS
SELECT
opinion_id,
sku,
fecha,
puntuacion,
texto_desidentificado AS texto,
pais,
CASE WHEN puntuacion >= 4 THEN 'positiva'
WHEN puntuacion = 3 THEN 'neutra'
ELSE 'negativa' END AS valoracion,
LENGTH(texto_desidentificado) AS longitud_texto
FROM `alpinashop-datos.alpinashop_analitica.opiniones_desidentificadas`;El pipeline nocturn escriu a opiniones_desidentificadas aplicant la plantilla, i la taula original opiniones queda amb accés restringit a gcp-seguridad@. Looker Studio, la Lucía i els futurs models del mòdul 5 consumeixen exclusivament la vista.
(d) Advertiment de RGPD.
Les ressenyes de clients contenen dades personals, tant en camps estructurats (
paiscombinat ambskuifechapot ser reidentificable si el volum és baix) com incrustades en text lliure. Aquesta proposta aplica dues mesures tècniques: desidentificació automàtica del text mitjançant Sensitive Data Protection i restricció d'accés a la taula original.Abans de passar a producció és necessari que un professional de compliance o el delegat de protecció de dades determini: la base legal del tractament analític de les ressenyes; si la desidentificació aplicada constitueix anonimització efectiva o mera pseudonimització —cosa que determina si el RGPD continua aplicant-se al resultat—; el termini de conservació adequat; el risc de reidentificació per combinació de camps aparentment no identificatius; i si l'ús previst al mòdul 5 (anàlisi de sentiment) requereix informació addicional a l'interessat. La desidentificació automàtica no és infal·lible: un client que escrigui "soc el que va comprar la motxilla blava el dimarts a la botiga de Sabadell" no serà detectat per cap tipus de dada predefinit. Totes les dades d'aquest curs són fictícies.
Solució 3
Gravetat relativa, de major a menor:
Problema 3 (enllaç públic) + Problema 2 (credencials del propietari) = INCIDENT DE SEGURETAT.
No són dos problemes: són un de sol i greu. Que totes les consultes les faci la Lucía significa mode credencials del propietari. Combinat amb "qualsevol persona amb l'enllaç", qualsevol que tingui o rebi aquest enllaç consulta BigQuery amb els permisos de la Lucía, que inclouen la taula pedidos amb email_cliente. Si el consultor extern va reenviar l'enllaç, o si va acabar en un correu o un xat, hi ha una possible bretxa de dades personals amb obligació de notificació. S'actua primer, avui, en minuts.
Problema 4 (el número no quadra amb comptabilitat) = CRISI DE CONFIANÇA. És el segon en gravetat perquè destrueix el valor de tot el construït. Un tauler de control en què direcció no confia deixa d'utilitzar-se, i la feina de set lliçons es perd.
Problema 1 (lent i car) = OPERATIU. 310 € al mes fan mal, però no comprometen ni la seguretat ni la confiança. S'arregla en una tarda.
Actuació en tres fases:
Fase 1 — Avui, en minuts: tallar l'exposició.
1. Canviar la comparticio a "Persones concretes": gcp-datos@ i direccion@. Eliminar "qualsevol persona amb l enllac". 2. Canviar l origen de dades a CREDENCIALS DE L ESPECTADOR. 3. Comprovar a que apunta l origen. Si es una taula amb email_cliente, reapuntar-lo a la vista desidentificada v_pedidos_analitica.
-- Comprovar l abast real: qui ha consultat i quant, en 60 dies
SELECT
user_email,
COUNT(*) AS consultas,
MIN(creation_time) AS primera,
MAX(creation_time) AS ultima,
COUNT(DISTINCT DATE(creation_time)) AS dias_distintos
FROM `region-europe-west1`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 60 DAY)
AND job_type = 'QUERY'
AND STRPOS(IFNULL(query, ''), 'alpinashop_analitica') > 0
GROUP BY user_email
ORDER BY consultas DESC;I en paral·lel: avisar el responsable de seguretat i el DPD. La valoració de si això constitueix una bretxa notificable sota el RGPD no la pren l'equip tècnic. Cal documentar quines dades eren accessibles, durant quant de temps i a qui es va compartir l'enllaç.
Fase 2 — Aquesta setmana: recuperar la confiança en el número.
La discrepància amb comptabilitat té tres causes candidates, i cal determinar quina és abans de tocar res:
-- Comparar les tres definicions possibles de "vendes del mes"
SELECT
'A) Brut, IVA inclos, sense cancel·lades' AS definicion,
ROUND(SUM(total_pedido), 2) AS importe
FROM `alpinashop-datos.alpinashop_analitica.pedidos`
WHERE fecha_pedido BETWEEN DATE '2026-03-01' AND DATE '2026-03-31'
AND estado != 'cancelado'
UNION ALL
SELECT
'B) Brut sense IVA, sense cancel·lades',
ROUND(SUM(subtotal - IFNULL(descuento,0)), 2)
FROM `alpinashop-datos.alpinashop_analitica.pedidos`
WHERE fecha_pedido BETWEEN DATE '2026-03-01' AND DATE '2026-03-31'
AND estado != 'cancelado'
UNION ALL
SELECT
'C) Net sense IVA, sense cancel·lades NI retornades',
ROUND(SUM(subtotal - IFNULL(descuento,0)), 2)
FROM `alpinashop-datos.alpinashop_analitica.pedidos`
WHERE fecha_pedido BETWEEN DATE '2026-03-01' AND DATE '2026-03-31'
AND estado NOT IN ('cancelado','devuelto');Gairebé amb tota seguretat, comptabilitat utilitza la definició C —vendes netes sense IVA— i l'informe mostra la A. No és un error de dades: és un error de definició no documentada, exactament el segon problema de l'inici d'aquesta lliçó.
La correcció:
- Acordar amb comptabilitat una definició canònica i escriure-la.
- Implementar-la a la taula
bi_resumen_diario, exposant totes dues magnituds amb noms inequívocs:ventas_brutas_iva_incliventas_netas_sin_iva. - Escriure-la a l'etiqueta
definicion_negociodel catàleg de Dataplex. - Afegir una nota metodològica visible al peu del tauler de control.
Fase 3 — Aquest mes: cost i rendiment.
El diagnòstic primer:
SELECT
SUBSTR(REGEXP_REPLACE(query, r'\s+', ' '), 1, 200) AS consulta,
COUNT(*) AS ejecuciones,
ROUND(AVG(total_bytes_billed)/POW(1024,3), 2) AS gb_por_ejecucion,
ROUND(SUM(total_bytes_billed)/POW(1024,4), 2) AS tb_totales,
COUNTIF(cache_hit) AS desde_cache
FROM `region-europe-west1`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time >= TIMESTAMP_TRUNC(CURRENT_TIMESTAMP(), MONTH)
AND job_type = 'QUERY'
GROUP BY consulta
ORDER BY tb_totales DESC
LIMIT 10;El resultat esperat: l'informe està connectat directament a lineas_pedido o a pedidos, i cadascun dels vuit gràfics executa la seva pròpia consulta cada vegada que algú mou un filtre. Dotze persones × diversos filtres al dia × vuit gràfics = milers de consultes sobre milions de files.
Les quatre correccions, per ordre d'impacte:
- Reapuntar l'informe a
bi_resumen_diario, la taula agregada d'uns pocs milers de files que produeix el procés nocturn. Sola, aquesta mesura sol dividir el cost per cent i baixar la càrrega de 40 segons a menys de 3. - Activar la memòria cau de l'informe amb 12 hores de vigència. Dotze persones mirant generen una consulta, no dotze.
- Reservar 2 GB de BI Engine. La taula agregada hi cap sencera en memòria: resposta en mil·lisegons i zero bytes facturats.
- Posar una quota diària de bytes al projecte i una alerta de pressupost sobre l'etiqueta
centro-coste:analitica, perquè un problema equivalent es detecti als 20 € i no als 310 €.
Resultat esperat: de 310 €/mes a menys de 10 €, i de 40 segons a menys de 3.
La lliçó transversal de l'exercici: els quatre problemes eren evitables amb el que ja sabíem. El cost, amb el de 04-01. Els permisos, amb el de 03-04 i l'apartat 13. La discrepància de definicions, amb l'etiquetatge de l'apartat 4. Cap no era una fallada tècnica difícil: els quatre eren fallades de govern.
Conclusió
El mòdul 4 es tanca aquí, i es tanca amb la plataforma completa.
Has entès què és el govern de les dades —catàleg, llinatge, qualitat, classificació i cicle de vida— i per què una pime el necessita igual o més que una multinacional: el RGPD no distingeix per mida, el coneixement no té redundància quan l'equip són tres persones, els errors arriben a direcció sense filtres intermedis, i el deute de govern s'acumula amb interessos.
Has organitzat la plataforma a Dataplex: el llac alpinashop-lago-comercial amb la seva zona crua i la seva zona curada, amb els buckets i el dataset registrats com a actius i amb descobriment automàtic que converteix els Parquet de Spark en taules consultables sense declarar res. Has utilitzat el catàleg universal per respondre en segons a "on és la dada de conversió?" i a "on hi ha columnes que es diguin email". I has documentat amb una plantilla d'etiquetes que obliga a declarar propietari, domini, sensibilitat, frescor, retenció, aptitud per a informes i —el més valuós— la definició de negoci, aquella frase escrita una vegada que resol per sempre si total_pedido inclou IVA.
Has perfilat les taules abans de jutjar-les, descobrint el que ningú no sospitava: un 12 % de comandes sense client, cinc valors a canal on n'hi havia d'haver tres, i un total_pedido negatiu que distorsionava totes les mitjanes. I sobre aquest coneixement has definit regles de qualitat en les sis dimensions, amb llindars, amb exportació de resultats i —això és el que les fa útils— amb una acció assignada a cada fallada i amb integració a l'orquestrador perquè una fallada crítica aturi el procés abans de propagar dades dolentes.
Has activat el llinatge automàtic i tens el graf complet des de Cloud SQL i l'ERP de Sabadell fins al tauler de control, capaç de respondre d'on ve un número, què es trenca si canvies un esquema, on és la dada d'un client que exerceix el seu dret de supressió, i quin procés es pot apagar sense por.
Has inspeccionat amb Sensitive Data Protection i has trobat el que sempre es troba: correus al bolcat cru de Pub/Sub, noms al camp d'incidències del transportista, telèfons dins de ressenyes de clients, i IP a les dades de navegació. Quatre sorpreses de cinc troballes, cap per mala fe. I has desidentificat amb criteri: hash amb clau de KMS per poder comptar clients sense saber qui són, emmascarament del codi postal conservant la província, i substitució per tipus dins del text lliure perquè les ressenyes continuïn sent analitzables sense dades personals a dins. Amb l'advertiment exprés, repetit on tocava, que això són controls tècnics i que la decisió jurídica correspon a un professional de compliance o al DPD.
I has construït per fi el tauler de control que direcció demanava: connectat a una taula agregada petita i no a la taula de detall, amb memòria cau, amb BI Engine, amb camps calculats definits en SQL versionat i no tancats a l'informe, amb quatre indicadors i no dotze, amb comparació sempre, amb data d'actualització visible i amb nota metodològica al peu. I amb la lliçó de permisos que val per si sola tota la lliçó: credencials de l'espectador, compartició amb persones concretes, i l'origen apuntant sempre a una vista desidentificada, perquè és l'única defensa que no depèn que ningú se'n recordi. Saps quan Looker amb LookML justifica el seu preu —quan el cost de la incoherència supera el de la llicència— i per què AlpinaShop no és en aquest cas.
Mira el que existeix ara i que no existia fa set lliçons. Les comandes entren per Pub/Sub sense acoblar la botiga a res. Dataflow les transforma per lots i en streaming, amb el temps de l'esdeveniment ben entès. Dataproc calcula allò algorítmic en clústers que viuen quatre minuts. Data Fusion porta el que arriba brut de fora. BigQuery ho guarda i ho respon en segons, particionat, clusteritzat i sense arruïnar ningú. Workflows ho orquestra cada nit amb comprovacions que bloquegen si alguna cosa no quadra. Dataplex ho cataloga, ho mesura i ho rastreja. I Looker Studio ho ensenya. AlpinaShop ha passat de no saber quina motxilla es ven més a Catalunya a tenir una plataforma de dades governada per la qual la Lucía no demana res a ningú.
Però fixa't en el que tot això té en comú: descriu el que ja va passar. Explica les vendes d'ahir, l'embut del mes, el marge del trimestre, quins productes es van comprar junts. És memòria, i la memòria és valuosíssima. No és predicció, i no és automatització.
I AlpinaShop té ara mateix quatre preguntes que la memòria no pot respondre. Quan un client posa uns grampons al carretó, què li hauria de suggerir el web en aquell instant, aprofitant la matriu de coocurrència que va calcular Spark? Quan entren 60 GB d'imatges noves al catàleg, les ha d'etiquetar algú a mà o pot la màquina dir "això és una motxilla blava de 40 litres"? Amb 8.000 ressenyes en text lliure ja desidentificades, algú se les llegirà totes per saber què falla als frontals? I amb 2.400 fitxes de producte per descriure, qui les escriu?
Al mòdul 5, Aprenentatge automàtic i IA, AlpinaShop passa de descriure a predir i automatitzar. Començarem per 05-01, Vertex AI, la plataforma que unifica tot el cicle de vida del model —dades, entrenament, avaluació, desplegament i monitoratge— i que connectarà directament amb el dataset alpinashop_analitica que acabes de governar. Després arribaran AutoML per entrenar sense escriure codi, TensorFlow per quan calgui control total, les API de llenguatge natural i de visió que responen a les preguntes de les ressenyes i de les imatges sense entrenar res, la IA generativa amb Gemini per a les descripcions, i MLOps amb Vertex AI Pipelines perquè un model no sigui un experiment al portàtil d'algú sinó un sistema de producció amb la mateixa disciplina d'idempotència, qualitat, llinatge i cost que has aplicat en tot aquest mòdul.
Les dades ja són netes, governades, documentades i consultables. Això no era l'objectiu: era el requisit. Ara comença el que és interessant.
Curs de Google Cloud Platform (GCP)
Mòdul 1: Introducció a Google Cloud Platform
- Què és Google Cloud Platform?
- Configuració del teu compte de GCP
- Descripció general de la consola de GCP
- Projectes, jerarquia de recursos i facturació
- Regions, zones i model de responsabilitat compartida
- Cloud Shell i la CLI de gcloud
Mòdul 2: Serveis principals de GCP
- Compute Engine: màquines virtuals a Google Cloud
- Cloud Storage: emmagatzematge d'objectes
- Cloud SQL: bases de dades relacionals gestionades
- App Engine: plataforma com a servei
- Google Kubernetes Engine (GKE)
- Bases de dades NoSQL: Firestore, Bigtable i Spanner
- Com triar el servei de còmput adequat
Mòdul 3: Xarxes i seguretat
- Xarxes VPC
- Balanceig de càrrega al núvol
- Cloud CDN
- Gestió d'identitat i accés (IAM)
- Cloud Armor
- Secrets i xifratge: Secret Manager i Cloud KMS
- Cloud DNS, certificats TLS i publicació segura de serveis
Mòdul 4: Dades i anàlisi
- BigQuery: el magatzem de dades analític
- Cloud Dataflow: processament de dades per lots i en temps real
- Cloud Dataproc: Spark i Hadoop gestionats
- Cloud Pub/Sub: missatgeria asíncrona
- Cloud Data Fusion: integració de dades sense codi
- Orquestració de pipelines amb Cloud Composer i Workflows
- Govern de les dades i taulers amb Dataplex i Looker Studio
Mòdul 5: Aprenentatge automàtic i IA
- Vertex AI: la plataforma d'aprenentatge automàtic de GCP
- AutoML: models a mida sense escriure codi
- TensorFlow a GCP: entrenament i servei de models
- API de llenguatge natural
- API de visió
- IA generativa a Vertex AI: models Gemini i incrustacions
- MLOps: del model al producte amb Vertex AI Pipelines
Mòdul 6: DevOps i monitoratge
- Cloud Build: integració contínua a GCP
- Cloud Source Repositories i gestió del codi font
- Cloud Functions: funcions sense servidor
- Cloud Monitoring (abans Stackdriver): mètriques, taulers i alertes
- Cloud Deployment Manager i infraestructura com a codi nativa
- Cloud Logging i Cloud Trace: registres, traces i diagnòstic
- Terraform a GCP: infraestructura com a codi a la pràctica
Mòdul 7: Temes avançats de GCP
- Híbrid i multinúvol amb Anthos
- Computació sense servidor amb Cloud Run
- Xarxes avançades: VPC compartida, aparellament i connectivitat híbrida
- Bones pràctiques de seguretat
- Gestió i optimització de costos
- Fiabilitat: SLO, alta disponibilitat i recuperació de desastres
- Govern a escala: organització, polítiques i auditoria
