Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Kanál může obsahovat více toků, které jsou téměř identické a liší se pouze několika parametry. Definování těchto toků je explicitně náchylné k chybám, redundantní a obtížně se udržuje. Metaprogramování pomocí Python vnitřních funkcí generuje opakující se toky dynamicky, přičemž každé vyvolání poskytuje jinou sadu parametrů.
Přehled metaprogramování
Metaprogramování v deklarativních potrubí Lakeflow Spark používá vnitřní funkce Pythonu. Vzhledem k tomu, že tyto funkce jsou vyhodnocovány s odkladem při běhu kanálu, můžete zabalit @dp.table dekorátory uvnitř tovární funkce a volat tuto továrnu vícekrát s různými argumenty. Každé volání zaregistruje nový tok bez duplikování kódu.
Více informací o používání for smyček s deklarativními kanály Lakeflow Spark najdete v části Vytváření tabulek ve smyčcefor.
Příklad: Doby odezvy hasičského sboru
Následující příklad používá integrovanou datovou sadu hasičského sboru k vyhledání sousedství s nejrychlejší dobou odezvy tísňového volání pro každý typ volání. Bez metaprogramování musíte napsat téměř identické definice tabulky pro každý typ volání (Alarmy, Požár struktury, Lékařský incident). Při metaprogramování vygeneruje jedna tovární funkce všechny.
Krok 1: Definování nezpracované tabulky příjmu dat
import functools
from pyspark import pipelines as dp
from pyspark.sql.functions import *
@dp.table(
name="raw_fire_department",
comment="raw table for fire department response"
)
@dp.expect_or_drop("valid_received", "received IS NOT NULL")
@dp.expect_or_drop("valid_response", "responded IS NOT NULL")
@dp.expect_or_drop("valid_neighborhood", "neighborhood != 'None'")
def get_raw_fire_department():
return (
spark.read.format('csv')
.option('header', 'true')
.option('multiline', 'true')
.load('/databricks-datasets/timeseries/Fires/Fire_Department_Calls_for_Service.csv')
.withColumnRenamed('Call Type', 'call_type')
.withColumnRenamed('Received DtTm', 'received')
.withColumnRenamed('Response DtTm', 'responded')
.withColumnRenamed('Neighborhooods - Analysis Boundaries', 'neighborhood')
.select('call_type', 'received', 'responded', 'neighborhood')
)
Krok 2: Definování funkce toku továrny
Funkce generate_tables továrny registruje dvě tabulky pro každý typ volání: filtrovanou tabulku volání a seřazenou tabulku doby odezvy. Obě jsou vytvořeny jako vnitřní funkce dekorované s @dp.table.
all_tables = []
def generate_tables(call_table, response_table, filter):
@dp.table(
name=call_table,
comment="top level tables by call type"
)
def create_call_table():
return spark.sql("""
SELECT
unix_timestamp(received,'M/d/yyyy h:m:s a') as ts_received,
unix_timestamp(responded,'M/d/yyyy h:m:s a') as ts_responded,
neighborhood
FROM raw_fire_department
WHERE call_type = '{filter}'
""".format(filter=filter))
@dp.table(
name=response_table,
comment="top 10 neighborhoods with fastest response time"
)
def create_response_table():
return spark.sql("""
SELECT
neighborhood,
AVG((ts_received - ts_responded)) as response_time
FROM {call_table}
GROUP BY 1
ORDER BY response_time
LIMIT 10
""".format(call_table=call_table))
all_tables.append(response_table)
Krok 3: Vyvolání továrny a definování souhrnné tabulky
Zavolejte továrnu jednou pro každý typ volání a pak definujte souhrnnou tabulku, která sjednocuje výsledky a vyhledá okolí, která se nejčastěji zobrazují napříč všemi kategoriemi.
generate_tables("alarms_table", "alarms_response", "Alarms")
generate_tables("fire_table", "fire_response", "Structure Fire")
generate_tables("medical_table", "medical_response", "Medical Incident")
@dp.table(
name="best_neighborhoods",
comment="which neighbor appears in the best response time list the most"
)
def summary():
target_tables = [dp.read(t) for t in all_tables]
unioned = functools.reduce(lambda x, y: x.union(y), target_tables)
return (
unioned.groupBy(col("neighborhood"))
.agg(count("*").alias("score"))
.orderBy(desc("score"))
)
Poté, co spustíte tento pipeline, vytvoříte sadu podobných tabulek, jako v tomto grafu:
Klíčové koncepty
-
Vnitřní funkce jsou opožděně zaregistrovány:
@dp.tableDekorátor nespustí funkci okamžitě. Zaregistruje funkci v pipeline runtime, který před zahájením spuštění provede kompletní zpracování grafu toku dat. -
Uzavření zachycuje parametry: Každá vnitřní funkce se zavře nad parametry předanými do továrny (
call_table,response_table,filter), takže každý registrovaný tok používá svou vlastní izolovanou sadu hodnot. -
Dynamické seznamy tabulek: Použitím seznamu, jako je
all_tables, ke sledování názvů tabulek generovaných programově je pozdější odkazování na ně snadné (například ve sjednocení nebo spojení).