<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vikneshwara R B</title>
    <description>The latest articles on DEV Community by Vikneshwara R B (@vikneshwara_r_b).</description>
    <link>https://dev.to/vikneshwara_r_b</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4176999%2Ff085df7e-72b5-4f88-9075-782991de8348.JPG</url>
      <title>DEV Community: Vikneshwara R B</title>
      <link>https://dev.to/vikneshwara_r_b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vikneshwara_r_b"/>
    <language>en</language>
    <item>
      <title>One Glue Job, Zero Orchestrators — My First Spark Declarative Pipeline on AWS Glue</title>
      <dc:creator>Vikneshwara R B</dc:creator>
      <pubDate>Mon, 12 Oct 2026 03:24:50 +0000</pubDate>
      <link>https://dev.to/aws-builders/one-glue-job-zero-orchestrators-my-first-spark-declarative-pipeline-on-aws-glue-bn2</link>
      <guid>https://dev.to/aws-builders/one-glue-job-zero-orchestrators-my-first-spark-declarative-pipeline-on-aws-glue-bn2</guid>
      <description>&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;This is an independent, personal write-up — not official AWS content, and not&lt;br&gt;
endorsed by or affiliated with AWS. It documents a hobby project built while&lt;br&gt;
learning &lt;a href="https://aws.amazon.com/blogs/big-data/build-declarative-etl-pipelines-with-aws-glue-6-0/" rel="noopener noreferrer"&gt;AWS Glue 6.0's Spark Declarative Pipelines&lt;/a&gt;,&lt;br&gt;
following the walkthrough in that official AWS Big Data blog post. All opinions&lt;br&gt;
below are my own.&lt;/p&gt;

&lt;p&gt;I've tried to explain every piece of jargon the first time it shows up, so if you're&lt;br&gt;
new to data engineering or to AWS Glue, you should be able to follow this end to&lt;br&gt;
end. No prior Glue or Spark experience assumed.&lt;/p&gt;
&lt;h2&gt;
  
  
  The problem, in plain terms
&lt;/h2&gt;

&lt;p&gt;Imagine you need to process data in three steps: clean it up, validate it, then&lt;br&gt;
summarize it for a report. Easy enough on its own. Now imagine step 2 must &lt;em&gt;never&lt;/em&gt;&lt;br&gt;
start before step 1 finishes, and if step 2 fails halfway through, you don't want to&lt;br&gt;
redo all of step 1's work. And now imagine you have to add a step 4 next month.&lt;/p&gt;

&lt;p&gt;That coordination problem — making sure things run in the right order, handling&lt;br&gt;
retries, not redoing work that already succeeded — is called &lt;strong&gt;orchestration&lt;/strong&gt;. It's&lt;br&gt;
not the interesting part of a data pipeline. It's the part you &lt;em&gt;have&lt;/em&gt; to get right&lt;br&gt;
so the interesting part (the actual data transformations) works reliably.&lt;/p&gt;

&lt;p&gt;The classic way to structure a pipeline like this is the &lt;strong&gt;medallion architecture&lt;/strong&gt;:&lt;br&gt;
raw data comes in as &lt;strong&gt;bronze&lt;/strong&gt; (untouched, as-is — think raw ore), gets cleaned and&lt;br&gt;
validated into &lt;strong&gt;silver&lt;/strong&gt; (refined metal), and finally gets aggregated into &lt;strong&gt;gold&lt;/strong&gt;&lt;br&gt;
(the finished product, ready for a dashboard or report). It's a great mental model.&lt;br&gt;
The part that quietly gets expensive is everything &lt;em&gt;around&lt;/em&gt; it: three separate jobs,&lt;br&gt;
an orchestrator (like AWS Step Functions or Apache Airflow) wiring them together in&lt;br&gt;
order, retry logic at every stage, and bookkeeping so a partial failure doesn't force&lt;br&gt;
you to reprocess everything from scratch. None of that is business logic. It's&lt;br&gt;
plumbing that exists purely to make sure step 2 waits for step 1.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AWS's own blog post has a diagram of exactly this shape — three separate AWS Glue jobs wired together by an Amazon MWAA DAG:&lt;br&gt;
&lt;a href="https://aws.amazon.com/blogs/big-data/build-declarative-etl-pipelines-with-aws-glue-6-0/" rel="noopener noreferrer"&gt;"Three AWS Glue Jobs with orchestration running in Amazon MWAA"&lt;/a&gt;,&lt;br&gt;
from &lt;em&gt;Build declarative ETL pipelines with AWS Glue 6.0&lt;/em&gt; (AWS Big Data Blog). Here's my own version of that same idea:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fctbkxdk0avk4thnj4815.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fctbkxdk0avk4thnj4815.png" alt="Three Glue jobs orchestrated by Amazon MWAA" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Enter "declarative" pipelines
&lt;/h2&gt;

