Class BigQuerySourceBuilder<T>
- Type Parameters:
T- type of the records produced by the source
BigQuerySource.-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final longDefault formaxBytesPerFetch(long): 8 MiB of serialized Avro rows per fetch.static final intThe most rows one fetch hands to the task thread.static final intDefault forretryMaxAttempts(int): consecutiveReadRowsattempts without progress. -
Method Summary
Modifier and TypeMethodDescriptionorg.apache.flink.api.connector.source.Source<T,ReadStreamSplit, BigQueryReadEnumeratorState> build()Builds the source.deserializer(BigQueryRowDeserializationSchema<T> deserializer) Sets the deserializer converting each row into zero or more records.emulatorEndpoint(String emulatorEndpoint) Sends the source's traffic to a BigQuery emulator athost:port, over plaintext and without credentials.emulatorRestEndpoint(String emulatorRestEndpoint) Sends the source's REST traffic — its query job, and the view lookupmaterializeViews()makes — to a BigQuery emulator athost:port, over plain HTTP and without credentials.Reads atable(TableDestination)that turns out to be a view by materializing it.maxBytesPerFetch(long maxBytesPerFetch) Sets the target serialized Avro bytes one fetch hands to the task thread.maxRecordsPerFetch(int maxRecordsPerFetch) Sets the most rows one fetch hands to the task thread.maxStreamCount(int maxStreamCount) Sets an upper bound on the number of read streams BigQuery creates.parentProject(String parentProject) Sets the project the read session belongs to and is billed to.preferredMinStreamCount(int preferredMinStreamCount) Sets the number of read streams to ask BigQuery for.Sets a query whose result is read, instead of reading a table directly.queryLocation(String queryLocation) Sets the BigQuery location the query job runs in.queryResultDataset(String queryResultDataset) Sets a dataset the query's result is written to, instead of BigQuery's anonymous dataset.retryMaxAttempts(int retryMaxAttempts) Sets how many consecutiveReadRowsattempts without progress the client makes before the read fails.reuseQueryResultWithin(Duration reuseQueryResultWithin) Lets a re-planned job reuse a previous attempt's query job instead of running the query again, for attempts within the given window.rowRestriction(String rowRestriction) Sets a filter BigQuery applies before any row is sent.selectedFields(String... fields) Sets the columns to read.selectedFields(Collection<String> fields) Sets the columns to read, rejecting a blank or repeated column name.serviceAccountKeyFile(String serviceAccountKeyFile) Uses the service account in the given JSON key file for every BigQuery client this source opens.snapshotTime(Instant snapshotTime) Sets the instant the table is read as of.table(TableDestination table) Sets the table to read.
-
Field Details
-
DEFAULT_MAX_RECORDS_PER_FETCH
public static final int DEFAULT_MAX_RECORDS_PER_FETCHThe most rows one fetch hands to the task thread.A BigQuery response block carries up to about 128 MiB of rows, so a cap is what lets a checkpoint be taken part-way through one. The value follows the reference connector's own default and complements
DEFAULT_MAX_BYTES_PER_FETCH: this cap bounds small decoded records by count while the byte target bounds large variable-width records.- See Also:
-
DEFAULT_MAX_BYTES_PER_FETCH
public static final long DEFAULT_MAX_BYTES_PER_FETCHDefault formaxBytesPerFetch(long): 8 MiB of serialized Avro rows per fetch.The byte cap complements the row cap for variable-width rows. A local benchmark over 4-256 KiB rows retained 92% of the count-only throughput while reducing the first retained batch from 64 MiB to 8.1 MiB. It is a target rather than a hard heap limit: one row is always allowed to make progress, and the cursor also retains the current Storage Read response block.
- See Also:
-
DEFAULT_RETRY_MAX_ATTEMPTS
public static final int DEFAULT_RETRY_MAX_ATTEMPTSDefault forretryMaxAttempts(int): consecutiveReadRowsattempts without progress.Read off the sequence it bounds rather than chosen for its own sake, and how long it is depends on the failure. An
UNAVAILABLEbacks off exponentially — nominally 100 ms growing by 1.3 — with gax picking each wait uniformly between zero and that value, which puts twenty-five consecutive failures at about three minutes at worst and half that on average: long enough to ride out the restarts a long read meets, short enough that a stream which is never coming back is reported instead of retried for the SDK's own twenty-four hours. TheINTERNALtransport faults the client also resumes are retried a fixed millisecond apart with no growth, so for those the bound is reached almost at once.- See Also:
-
-
Method Details
-
table
Sets the table to read.Either this or
query(String), never both and never neither. A view is not a table here: the Storage Read API reads storage, and a view has none — pass its query, orSELECT * FROM the_view, toquery(String)instead.- Parameters:
table- the table- Returns:
- this builder
-
query
Sets a query whose result is read, instead of reading a table directly.The query is run once, at job start, as an ordinary BigQuery query job, and the source reads the table its result landed in. That is what makes a view readable — the Storage Read API cannot read a logical or materialized view at all, because it reads storage and a view has none.
It is billed twice: once for the bytes the query scans, and again for the bytes the read session scans out of its result. Prune inside the query itself rather than relying on
selectedFields(String...)androwRestriction(String), which BigQuery applies to the result and so cannot make the query cheaper.Where the result lands is
queryResultDataset(String)'s choice, and by default it is BigQuery's own anonymous dataset — nothing this connector has to create, expire or delete.Requires
parentProject(String): with no table named, nothing else says which project the query job is submitted to and billed to.- Parameters:
query- the query, in GoogleSQL- Returns:
- this builder
-
materializeViews
Reads atable(TableDestination)that turns out to be a view by materializing it.Optional, and off by default. With it, the source asks BigQuery once, at job start, what the configured name is; a view — logical or materialized — is then read the way
query(String)reads one, by runningSELECT … FROM the_viewand reading its result. An ordinary table is read directly, exactly as without this. Spark's and the Dataproc connector's equivalent is spelledviewsEnabled.Off by default because it costs a metadata call, and a source pointed at a table should not pay a round trip to be told it is a table — the read path otherwise makes no REST call at all. Asking for this is also asking to be billed for a query nobody typed, which is the other reason it is not the default.
selectedFields(String...)is folded into the generatedSELECT, so a view is not scanned column by column for data that is then discarded.rowRestriction(String)is not: BigQuery's restriction syntax is not a SQLWHERE, so it stays where a table source applies it, on the read session.Where the materialized result lands, and what it costs, is
queryResultDataset(String)'s choice, exactly as forquery(String).- Returns:
- this builder
-
queryLocation
Sets the BigQuery location the query job runs in.Optional; defaults to letting BigQuery infer it from the tables the query names, which is what it does for a query submitted without one. Set it where the inference has nothing to go on, or where the job must be pinned to a region.
- Parameters:
queryLocation- the location, for example"US"or"asia-northeast1"- Returns:
- this builder
-
queryResultDataset
Sets a dataset the query's result is written to, instead of BigQuery's anonymous dataset.Optional, and the two choices differ in who owns the result:
- Unset — BigQuery's anonymous dataset. The query is submitted with no destination table, so BigQuery writes the result into a hidden dataset of its own, expires it after about a day and charges no storage for it. Nothing is created here, so nothing is left to clean up, and an identical query re-run within that window is answered from cache — free, and landing on the same table. Its constraints are BigQuery's: access is restricted to the identity that ran the query, Google advises against depending on a cached result table, and a result above the maximum response size is not kept.
- Set — a table in this dataset. The result is written to a table this connector creates there, with an expiration of a day set on it. Storage is charged for it until then, and nothing deletes it earlier: teardown also runs on a JobManager failover, where the restored job is still reading the read session that table backs.
The dataset must already exist, must be in the query's own location, and must live in
parentProject(String).- Parameters:
queryResultDataset- the dataset id- Returns:
- this builder
-
reuseQueryResultWithin
Lets a re-planned job reuse a previous attempt's query job instead of running the query again, for attempts within the given window.Optional, and off by default — the job id is then random and every plan runs the query. With it, the job id is derived from the Flink job name, a digest of the query configuration, and the window, so a JobManager failover before the first checkpoint — the one failure that re-plans a source — finds the first attempt's job and adopts it: a job still running is waited for instead of racing it with a second scan, and a finished one has its result table checked and read — a table that vanished meanwhile makes the attempt run the query again instead.
queryJobsReattachedreports each reuse.What it treats as "the same job" is the Flink job name, because the name is the identifier the user controls: rename the job and nothing is reused. The rest of the id is derived — a digest over the query, project, location, result dataset and this window — so two pipelines can only ever share a job when they would run the identical query to the identical place, in which case sharing it is correct. The flip side is deliberate: attempts of the same name and query inside one window reuse each other's result even across an intentional redeploy, so the result can be up to a window old. Size the window to how stale a result the pipeline can read, or rename the job to force a fresh one.
At most 24 hours, because both places a result can land expire at about a day: past that there is nothing left to reuse — an adoption whose table has expired falls back to running the query — so a longer window could only ever pay for the query again while appearing to deduplicate it.
Requires
queryLocation(String): BigQuery scopes a job to (project, location, id), and a look-up that names no location sees only the US multi-region — outside it the previous attempt's job would never be found, so the reuse this knob asks for could never happen (measured 2026-08-10 against a us-central1 dataset).- Parameters:
reuseQueryResultWithin- the window, positive and at most 24 hours- Returns:
- this builder
-
parentProject
Sets the project the read session belongs to and is billed to.Optional beside
table(TableDestination), where it defaults to the table's own project; set it to read a table in another project — a public dataset, say — where the read cannot be billed to the project that owns the table. Required besidequery(String), which names no table to take a default from, and where it is also the project the query job runs in and is billed to.- Parameters:
parentProject- the Google Cloud project id- Returns:
- this builder
-
deserializer
Sets the deserializer converting each row into zero or more records.- Parameters:
deserializer- the deserializer- Returns:
- this builder
-
selectedFields
Sets the columns to read.Optional; defaults to every column. The projection is applied by BigQuery when the read session is created, so unread columns are neither scanned nor billed.
- Parameters:
fields- the column names- Returns:
- this builder
-
selectedFields
Sets the columns to read, rejecting a blank or repeated column name.- Parameters:
fields- the column names- Returns:
- this builder
- See Also:
-
rowRestriction
Sets a filter BigQuery applies before any row is sent.Optional; defaults to no filter. The expression is BigQuery's own restriction syntax, a
WHEREclause without the keyword, for example"state = 'CA' AND year > 2020". Rows it excludes are neither transferred nor billed.- Parameters:
rowRestriction- the restriction- Returns:
- this builder
-
snapshotTime
Sets the instant the table is read as of.Optional; defaults to the table's contents when the read session is created. BigQuery serves this from its time-travel window and rejects an instant outside it.
- Parameters:
snapshotTime- the instant to read the table as of- Returns:
- this builder
-
maxStreamCount
Sets an upper bound on the number of read streams BigQuery creates.Optional; defaults to
0, which lets BigQuery choose. It is a cap and not a target: BigQuery returns at most this many streams and may return far fewer — a small table is read by a single stream however many are asked for (measured 2026-08-09). Since one stream is read by one subtask at a time, capping it below the job's parallelism leaves subtasks idle.- Parameters:
maxStreamCount- the upper bound, or0to let BigQuery choose- Returns:
- this builder
-
preferredMinStreamCount
Sets the number of read streams to ask BigQuery for.Optional; defaults to
0, which asks for no particular number. BigQuery makes a best effort to provide at least this many and may provide fewer. Asking for more streams than there are subtasks is how this source gets its elasticity: readers take the next stream as they finish one, so over-provisioning is what keeps a slow stream from holding a subtask idle.- Parameters:
preferredMinStreamCount- the preferred lower bound, or0for none- Returns:
- this builder
-
maxRecordsPerFetch
Sets the most rows one fetch hands to the task thread.Optional; defaults to
DEFAULT_MAX_RECORDS_PER_FETCH. This remains an independent count bound for small rows and checkpoint cadence;maxBytesPerFetch(long)bounds variable-width rows by their serialized Avro size.- Parameters:
maxRecordsPerFetch- the cap- Returns:
- this builder
-
maxBytesPerFetch
Sets the target serialized Avro bytes one fetch hands to the task thread.Optional; defaults to
DEFAULT_MAX_BYTES_PER_FETCH. The reader stops before adding a row that would take a non-empty batch over the target. A row larger than the target is emitted by itself so the source always makes progress.- Parameters:
maxBytesPerFetch- the positive byte target- Returns:
- this builder
-
retryMaxAttempts
Sets how many consecutiveReadRowsattempts without progress the client makes before the read fails.Optional; defaults to
DEFAULT_RETRY_MAX_ATTEMPTS. The retry itself is the client library's, not this connector's: it resumes a broken stream at the row it had reached, and decides for itself which failures deserve a resume. This knob only stops it. Without one the client retries for twenty-four hours, so a stream that will never come back holds a reader for a day while reporting nothing.An attempt that produced rows resets the count, so this bounds a stream that is stuck rather than one that is slow. Raise it for a read that must survive a long outage; the job fails and restarts from its last checkpoint either way, resuming each stream at the offset that checkpoint holds rather than reading it from the top.
- Parameters:
retryMaxAttempts- the maximum number of consecutive attempts without progress- Returns:
- this builder
-
serviceAccountKeyFile
Uses the service account in the given JSON key file for every BigQuery client this source opens.Optional; absent uses application-default credentials. Only the path enters the job graph. The source loads the file when its runtime clients are first opened: the JobManager creates read sessions and runs query or view-materialization jobs, and TaskManagers open the assigned read streams. The same key file must therefore exist at that path on both process types, including after failover or rescaling.
Only service-account JSON is accepted. This setting cannot be combined with either emulator endpoint because emulator connections are credential-free.
- Parameters:
serviceAccountKeyFile- the service-account JSON key-file path- Returns:
- this builder
-
emulatorEndpoint
Sends the source's traffic to a BigQuery emulator athost:port, over plaintext and without credentials.For testing against a local emulator and nothing else. This is the whole of it for a source reading a
table(TableDestination)that does not ask formaterializeViews(): the read session carries the schema, so nothing on that path makes a REST call. A source reading aquery(String), or one that asked formaterializeViews(), does make one — the query job, and the view lookup — and needsemulatorRestEndpoint(String)as well.The value is parsed here, so a malformed
host:portis rejected on the client instead of surfacing as a connection failure once the job has been deployed.- Parameters:
emulatorEndpoint- the emulator's gRPC endpoint ashost:port- Returns:
- this builder
- Throws:
IllegalArgumentException- if the endpoint is nothost:portwith a port in 1..65535
-
emulatorRestEndpoint
Sends the source's REST traffic — its query job, and the view lookupmaterializeViews()makes — to a BigQuery emulator athost:port, over plain HTTP and without credentials.This is the REST half of
emulatorEndpoint(String). Two sources reach it:query(String), whose query job is a REST call, andtable(TableDestination)withmaterializeViews(), whose view lookup is one. The lookup is made whether or not the name turns out to be a view, so amaterializeViews()source over an ordinary table needs this endpoint and runs no query job at all. The two are separate because they are separate transports on separate ports, as they are on the sink side.- Parameters:
emulatorRestEndpoint- the emulator's REST endpoint ashost:port- Returns:
- this builder
- Throws:
IllegalArgumentException- if the endpoint is nothost:portwith a port in 1..65535
-
build
public org.apache.flink.api.connector.source.Source<T,ReadStreamSplit, build()BigQueryReadEnumeratorState> Builds the source.- Returns:
- the source
-