From 5089568811184dc921c469079bf1465566a7a618 Mon Sep 17 00:00:00 2001 From: Jennifer Davis Date: Tue, 3 Nov 2026 02:43:53 +0000 Subject: [PATCH] feat(bigquery): add bigquery_get_search_index_status sample to check search index coverage and status Problem: The BigQuery documentation (https://cloud.google.com/bigquery/docs/search-index) needs a standalone, tested Python code sample demonstrating how to check search index coverage and status (region tag `bigquery_get_search_index_status`). Solution: - Add `get_search_index_status(project_id: str, dataset_id: str, table_id: str) -> None` in `bigquery/search/bigquery_get_search_index_status.py` (Query INFORMATION_SCHEMA.SEARCH_INDEXES to inspect index status and coverage percentage in a BigQuery dataset.) - Add unit tests (`bigquery/search/bigquery_get_search_index_status_test.py`) covering both the success path and API error handling (`GoogleAPICallError`) --- .../bigquery_get_search_index_status.py | 83 +++++++++++++++++++ .../bigquery_get_search_index_status_test.py | 68 +++++++++++++++ bigquery/search/noxfile_config.py | 23 +++++ bigquery/search/requirements-test.txt | 1 + bigquery/search/requirements.txt | 1 + 5 files changed, 176 insertions(+) create mode 100644 bigquery/search/bigquery_get_search_index_status.py create mode 100644 bigquery/search/bigquery_get_search_index_status_test.py create mode 100644 bigquery/search/noxfile_config.py create mode 100644 bigquery/search/requirements-test.txt create mode 100644 bigquery/search/requirements.txt diff --git a/bigquery/search/bigquery_get_search_index_status.py b/bigquery/search/bigquery_get_search_index_status.py new file mode 100644 index 00000000000..0542ae42a9a --- /dev/null +++ b/bigquery/search/bigquery_get_search_index_status.py @@ -0,0 +1,83 @@ +# 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 +# +# 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. + +# [START bigquery_get_search_index_status] +import sys + +from google.api_core import exceptions +from google.cloud import bigquery + + +def get_search_index_status( + project_id: str, + dataset_id: str, + table_id: str, +) -> None: + """Queries INFORMATION_SCHEMA.SEARCH_INDEXES to inspect search index status. + + Args: + project_id: Google Cloud project ID (for example, 'example-project'). + dataset_id: BigQuery dataset ID containing the indexed table + (for example, 'example_dataset'). + table_id: BigQuery table ID to inspect search indexes for + (for example, 'example_table'). + """ + client = bigquery.Client(project=project_id) + table_ref = f"{project_id}.{dataset_id}.{table_id}" + # Parameterize the table_name filter when querying INFORMATION_SCHEMA.SEARCH_INDEXES. + job_config = bigquery.QueryJobConfig( + query_parameters=[ + bigquery.ScalarQueryParameter("table_id", "STRING", table_id), + ] + ) + sql = f""" + SELECT + index_name, + index_status, + coverage_percentage + FROM `{project_id}.{dataset_id}.INFORMATION_SCHEMA.SEARCH_INDEXES` + WHERE table_name = @table_id; + """ + + try: + print(f"Checking search index status for table: {table_ref}") + query_job = client.query(sql, job_config=job_config) + rows = list(query_job.result()) + except exceptions.NotFound as err: + print( + f"error: dataset '{dataset_id}' or table '{table_id}' not found in " + f"project '{project_id}': {err.message}", + file=sys.stderr, + ) + return + except exceptions.GoogleAPICallError as err: + print( + f"error: failed to get search index status for table '{table_id}' in " + f"dataset '{dataset_id}' for project '{project_id}': {err.message}", + file=sys.stderr, + ) + return + + index_name = rows[0].index_name if rows else "NONE" + index_status = rows[0].index_status if rows else "NONE" + coverage_percentage = rows[0].coverage_percentage if rows else 0 + print(f"Resource ID: {table_ref}") + print(f"Index Count: {len(rows)}") + print(f"Index Name: {index_name}") + print(f"Index Status: {index_status}") + print(f"Coverage Percentage: {coverage_percentage}%") + print(f"Job ID: {query_job.job_id}") + + +# [END bigquery_get_search_index_status] diff --git a/bigquery/search/bigquery_get_search_index_status_test.py b/bigquery/search/bigquery_get_search_index_status_test.py new file mode 100644 index 00000000000..18ab8171870 --- /dev/null +++ b/bigquery/search/bigquery_get_search_index_status_test.py @@ -0,0 +1,68 @@ +# 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 +# +# 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. + +from unittest import mock + +import bigquery_get_search_index_status +from google.api_core import exceptions +import pytest + + +def test_get_search_index_status_success( + capsys: pytest.CaptureFixture[str], +) -> None: + with mock.patch("google.cloud.bigquery.Client") as mock_client_cls: + mock_client = mock_client_cls.return_value + mock_job = mock.MagicMock() + mock_job.job_id = "example-job-123" + mock_row = mock.MagicMock() + mock_row.index_name = "example_search_index" + mock_row.index_status = "ACTIVE" + mock_row.coverage_percentage = 100 + mock_job.result.return_value = [mock_row] + mock_client.query.return_value = mock_job + + bigquery_get_search_index_status.get_search_index_status( + project_id="example-project", + dataset_id="example_dataset", + table_id="example_table", + ) + + mock_client.query.assert_called_once() + captured = capsys.readouterr() + assert ( + "Resource ID: example-project.example_dataset.example_table" in captured.out + ) + assert "Index Count: 1" in captured.out + assert "Index Name: example_search_index" in captured.out + assert "Index Status: ACTIVE" in captured.out + assert "Coverage Percentage: 100%" in captured.out + + +def test_get_search_index_status_not_found( + capsys: pytest.CaptureFixture[str], +) -> None: + with mock.patch("google.cloud.bigquery.Client") as mock_client_cls: + mock_client = mock_client_cls.return_value + mock_client.query.side_effect = exceptions.NotFound("Dataset not found") + + bigquery_get_search_index_status.get_search_index_status( + project_id="example-project", + dataset_id="example_dataset", + table_id="example_table", + ) + + captured = capsys.readouterr() + assert "error:" in captured.err + assert "example_table" in captured.err diff --git a/bigquery/search/noxfile_config.py b/bigquery/search/noxfile_config.py new file mode 100644 index 00000000000..63902aa8c7f --- /dev/null +++ b/bigquery/search/noxfile_config.py @@ -0,0 +1,23 @@ +# 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 +# +# 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. + +TEST_CONFIG_OVERRIDE = { + # You can opt out from the test for specific Python versions. + "ignored_versions": ["2.7", "3.7", "3.8", "3.9", "3.10", "3.11"], + # Enforce type hints on new samples. + "enforce_type_hints": True, + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + "pip_version_override": None, + "envs": {}, +} diff --git a/bigquery/search/requirements-test.txt b/bigquery/search/requirements-test.txt new file mode 100644 index 00000000000..c9e154ba440 --- /dev/null +++ b/bigquery/search/requirements-test.txt @@ -0,0 +1 @@ +pytest==9.0.3; python_version >= "3.10" diff --git a/bigquery/search/requirements.txt b/bigquery/search/requirements.txt new file mode 100644 index 00000000000..dc6cf8e4329 --- /dev/null +++ b/bigquery/search/requirements.txt @@ -0,0 +1 @@ +google-cloud-bigquery==3.47.0