&lt;p&gt;You've probably used something declarative before without calling it that. When you&lt;br&gt;
write a SQL &lt;code&gt;SELECT&lt;/code&gt; query, you don't tell the database &lt;em&gt;how&lt;/em&gt; to fetch and join the&lt;br&gt;
rows step by step — you describe &lt;em&gt;what&lt;/em&gt; result you want, and the database figures&lt;br&gt;
out the how. That's the declarative idea: say what you want, not the steps to get&lt;br&gt;
there. (The opposite — a loop that manually fetches, filters, and combines rows&lt;br&gt;
yourself — is called &lt;em&gt;imperative&lt;/em&gt;: you spell out every step.)&lt;/p&gt;

&lt;p&gt;AWS Glue 6.0 brings that same idea to entire pipelines, through a feature called&lt;br&gt;
&lt;strong&gt;Spark Declarative Pipelines (SDP)&lt;/strong&gt;. Worth knowing: this is an Apache Spark 4.1&lt;br&gt;
feature, not something AWS invented just for Glue — AWS Glue 6.0 just ships the&lt;br&gt;
Spark version that includes it.&lt;/p&gt;

&lt;p&gt;With SDP, you write code that says "&lt;code&gt;silver_orders&lt;/code&gt; is bronze_orders, cleaned up&lt;br&gt;
this way" and "&lt;code&gt;gold_sales_summary&lt;/code&gt; is &lt;code&gt;silver_orders&lt;/code&gt;, aggregated this way." You&lt;br&gt;
never write "run bronze, then silver, then gold." The engine reads those table&lt;br&gt;
references in your code, works out that silver depends on bronze (because your&lt;br&gt;
silver code literally reads from the bronze table), and runs everything in the&lt;br&gt;
correct order automatically — as &lt;strong&gt;one single Glue job&lt;/strong&gt;, not three jobs stitched&lt;br&gt;
together by an orchestrator.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;And the "after" picture from the same post:&lt;br&gt;
&lt;a href="https://aws.amazon.com/blogs/big-data/build-declarative-etl-pipelines-with-aws-glue-6-0/" rel="noopener noreferrer"&gt;"AWS Glue 6.0 - Spark Declarative Pipeline (single job)"&lt;/a&gt; —&lt;br&gt;
the same bronze/silver/gold flow, collapsed into one job, with the caption &lt;em&gt;"SDP resolves dependency order automatically — no DAG wiring needed."&lt;/em&gt; That line is the whole pitch, honestly. My own version of that picture:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4np4qqbfqyadvipmlzhq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4np4qqbfqyadvipmlzhq.png" alt="One Glue job, SDP resolves dependency order automatically" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I built a small project around the walkthrough in AWS's own blog post to see what&lt;br&gt;
this actually feels like end to end, including the infrastructure-as-code side&lt;br&gt;
(using AWS CDK, a tool for defining cloud infrastructure in regular code instead of&lt;br&gt;
clicking through the AWS console) that the original post doesn't cover. The repo is&lt;br&gt;
here if you want to follow along or just skim the code:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://github.com/vikneshwara-r-b/glue-sdp-demo" rel="noopener noreferrer"&gt;github.com/vikneshwara-r-b/glue-sdp-demo&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  What SDP actually does for you
&lt;/h2&gt;

