feat: Trino federation + Hadoop external tables + LLM data catalog
Trino Federation tab (3 sub-views): - Federated: catalog landscape + a single cross-source SQL that joins PostgreSQL + MySQL + MongoDB (region scorecard) — the federation proof, computed in the background and cached (large full scans take ~2 min). - Hadoop Lake: all federated business data materialized as external Iceberg tables on HDFS (iceberg.hadoop.*_ext, ~120k rows each) with live, fast business analytics (revenue by region/channel, top customers, HR by department, supply by type, telemetry averages). Includes a one-click "rebuild external tables" job. - Data Dictionary: every business table + column with masked / visible PII badges and categories. Backend trino_federated.py: /catalogs, /marquee(+refresh), /lake, /materialize(+status), /dictionary. Name-based PII detection flags raw PII in derived/lake tables as visible vs physically-masked curated layer. LLM context: platform_context now emits a full BUSINESS DATA CATALOG section (tables, columns, types, source row counts, federated scorecard) with exact per-column masked/visible status, so the assistant knows the data in detail and what is masked vs not.
This commit is contained in:
+72
-1
@@ -132,13 +132,84 @@ def build_masking_section() -> str:
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def build_business_data_section() -> str:
|
||||
"""Detailed inventory of the actual business data — tables, columns, types,
|
||||
row counts and per-column masked/visible status — so the assistant knows the
|
||||
data in detail and exactly what is masked vs not."""
|
||||
lines: list[str] = ["=== BUSINESS DATA CATALOG (live, every detail) ==="]
|
||||
|
||||
# source row totals (cheap estimates)
|
||||
try:
|
||||
import sql_console as s
|
||||
totals = {
|
||||
"PostgreSQL sales_orders": s._table_row_count("postgres", "public.sales_orders"),
|
||||
"MySQL employee_events": s._table_row_count("mysql", "hr.employee_events"),
|
||||
"MongoDB supplychain.events": s._table_row_count("mongodb", "supplychain.events"),
|
||||
}
|
||||
lines.append("Source volumes (live row counts):")
|
||||
for k, v in totals.items():
|
||||
lines.append(f" - {k}: {v:,} rows" if isinstance(v, int) else f" - {k}: ~")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# full column dictionary + masking per column
|
||||
try:
|
||||
from trino_federated import build_dictionary
|
||||
d = build_dictionary()
|
||||
summ = d.get("summary", {})
|
||||
lines.append(
|
||||
f"Catalogued tables: {summ.get('tables', 0)} — columns: {summ.get('columns', 0)}, "
|
||||
f"PII columns: {summ.get('pii_columns', 0)} ({summ.get('masked_columns', 0)} masked)."
|
||||
)
|
||||
for t in d.get("tables", []):
|
||||
lines.append(f"\n{t['engine']} · {t['fqn']} — {t['desc']}")
|
||||
for c in t.get("columns", []):
|
||||
flag = ""
|
||||
if c.get("masked"):
|
||||
flag = f" [MASKED · {c.get('category')}]"
|
||||
elif c.get("pii"):
|
||||
flag = f" [PII visible · {c.get('category')}]"
|
||||
lines.append(f" · {c['name']} ({c['type']}){flag}")
|
||||
except Exception as exc:
|
||||
lines.append(f"(data dictionary unavailable: {exc})")
|
||||
|
||||
# federated cross-source marquee (region scorecard), if computed
|
||||
try:
|
||||
from trino_federated import _marquee, _load_marquee
|
||||
if _marquee.get("data") is None:
|
||||
_load_marquee()
|
||||
m = _marquee.get("data")
|
||||
if m and m.get("rows"):
|
||||
lines.append("\nFederated region scorecard (one Trino SQL across PostgreSQL+MySQL+MongoDB):")
|
||||
for r in m["rows"][:8]:
|
||||
rev = r.get("revenue")
|
||||
rev_s = f"€{rev:,.0f}" if isinstance(rev, (int, float)) else "?"
|
||||
lines.append(
|
||||
f" - {r.get('region')}: orders={r.get('orders')}, revenue={rev_s}, "
|
||||
f"hr_events={r.get('hr_events')}, supply_events={r.get('supply_events')}"
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
lines.append(
|
||||
"\nData is also materialized into the Hadoop lake as external Iceberg tables "
|
||||
"(iceberg.hadoop.*_ext) and exposed through one federated Trino engine "
|
||||
"(catalogs: postgres_sales, mysql_hr, mongodb_supplychain, cassandra_telemetry, iceberg, kafka)."
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def build_llm_addendum() -> str:
|
||||
try:
|
||||
platform = build_platform_section()
|
||||
except Exception as exc:
|
||||
platform = f"(platform section error: {exc})"
|
||||
try:
|
||||
business = build_business_data_section()
|
||||
except Exception as exc:
|
||||
business = f"(business data section error: {exc})"
|
||||
try:
|
||||
masking = build_masking_section()
|
||||
except Exception as exc:
|
||||
masking = f"(masking section error: {exc})"
|
||||
return "\n\n".join([platform, masking])
|
||||
return "\n\n".join([platform, business, masking])
|
||||
|
||||
Reference in New Issue
Block a user