Repository navigation
docs: add code samples for BigQuery dry run #14703
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c6196e0
0e5b170
fbc4ede
7e6b2c9
f774ec6
dc8af8a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| # [START bigquery_bigframes_query_dry_run] | ||
| from typing import Tuple | ||
|
|
||
| import bigframes.pandas as bpd | ||
| import pandas as pd | ||
|
|
||
| # Set partial ordering mode as the default configuration for BigQuery | ||
| # DataFrames. | ||
| bpd.options.bigquery.ordering_mode = "partial" | ||
|
|
||
|
|
||
| def query_dry_run( | ||
| project_id: str = "your-project-id", | ||
| ) -> Tuple[pd.Series, pd.Series]: | ||
| """Estimates the bytes processed by a SQL query and a DataFrame operation.""" | ||
| bpd.options.bigquery.project = project_id | ||
|
|
||
| sql = """ | ||
| SELECT name, SUM(number) AS total_people | ||
| FROM `bigquery-public-data.usa_names.usa_1910_current` | ||
| WHERE state = 'TX' | ||
| GROUP BY name | ||
| """ | ||
|
|
||
| # Perform a dry run on a SQL query without executing it. | ||
| sql_stats = bpd.read_gbq(sql, use_cache=False, dry_run=True) | ||
| print(f"SQL query will process {sql_stats['totalBytesProcessed']} bytes.") | ||
|
|
||
| # Perform a dry run on BigQuery DataFrames operations before downloading | ||
| # results to an in-memory pandas DataFrame. | ||
| df = bpd.read_gbq("bigquery-public-data.usa_names.usa_1910_current") | ||
| df_tx = df[df["state"] == "TX"].groupby("name", as_index=False)["number"].sum() | ||
| df_stats = df_tx.to_pandas(dry_run=True) | ||
| print(f"DataFrame operation will process {df_stats['totalBytesProcessed']} bytes.") | ||
|
|
||
| return sql_stats, df_stats | ||
|
|
||
|
|
||
| # [END bigquery_bigframes_query_dry_run] | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| import os | ||
|
|
||
| project = os.environ.get("GOOGLE_CLOUD_PROJECT", "your-project-id") | ||
| query_dry_run(project_id=project) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import bigframes.pandas as bpd | ||
| import pytest | ||
|
|
||
| import query_dry_run | ||
|
|
||
|
|
||
| def test_query_dry_run(project_id: str, capsys: pytest.CaptureFixture) -> None: | ||
| bpd.close_session() | ||
|
|
||
| sql_stats, df_stats = query_dry_run.query_dry_run(project_id=project_id) | ||
| out, _ = capsys.readouterr() | ||
|
|
||
| assert sql_stats["totalBytesProcessed"] > 0 | ||
| assert df_stats["totalBytesProcessed"] > 0 | ||
| assert "bytes" in out |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| # [START bigquery_migration_pandas_gbq_query_dry_run] | ||
| import pandas as pd | ||
| import pandas_gbq | ||
|
|
||
|
|
||
| def query_dry_run(project_id: str = "your-project-id") -> pd.Series: | ||
| """Estimates the bytes processed by a SQL query using a dry run.""" | ||
| sql = """ | ||
| SELECT name, SUM(number) AS total_people | ||
| FROM `bigquery-public-data.usa_names.usa_1910_current` | ||
| WHERE state = 'TX' | ||
| GROUP BY name | ||
| """ | ||
|
|
||
| # Perform a dry run to estimate bytes processed without running the query. | ||
| query_config = { | ||
| "query": { | ||
| "useQueryCache": False, | ||
| } | ||
| } | ||
| stats = pandas_gbq.read_gbq( | ||
| sql, | ||
| project_id=project_id, | ||
| configuration=query_config, | ||
| dry_run=True, | ||
| ) | ||
| print(f"This query will process {stats['totalBytesProcessed']} bytes.") | ||
| return stats | ||
|
|
||
|
|
||
| # [END bigquery_migration_pandas_gbq_query_dry_run] | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| import os | ||
|
|
||
| project = os.environ.get("GOOGLE_CLOUD_PROJECT", "your-project-id") | ||
| query_dry_run(project_id=project) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import os | ||
|
|
||
| import pytest | ||
|
|
||
| import query_dry_run | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def project_id() -> str: | ||
| return os.environ["GOOGLE_CLOUD_PROJECT"] | ||
|
|
||
|
|
||
| def test_query_dry_run(project_id: str, capsys: pytest.CaptureFixture) -> None: | ||
| stats = query_dry_run.query_dry_run(project_id=project_id) | ||
| out, _ = capsys.readouterr() | ||
|
|
||
| assert stats["totalBytesProcessed"] > 0 | ||
| assert "bytes" in out |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,10 @@ | ||
| google-cloud-bigquery==3.27.0 | ||
| google-cloud-bigquery-storage==2.27.0 | ||
| pandas==2.0.3; python_version == '3.8' | ||
| pandas==2.2.3; python_version > '3.8' | ||
| pandas-gbq==0.24.0 | ||
| pandas==2.2.3; python_version < '3.11' | ||
| pandas==3.1.0; python_version >= '3.11' | ||
| pandas-gbq==0.35.3 | ||
| grpcio==1.70.0; python_version == '3.8' | ||
| grpcio==1.74.0; python_version > '3.8' | ||
| grpcio==1.74.0; python_version == '3.9' | ||
| grpcio==1.85.1; python_version >= '3.10' | ||
|
Comment on lines
3
to
+9
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Python versions below 3.10 are no longer supported. Please remove the fallback dependency versions and environment markers for Python 3.8 and 3.9, and simplify the requirements accordingly. References
|
||
| pyarrow==24.0.0 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # polars-bigquery samples | ||
|
|
||
| This directory contains samples used to demonstrate use of the `polars-bigquery` | ||
| package. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # Copyright 2021 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # https://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import os | ||
|
|
||
| import pytest | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def project_id() -> str: | ||
| return os.environ["GOOGLE_CLOUD_PROJECT"] |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,39 @@ | ||||||
| # Copyright 2021 Google LLC | ||||||
| # | ||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
| # you may not use this file except in compliance with the License. | ||||||
| # You may obtain a copy of the License at | ||||||
| # | ||||||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||||||
| # | ||||||
| # Unless required by applicable law or agreed to in writing, software | ||||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
| # See the License for the specific language governing permissions and | ||||||
| # limitations under the License. | ||||||
|
|
||||||
| # Default TEST_CONFIG_OVERRIDE for python repos. | ||||||
|
|
||||||
| # You can copy this file into your directory, then it will be imported from | ||||||
| # the noxfile.py. | ||||||
|
|
||||||
| # The source of truth: | ||||||
| # https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/noxfile_config.py | ||||||
|
|
||||||
| TEST_CONFIG_OVERRIDE = { | ||||||
| # You can opt out from the test for specific Python versions. | ||||||
| # Skipping for Python 3.9 due to pyarrow compilation failure. | ||||||
| "ignored_versions": ["3.8", "3.9", "3.11", "3.12", "3.13"], | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To adhere to the testing policy of only testing the oldest and newest supported Python releases, we should test Python 3.10 (oldest) and Python 3.13 (newest). Please remove Python 3.13 from the ignored versions list so that it is included in the test suite.
Suggested change
References
|
||||||
| # Old samples are opted out of enforcing Python type hints | ||||||
| # All new samples should feature them | ||||||
| "enforce_type_hints": False, | ||||||
| # An envvar key for determining the project id to use. Change it | ||||||
| # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a | ||||||
| # build specific Cloud project. You can also use your own string | ||||||
| # to use your own Cloud project. | ||||||
| "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", | ||||||
| # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', | ||||||
| # A dictionary you want to inject into your test. Don't put any | ||||||
| # secrets here. These values will override predefined values. | ||||||
| "envs": {}, | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| # [START bigquery_polars_query_bqstorage] | ||
| import polars | ||
| import polars_bigquery | ||
|
|
||
|
|
||
| def construct_client(project_id: str = "your-project-id") -> polars_bigquery.Client: | ||
| return polars_bigquery.Client( | ||
| quota_project_id=project_id, | ||
| ) | ||
|
|
||
|
|
||
| def query_bqstorage(plbq: polars_bigquery.Client) -> polars.DataFrame: | ||
| sql = """ | ||
| SELECT year, name, SUM(number) | ||
| FROM `bigquery-public-data.usa_names.usa_1910_current` | ||
| GROUP BY year, name | ||
| """ | ||
|
|
||
| # Run a query and immediately download the results. polars-biqquery | ||
| # automatically uses the BigQuery Storage Read API to download results that | ||
| # don't fit in a single response message. | ||
| df = plbq.read_query( | ||
| sql, | ||
| # For the best performance, set maintain_order=False if you don't care | ||
| # about the order of the rows in the result. This allows polars-bigquery | ||
| # to create multiple BigQuery Storage Read API read streams if needed. | ||
| maintain_order=False, | ||
| ) | ||
| return df | ||
| # [END bigquery_polars_query_bqstorage] | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| import os | ||
|
|
||
| project = os.environ.get("GOOGLE_CLOUD_PROJECT", "your-project-id") | ||
| print(query_bqstorage(construct_client(project))) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import query_bqstorage | ||
|
|
||
|
|
||
| def test_query_bqstorage(project_id: str) -> None: | ||
| plbq = query_bqstorage.construct_client(project_id=project_id) | ||
| pandas_df = query_bqstorage.query_bqstorage(plbq) | ||
| assert pandas_df is not None |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # Copyright 2026 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| # [START bigquery_polars_query_dry_run] | ||
| import polars | ||
| import polars_bigquery | ||
|
|
||
|
|
||
| def construct_client( | ||
| project_id: str = "your-project-id", | ||
| ) -> polars_bigquery.Client: | ||
| """Constructs a Polars BigQuery client.""" | ||
| return polars_bigquery.Client( | ||
| quota_project_id=project_id, | ||
| ) | ||
|
|
||
|
|
||
| def query_dry_run(plbq: polars_bigquery.Client) -> polars.DataFrame: | ||
| """Estimates the bytes processed by a SQL query using a dry run.""" | ||
| sql = """ | ||
| SELECT name, SUM(number) AS total_people | ||
| FROM `bigquery-public-data.usa_names.usa_1910_current` | ||
| WHERE state = 'TX' | ||
| GROUP BY name | ||
| """ | ||
|
|
||
| # Perform a dry run to validate the query and estimate bytes processed | ||
| # without executing the query. | ||
| stats = plbq.read_query( | ||
| sql, | ||
| dry_run=True, | ||
| use_query_cache=False, | ||
| ) | ||
| total_bytes = stats.item(0, "totalBytesProcessed") | ||
| print(f"This query will process {total_bytes} bytes.") | ||
| return stats | ||
|
|
||
|
|
||
| # [END bigquery_polars_query_dry_run] | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| import os | ||
|
|
||
| project = os.environ.get("GOOGLE_CLOUD_PROJECT", "your-project-id") | ||
| query_dry_run(construct_client(project_id=project)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dry run operations in BigQuery DataFrames return metadata objects (or dict-like objects) rather than a
pandas.Series. Update the return type annotation toTuple[dict, dict]to accurately reflect the returned types.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BigFrames does return a panda Series.