&lt;p&gt;A pipeline is just a small YAML file (&lt;code&gt;spark-pipeline.yml&lt;/code&gt;, think of it as the&lt;br&gt;
pipeline's table of contents) plus your SQL/Python transformation code. From those,&lt;br&gt;
SDP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;figures out the dependency order from table references in your code (e.g. a line
like &lt;code&gt;spark.readStream.table("bronze_orders")&lt;/code&gt; tells it silver needs bronze first)
— you never draw this graph by hand;&lt;/li&gt;
&lt;li&gt;runs independent parts in parallel when it can;&lt;/li&gt;
&lt;li&gt;keeps track of &lt;strong&gt;checkpoints&lt;/strong&gt; (a bookmark of "which data have I already
processed") for tables that update incrementally, so a rerun doesn't redo
everything;&lt;/li&gt;
&lt;li&gt;registers every output table in the Glue Data Catalog (AWS's metadata store — the
thing that lets tools like Athena find and query your tables by name) as soon as
it's created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are three kinds of tables you can define, and picking the right one matters&lt;br&gt;
more than it sounds like it should:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Streaming table&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only processes &lt;em&gt;new&lt;/em&gt; data since last time&lt;/td&gt;
&lt;td&gt;ingesting files as they arrive, change-tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Materialized view&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Recomputes completely, every single run&lt;/td&gt;
&lt;td&gt;summaries, aggregations, reports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Temporary view&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Exists only during the run, never saved&lt;/td&gt;
&lt;td&gt;a quick intermediate step, like a scratch variable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  The pipeline I built: orders, bronze to gold
&lt;/h2&gt;

&lt;p&gt;The demo reads order CSV files from S3 (object storage — think of it as a folder&lt;br&gt;
that lives in the cloud) and produces three tables, all from one Glue job:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdqn88z3nlry28ish2k6r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdqn88z3nlry28ish2k6r.png" alt="Orders ER diagram" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;bronze_orders&lt;/code&gt;&lt;/strong&gt; (streaming table) — the raw CSV, every single column kept as
plain text, no cleanup at all. It's a streaming table on purpose: new order files
should be picked up incrementally as they land, not reprocessed from scratch every
time the job runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;silver_orders&lt;/code&gt;&lt;/strong&gt; (streaming table) — same data, but now typed properly (amounts
become actual numbers, timestamps become actual timestamps), filtered down to only
completed orders with a positive amount, and with a new &lt;code&gt;amount_band&lt;/code&gt; column
(small/medium/large) added.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;gold_sales_summary&lt;/code&gt;&lt;/strong&gt; (a SQL &lt;strong&gt;materialized view&lt;/strong&gt;, not a streaming table) —
order count, total sales, and average order value, grouped by region. This one's a
materialized view on purpose: it's a pure aggregation, and since materialized
views always fully recompute anyway, there's no incremental benefit being given up
here — it's just the right tool for this specific job.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the bit of code I'd flag if you're following along and writing your own&lt;br&gt;
streaming table, because it's easy to get subtly wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pyspark&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pipelines&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pyspark.sql&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SparkSession&lt;/span&gt;

&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_streaming_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;silver_orders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@dp.append_flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;silver_orders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ingest_silver_orders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;spark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SparkSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# readStream.table, not spark.table -- otherwise every run reprocesses
&lt;/span&gt;    &lt;span class="c1"&gt;# bronze's entire history into silver instead of just what's new.
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;spark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bronze_orders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;dp.create_streaming_table()&lt;/code&gt; paired with &lt;code&gt;@dp.append_flow(target=...)&lt;/code&gt; is the&lt;br&gt;
actual, documented Python API for a streaming table in AWS Glue's docs. You'll see&lt;br&gt;
a simpler-looking &lt;code&gt;@dp.table&lt;/code&gt; decorator mentioned informally in some write-ups&lt;br&gt;
(including the original blog post's prose) — that's not the syntax Glue's own&lt;br&gt;
developer guide specifies, so I stuck with the documented one.&lt;/p&gt;
&lt;h2&gt;
  
  
  The infrastructure side (not covered in the original post)
&lt;/h2&gt;

&lt;p&gt;The original walkthrough is hands-on-the-CLI: you run &lt;code&gt;aws glue create-job&lt;/code&gt;&lt;br&gt;
yourself, zip and upload files by hand. My version wraps all of that in one AWS CDK&lt;br&gt;
(Python) stack, so the whole thing is &lt;code&gt;cdk deploy&lt;/code&gt; and done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one private, encrypted S3 bucket holding the input CSV, the pipeline's checkpoint
state, and the Data Catalog's storage location — one bucket, three folders inside
it;&lt;/li&gt;
&lt;li&gt;one IAM role (an AWS identity the Glue job "wears" to get permissions) scoped
tightly to just that bucket, plus the one AWS-managed permission set Glue itself
needs to operate;&lt;/li&gt;
&lt;li&gt;a Glue database definition with an explicit storage location — SDP will register
tables into this database, but it won't create the database itself, so it has to
exist first;&lt;/li&gt;
&lt;li&gt;one Glue job, version 6.0, with the two flags that turn SDP on and wire it up to
the Data Catalog;&lt;/li&gt;
&lt;li&gt;a small packaging script that fills in the bucket/database names into
&lt;code&gt;spark-pipeline.yml&lt;/code&gt; right before deployment, and zips everything up for upload.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Running it
&lt;/h2&gt;

&lt;p&gt;Once deployed, there are two independent dials you turn via the job's arguments:&lt;br&gt;
whether to actually write data or just check everything compiles, and how much to&lt;br&gt;
reprocess.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Dry run: checks the dependency graph and your SQL/Python compile correctly.&lt;/span&gt;
&lt;span class="c"&gt;# Writes zero data. Good first check after a fresh deploy.&lt;/span&gt;
aws glue start-job-run &lt;span class="nt"&gt;--job-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$JOB_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--arguments&lt;/span&gt; &lt;span class="s1"&gt;'{"--conf":"spark.glue.sdp.jobMode=VALIDATE"}'&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# The real thing.&lt;/span&gt;
aws glue start-job-run &lt;span class="nt"&gt;--job-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$JOB_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--arguments&lt;/span&gt; &lt;span class="s1"&gt;'{"--conf":"spark.glue.sdp.jobMode=RUN"}'&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Full refresh: throw away every table (including streaming checkpoints) and&lt;/span&gt;
&lt;span class="c"&gt;# recompute everything from zero. Both settings have to share ONE --conf value,&lt;/span&gt;
&lt;span class="c"&gt;# space-separated -- the underlying API only accepts one --conf entry at a time.&lt;/span&gt;
aws glue start-job-run &lt;span class="nt"&gt;--job-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$JOB_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--arguments&lt;/span&gt; &lt;span class="s1"&gt;'{"--conf":"spark.glue.sdp.jobMode=RUN --conf spark.glue.sdp.runMode=--full-refresh-all"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AWS_REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wrapped these in a couple of small shell scripts&lt;br&gt;
(&lt;code&gt;scripts/run_job.sh --validate&lt;/code&gt;, &lt;code&gt;--run --wait&lt;/code&gt;, &lt;code&gt;--full-refresh-all&lt;/code&gt;, and&lt;br&gt;
&lt;code&gt;scripts/deploy.sh --upload&lt;/code&gt; for getting sample data into the bucket) — mostly so I&lt;br&gt;
never have to hand-type a JSON string in the middle of a live demo.&lt;/p&gt;

&lt;p&gt;Here's what a successful &lt;code&gt;RUN&lt;/code&gt; actually looks like in the Glue console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm21kd6jkwoqiu6w2d350.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm21kd6jkwoqiu6w2d350.png" alt="AWS Glue job run detail screen showing a SUCCEEDED run of orders-sdp-job" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The job configuration/run screen after a successful &lt;code&gt;RUN&lt;/code&gt; — Glue version 6.0, the&lt;br&gt;
SDP job arguments, and a completed run.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And the three tables it registers, visible in the Glue Data Catalog:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsr5fgxynlhdkkwpbkzlh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsr5fgxynlhdkkwpbkzlh.png" alt="AWS Glue Data Catalog table list showing bronze_orders, silver_orders, gold_sales_summary" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;bronze_orders&lt;/code&gt;, &lt;code&gt;silver_orders&lt;/code&gt;, and &lt;code&gt;gold_sales_summary&lt;/code&gt; — all three, registered&lt;br&gt;
automatically, from one job run.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Querying the results
&lt;/h2&gt;

&lt;p&gt;The whole point of getting data into bronze → silver → gold is being able to&lt;br&gt;
actually query it. Once the tables are in the Data Catalog, Amazon Athena can see&lt;br&gt;
them immediately — no extra wiring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order_count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_sales&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;average_order_value&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;gold_sales_summary&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;total_sales&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc8hb4xzcelsl30v7e0ol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc8hb4xzcelsl30v7e0ol.png" alt="Amazon Athena query editor showing results from gold_sales_summary against real sample data" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Real output, from the sample &lt;code&gt;orders.csv&lt;/code&gt; in the repo — not a mockup.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I took away from this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The core idea really does hold up.&lt;/strong&gt; Three tables, zero hand-written
orchestration code, dependency order worked out entirely from the table
references already sitting in your transformation code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming table vs. materialized view is a real design decision&lt;/strong&gt;, not just a
style preference — pick the wrong one for a given table and you'll feel it in
either unnecessary reprocessing or stale data, not in an obvious error up front.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reading about a pattern and building it are genuinely different.&lt;/strong&gt; Several small
details only became obvious once I actually deployed and ran this against real
AWS, not just from reading the walkthrough.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're newer to data engineering: don't let the jargon (DAG, checkpoint, orchestrator, materialized view) intimidate you out of trying this. Every one of those words describes something pretty ordinary once you've seen it in action once — and a three-table demo like this one is a genuinely good size to see it in action for the first time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original walkthrough this project is based on&lt;/strong&gt;:&lt;br&gt;
&lt;a href="https://aws.amazon.com/blogs/big-data/build-declarative-etl-pipelines-with-aws-glue-6-0/" rel="noopener noreferrer"&gt;Build declarative ETL pipelines with AWS Glue 6.0&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;(AWS Big Data Blog). Companion repo, if you'd like to try it yourself:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/vikneshwara-r-b/glue-sdp-demo" rel="noopener noreferrer"&gt;github.com/vikneshwara-r-b/glue-sdp-demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have questions or want to discuss about data engineering? Connect with me on &lt;a href="https://www.linkedin.com/in/vikneshwararb/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; or drop a comment below.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>python</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
