Skip to content

Avoid writing empty placeholder files for date partitions with no data - #13

Merged
tomaslink merged 1 commit into
mainfrom
fix/bq-to-parquet-skip-empty-partitions
Aug 5, 2026
Merged

tomaslink merged 1 commit into
mainfrom
fix/bq-to-parquet-skip-empty-partitions

Conversation

@tomaslink

Copy link
Copy Markdown
Collaborator

https://globalfishingwatch.atlassian.net/browse/PIPELINE-4368


Avoid writing empty placeholder files for date partitions with no data

  • PartitionedSource writes a schema-only file even for empty/non-existent partitions (BigQuery's table$YYYYMMDD decorator returns 0 rows instead of erroring) — cluttering the external table with tiny files that hurt query performance.
  • Fixed by checking BigQuery partition/table metadata up front (INFORMATION_SCHEMA.PARTITIONS/.TABLES, metadata-only, no scan) and skipping dates with no data before submitting a job.
  • ShardedSource gets the same proactive check, replacing its old reliance on catching NotFound — that exception fires for any missing resource (table, dataset, project), so it couldn't reliably distinguish a missing shard from a misconfigured source.

@tomaslink tomaslink self-assigned this Aug 5, 2026
PartitionedSource addresses each date via BigQuery's partition decorator
(table$YYYYMMDD), which returns zero rows rather than raising NotFound
when a partition has no data -- unlike ShardedSource, where a missing
shard table does raise NotFound. This meant non-sharded sources
silently wrote a schema-only placeholder file for every empty date
(e.g. before a source's real start date, or any gap day), cluttering
the output with tiny files that hurt query performance on the
external table.

Source stays a pure addressing/naming type: dates_with_data_query()
returns the check as data (a query + parameters), not by running it,
so it never needs a BQ client. Exporter (which already owns the BQ
client) runs the query and filters dates accordingly. There's no safe
generic default for this on the base class, same as separator: a
source that can't support the check must explicitly return None
(a deliberate choice, not an inherited omission), which Exporter
treats as "assume every date has data".

ShardedSource gets the same proactive check via
INFORMATION_SCHEMA.TABLES, instead of relying on catching NotFound
from a submitted extract job. NotFound is a generic "resource
missing" error -- it fires the same way for a missing shard, a
typo'd dataset, or a missing project, so treating it as proof "this
date has no data" was unreliable: a misconfigured source could make
every date look like a benign gap instead of a hard failure. A truly
wrong project/dataset now fails immediately anyway, since
Exporter.dates_with_data() runs its check with no try/except, before
any job is submitted.

Since dates are now confirmed to exist before a job is ever
submitted, a NotFound at job-completion time is an anomaly (e.g. a
genuine race: the table dropped between the check and the job
running), not a routine outcome. It's handled by the same generic
except Exception path as any other unexpected failure -- no special
case needed, since the outcome (fail hard, surface via run()'s
RuntimeError, get retried) is identical either way. ExportStatus.
NOT_FOUND and ExportJobResults.skipped are removed as a result:
nothing should intentionally produce that status anymore.
@tomaslink
tomaslink force-pushed the fix/bq-to-parquet-skip-empty-partitions branch from 3a95f41 to 502569b Compare August 5, 2026 19:56
@tomaslink
tomaslink requested a review from andres-arana August 5, 2026 19:58
@tomaslink
tomaslink merged commit eebf4fb into main Aug 5, 2026
3 checks passed
@tomaslink
tomaslink deleted the fix/bq-to-parquet-skip-empty-partitions branch August 5, 2026 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant