chore: auto-commit (26 archivos)
- python/functions/bigquery/bq_auth.md - python/functions/bigquery/bq_load_from_file.md - python/functions/bigquery/bq_load_from_gcs.md - python/functions/bigquery/client.py - python/functions/bigquery/queries.py - python/functions/datascience/__init__.py - python/functions/datascience/decode_qr_image.py - python/functions/datascience/load_bq_table_to_duckdb.md - python/functions/datascience/load_bq_table_to_duckdb.py - python/functions/pipelines/profile_bq_table.md - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
---
|
||||
name: profile_bq_dataset
|
||||
kind: pipeline
|
||||
lang: py
|
||||
domain: pipelines
|
||||
purity: impure
|
||||
version: "1.1.0"
|
||||
signature: "def profile_bq_dataset(project_id: str, dataset: str, tables: list = None, include_views: bool = False, sample_frac: float = None, max_rows: int = 0, pseudonymize_cols: dict = None, report_dir: str = \"reports\", duckdb_path: str = \"\", keep_duckdb: bool = True, min_inclusion: float = 0.9, emit_pdf: bool = True, run_llm: bool = False) -> dict"
|
||||
description: "EDA one-shot de un dataset BigQuery ENTERO con descubrimiento cross-tabla: materializa CADA tabla del dataset (COMPLETA por defecto; muestreo opt-in con sample_frac; seudonimizacion PII por tabla, LOPDGDD/RGPD) en UN MISMO DuckDB compartido con load_bq_table_to_duckdb, lo perfila entero con profile_database (perfiles por tabla + relaciones FK inter-tabla por containment + join graph Mermaid + report markdown/JSON + PDF movil), y construye el diccionario de columnas del dataset con build_column_dictionary. Es el analogo BigQuery de profile_database a nivel de dataset, resuelto por composicion estricta (list_bq_dataset_tables -> load_bq_table_to_duckdb x N -> profile_database -> build_column_dictionary) sin duplicar descubrimiento, perfilado ni inferencia de relaciones. Es el hazme un EDA de este dataset BigQuery entero y descubre como se relacionan sus tablas, en una sola llamada."
|
||||
tags: [eda, bigquery, relations, launcher]
|
||||
uses_functions:
|
||||
- list_bq_dataset_tables_py_datascience
|
||||
- load_bq_table_to_duckdb_py_datascience
|
||||
- profile_database_py_pipelines
|
||||
- build_column_dictionary_py_datascience
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: error_go_core
|
||||
imports: []
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "python/functions/pipelines/profile_bq_dataset.py"
|
||||
params:
|
||||
- name: project_id
|
||||
desc: "Proyecto GCP (facturacion + primer segmento del FQN). Ej: 'autingo-159109'."
|
||||
- name: dataset
|
||||
desc: "Dataset BigQuery a perfilar entero. Ej: 'customer_marts'."
|
||||
- name: tables
|
||||
desc: "Lista de NOMBRES de tabla del dataset. None (DEFAULT) = todas las del dataset (filtradas por include_views)."
|
||||
- name: include_views
|
||||
desc: "Si True incluye las VIEW ademas de las BASE TABLE cuando tables=None. Default False (solo BASE TABLE, coherente con profile_database que salta las VIEWs)."
|
||||
- name: sample_frac
|
||||
desc: "None (DEFAULT) = FULL, perfila TODAS las filas de cada tabla. Un float en (0,1) activa el muestreo opt-in por tabla (`WHERE rand() < frac`)."
|
||||
- name: max_rows
|
||||
desc: "Tope duro de filas por tabla (LIMIT). 0 (DEFAULT) = sin tope. Se aplica a cada tabla materializada."
|
||||
- name: pseudonymize_cols
|
||||
desc: "Dict {\"tabla\": [\"col1\", \"col2\"]} de columnas PII a seudonimizar (hash) por tabla ANTES de materializar (LOPDGDD/RGPD [POL-MMNSEG-001-1.0]). Preserva nulos y cardinalidad."
|
||||
- name: report_dir
|
||||
desc: "Directorio de salida de los reports + del DuckDB compartido por defecto. Default 'reports' (artefacto local gitignored). Se crea si no existe."
|
||||
- name: duckdb_path
|
||||
desc: "Ruta del DuckDB compartido donde se materializan todas las tablas. Vacio (DEFAULT) = report_dir/eda_bq_<dataset>.duckdb (se limpia si ya existia)."
|
||||
- name: keep_duckdb
|
||||
desc: "Si True (DEFAULT) conserva el DuckDB materializado: es el artefacto explorable post-EDA (notebook Jupyter, joins ad-hoc). Con False se borra al terminar."
|
||||
- name: min_inclusion
|
||||
desc: "Umbral de inclusion (0-1) para emitir una FK candidata cross-tabla (se pasa a profile_database -> infer_fk_containment_duckdb). Default 0.9."
|
||||
- name: emit_pdf
|
||||
desc: "Si True (DEFAULT) emite el PDF movil DB-level (resumen de tablas + relaciones FK + join graph). Se pasa a profile_database."
|
||||
- name: run_llm
|
||||
desc: "Si True (default False) activa la capa LLM interpretativa por tabla (se pasa a profile_database -> profile_table): una llamada LLM por tabla sobre el perfil agregado, nunca filas crudas."
|
||||
output: "dict dict-no-throw. En exito {status:'ok', project_id, dataset, n_tables_loaded, n_tables_profiled, tables_skipped:[...], errors:[...], duckdb_path, db_profile:<DatabaseProfile con tables[resumen], table_profiles[completos], fk_candidates, join_graph{nodes,edges,mermaid,hubs}>, column_dictionary:{entries,pii_columns} (sin markdown), report_md_path, report_json_path, report_pdf_path, dict_md_path, dict_json_path}. En error {status:'error', error, stage}."
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
from pipelines.profile_bq_dataset import profile_bq_dataset
|
||||
|
||||
# FULL por defecto: EDA del dataset ENTERO (todas las tablas, todas las filas),
|
||||
# con FK cross-tabla + join graph + diccionario de columnas. El DuckDB compartido
|
||||
# queda en reports/eda_bq_customer_marts.duckdb para seguir explorando.
|
||||
r = profile_bq_dataset("autingo-159109", "customer_marts")
|
||||
print(r["n_tables_loaded"], "tablas materializadas,", r["n_tables_profiled"], "perfiladas")
|
||||
print("FKs:", [f"{fk['from_table']}.{fk['from_col']}->{fk['to_table']}.{fk['to_col']}"
|
||||
for fk in r["db_profile"]["fk_candidates"]])
|
||||
print(r["report_md_path"]); print(r["report_pdf_path"]); print(r["dict_md_path"])
|
||||
print("DuckDB explorable:", r["duckdb_path"])
|
||||
|
||||
# Dataset con tablas enormes: muestreo opt-in + PII seudonimizada por tabla.
|
||||
r = profile_bq_dataset(
|
||||
"autingo-159109",
|
||||
"customer_marts",
|
||||
sample_frac=0.05,
|
||||
pseudonymize_cols={
|
||||
"customer_profile": ["document_number", "full_name", "email", "phone"],
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando pidan un EDA de un DATASET BigQuery entero y no solo de una tabla: quieres
|
||||
el perfil de todas sus tablas MAS su esquema relacional (que tabla referencia a
|
||||
cual, con que cardinalidad) descubierto cross-tabla en una sola llamada. Es el
|
||||
escalon a nivel de dataset sobre `profile_bq_table` (una tabla) y el adaptador
|
||||
BigQuery de `profile_database` (una base DuckDB). Usala al recibir un dataset
|
||||
BigQuery desconocido, para documentar un data mart, para descubrir el star schema
|
||||
(las tablas hub del join graph) o antes de escribir joins sin tener el modelo
|
||||
declarado. Para datasets con tablas enormes, pasa `sample_frac` o `max_rows` y
|
||||
dejalo declarado en el report.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Impura: requiere ADC de BigQuery configurado (Application Default Credentials).
|
||||
Si el ADC del usuario lleva un quota project ajeno, `load_bq_table_to_duckdb` /
|
||||
`list_bq_dataset_tables` aplican `creds.with_quota_project(None)` para evitar el
|
||||
403 USER_PROJECT_DENIED — remitido a los gotchas de esas funciones.
|
||||
- Coste de traer un DATASET entero: FULL por defecto materializa TODAS las filas
|
||||
de CADA tabla a RAM (via BigQuery Storage Read API/Arrow) antes de volcar al
|
||||
DuckDB compartido. Un dataset con varias tablas de millones de filas puede
|
||||
costar en tiempo, bytes escaneados de BigQuery y GBs de RAM/disco. Acota con
|
||||
`sample_frac` in (0,1) (muestreo opt-in por tabla) o `max_rows` (tope duro por
|
||||
tabla). Si por limite de recursos no cabe el total, dilo explicito en el report
|
||||
con el maximo que si se cargo.
|
||||
- El DuckDB compartido puede ocupar GBs: todas las tablas del dataset viven en un
|
||||
MISMO archivo (necesario para que la inferencia de FK opere cross-tabla). Con
|
||||
`keep_duckdb=True` (default) queda en disco como artefacto explorable; pasa
|
||||
`keep_duckdb=False` para borrarlo al terminar. Con `duckdb_path` explicito la
|
||||
ruta se respeta; el path por defecto se limpia al inicio para no mezclar tablas
|
||||
de corridas anteriores.
|
||||
- FK por containment es una HEURISTICA (falsos positivos/negativos posibles) y
|
||||
`profile_database` SALTA los pares de FK hacia tablas con mas de 200k filas (el
|
||||
lado caro del INTERSECT): esas relaciones quedan sin evaluar. Es un mapa de
|
||||
partida del esquema, no un DDL autoritativo.
|
||||
- Vistas excluidas por defecto (`include_views=False`, coherente con
|
||||
profile_database que salta VIEWs — perfilarlas infla n_tables y multiplica FK
|
||||
falsas). Pasa `include_views=True` solo si necesitas perfilarlas como si fueran
|
||||
tablas materializadas.
|
||||
- Seudonimiza PII con `pseudonymize_cols` (dict por tabla) para cumplir LOPDGDD/
|
||||
RGPD [POL-MMNSEG-001-1.0] ANTES de escribir a disco: nombres, DNI/NIE, email,
|
||||
telefono, direccion, IDs de cliente, IBAN, etc. Sin seudonimizar, el DuckDB
|
||||
compartido + los reports contienen datos personales reales.
|
||||
- Tolera fallos por tabla: si una carga falla, se anota en `errors[]` +
|
||||
`tables_skipped[]` y el pipeline sigue con las demas; `n_tables_profiled` cuenta
|
||||
solo las perfiladas con exito. Revisa `errors` para saber que quedo fuera.
|
||||
- Escribe a `report_dir` (default 'reports', artefacto local gitignored): el report
|
||||
DB-level de `profile_database` (markdown + JSON + PDF si emit_pdf) MAS el
|
||||
diccionario de columnas (`..._dict.md` + `..._dict.json`).
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- v1.1.0 (2026-07-02) — añade `run_llm` (passthrough a profile_database -> profile_table: una llamada LLM por tabla sobre el perfil agregado). Default False, sin breaking changes.
|
||||
Reference in New Issue
Block a user