@@ -97,13 +97,15 @@ data:
9797 A layered ELT + Spark pipeline that produces cross-engine lineage in Marquez:
9898
9999 tpch.tiny.customer ─┐
100- ├─(Trino)─> lakehouse.demo.customer_orders ─(Spark)─> lakehouse.demo.orders_by_nation
101- tpch.tiny.orders ──┘
100+ ├─(Trino)─> lakehouse.demo.customer_orders ─┐
101+ tpch.tiny.orders ──┘ ├─(Spark join)─> lakehouse.demo.orders_by_nation
102+ tpch.tiny.nation ──(Trino)─> lakehouse.demo.nation ───────────┘
102103
103104 The Trino steps read from the built-in `tpch` catalog and write Iceberg tables into the
104105 `lakehouse` catalog (shared hive-iceberg metastore + MinIO). The final step submits a Spark job
105- that reads `lakehouse.demo.customer_orders` and writes `lakehouse.demo.orders_by_nation` into the
106- *same* Iceberg catalog.
106+ that JOINS `lakehouse.demo.customer_orders` with the `lakehouse.demo.nation` dimension and writes
107+ `lakehouse.demo.orders_by_nation` into the *same* Iceberg catalog. The two-input Spark join is
108+ reported by OpenLineage as a fan-in lineage node (both source tables feed the output).
107109
108110 The single, connected end-to-end graph is the *Airflow* one: Airflow is one producer and names
109111 every dataset consistently, and the Spark step is stitched in by declaring its I/O under the same
@@ -379,6 +381,19 @@ data:
379381 ),
380382 )
381383
384+ # Nation dimension: the second input to the Spark join. Kept as its own load step (same
385+ # single-statement CREATE OR REPLACE pattern as the others) so it is an independent lineage
386+ # source that fans into the Spark job alongside customer_orders.
387+ load_nation = SQLExecuteQueryOperator(
388+ task_id="load_nation",
389+ conn_id="trino_default",
390+ sql=(
391+ "CREATE OR REPLACE TABLE lakehouse.demo.nation AS "
392+ "SELECT nationkey, name AS nation_name, regionkey "
393+ "FROM tpch.tiny.nation"
394+ ),
395+ )
396+
382397 customer_orders = SQLExecuteQueryOperator(
383398 task_id="customer_orders",
384399 conn_id="trino_default",
@@ -410,11 +425,16 @@ data:
410425 task_id="spark_orders_by_nation",
411426 namespace=namespace,
412427 application_file=build_spark_application(spark_app_name, namespace),
413- openlineage_inputs=[(trino_ol_namespace, "lakehouse.demo.customer_orders")],
428+ openlineage_inputs=[
429+ (trino_ol_namespace, "lakehouse.demo.customer_orders"),
430+ (trino_ol_namespace, "lakehouse.demo.nation"),
431+ ],
414432 openlineage_outputs=[(trino_ol_namespace, "lakehouse.demo.orders_by_nation")],
415433 )
416434
417- create_schema >> [load_customers, load_orders] >> customer_orders >> spark_orders_by_nation
435+ create_schema >> [load_customers, load_orders, load_nation]
436+ [load_customers, load_orders] >> customer_orders
437+ [customer_orders, load_nation] >> spark_orders_by_nation
418438 ---
419439apiVersion : v1
420440kind : Secret
0 commit comments