Skip to content

Commit 3dbbaa4

Browse files
committed
feat:Bigquery ADK support for search catalog tool
1 parent 330329a commit 3dbbaa4

File tree

6 files changed

+298
-152
lines changed

6 files changed

+298
-152
lines changed

contributing/samples/bigquery/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,4 @@ type.
129129
* which tables exist in the ml_datasets dataset?
130130
* show more details about the penguins table
131131
* compute penguins population per island.
132+
* are there any tables related to animals in project <your_project_id>?

src/google/adk/tools/bigquery/bigquery_credentials.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"https://www.googleapis.com/auth/bigquery",
2424
"https://www.googleapis.com/auth/cloud-platform",
2525
]
26+
BIGQUERY_DEFAULT_SCOPE = BIGQUERY_SCOPES
2627

2728

2829
@experimental(FeatureName.GOOGLE_CREDENTIALS_CONFIG)

src/google/adk/tools/bigquery/client.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
from __future__ import annotations
1616

17-
from typing import Optional
18-
1917
import google.api_core.client_info
2018
from google.api_core.gapic_v1 import client_info as gapic_client_info
2119
from google.auth.credentials import Credentials
@@ -27,18 +25,15 @@
2725
USER_AGENT_BASE = f"google-adk/{version.__version__}"
2826
BQ_USER_AGENT = f"adk-bigquery-tool {USER_AGENT_BASE}"
2927
DP_USER_AGENT = f"adk-dataplex-tool {USER_AGENT_BASE}"
30-
31-
32-
from typing import List
33-
from typing import Union
28+
USER_AGENT = BQ_USER_AGENT
3429

3530

3631
def get_bigquery_client(
3732
*,
38-
project: Optional[str],
33+
project: str | None,
3934
credentials: Credentials,
40-
location: Optional[str] = None,
41-
user_agent: Optional[Union[str, List[str]]] = None,
35+
location: str | None = None,
36+
user_agent: str | list[str] | None = None,
4237
) -> bigquery.Client:
4338
"""Get a BigQuery client.
4439
@@ -76,7 +71,7 @@ def get_bigquery_client(
7671
def get_dataplex_catalog_client(
7772
*,
7873
credentials: Credentials,
79-
user_agent: Optional[Union[str, List[str]]] = None,
74+
user_agent: str | list[str] | None = None,
8075
) -> dataplex_v1.CatalogServiceClient:
8176
"""Get a Dataplex CatalogServiceClient with minimal necessary arguments.
8277

src/google/adk/tools/bigquery/search_tool.py

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616

1717
import logging
1818
from typing import Any
19-
from typing import Dict
20-
from typing import List
21-
from typing import Optional
2219

2320
from google.api_core import exceptions as api_exceptions
2421
from google.auth.credentials import Credentials
@@ -29,44 +26,74 @@
2926

3027

3128
def _construct_search_query_helper(
32-
predicate: str, operator: str, items: List[str]
29+
predicate: str, operator: str, items: list[str]
3330
) -> str:
31+
"""Constructs a search query part for a specific predicate and items."""
3432
if not items:
3533
return ""
36-
if len(items) == 1:
37-
return f'{predicate}{operator}"{items[0]}"'
3834

3935
clauses = [f'{predicate}{operator}"{item}"' for item in items]
40-
return "(" + " OR ".join(clauses) + ")"
36+
return "(" + " OR ".join(clauses) + ")" if len(items) > 1 else clauses[0]
4137

4238

4339
def search_catalog(
4440
prompt: str,
4541
project_id: str,
42+
*,
4643
credentials: Credentials,
4744
settings: BigQueryToolConfig,
48-
location: str,
45+
location: str | None = None,
4946
page_size: int = 10,
50-
project_ids_filter: Optional[List[str]] = None,
51-
dataset_ids_filter: Optional[List[str]] = None,
52-
types_filter: Optional[List[str]] = None,
53-
) -> Dict[str, Any]:
47+
project_ids_filter: list[str] | None = None,
48+
dataset_ids_filter: list[str] | None = None,
49+
types_filter: list[str] | None = None,
50+
) -> dict[str, Any]:
5451
"""Search for BigQuery assets within Dataplex.
5552
5653
Args:
57-
prompt (str): The base search query (natural language or keywords).
58-
project_id (str): The Google Cloud project ID to scope the search.
59-
credentials (Credentials): Credentials for the request.
60-
settings (BigQueryToolConfig): BigQuery tool settings.
61-
location (str): The Dataplex location to use.
62-
page_size (int): Maximum number of results.
63-
project_ids_filter (Optional[List[str]]): Specific project IDs to include in the search results.
64-
If None, defaults to the scoping project_id.
65-
dataset_ids_filter (Optional[List[str]]): BigQuery dataset IDs to filter by.
66-
types_filter (Optional[List[str]]): Entry types to filter by (e.g., "TABLE", "DATASET").
54+
prompt: The base search query (natural language or keywords).
55+
project_id: The Google Cloud project ID to scope the search.
56+
credentials: Credentials for the request.
57+
settings: BigQuery tool settings.
58+
location: The Dataplex location to use.
59+
page_size: Maximum number of results.
60+
project_ids_filter: Specific project IDs to include in the search results.
61+
If None, defaults to the scoping project_id.
62+
dataset_ids_filter: BigQuery dataset IDs to filter by.
63+
types_filter: Entry types to filter by (e.g., BigQueryEntryType.TABLE,
64+
BigQueryEntryType.DATASET).
6765
6866
Returns:
69-
dict: Search results or error.
67+
Search results or error. The "results" list contains items with:
68+
- name: The Dataplex Entry name (e.g.,
69+
"projects/p/locations/l/entryGroups/g/entries/e").
70+
- linked_resource: The underlying BigQuery resource name (e.g.,
71+
"//bigquery.googleapis.com/projects/p/datasets/d/tables/t").
72+
- display_name, entry_type, description, location, update_time.
73+
74+
Examples:
75+
Search for tables related to customer data:
76+
77+
>>> search_catalog(
78+
... prompt="Search for tables related to customer data",
79+
... project_id="my-project",
80+
... credentials=creds,
81+
... settings=settings
82+
... )
83+
{
84+
"status": "SUCCESS",
85+
"results": [
86+
{
87+
"name": "projects/my-project/locations/us/entryGroups/@bigquery/entries/entry-id",
88+
"display_name": "customer_table",
89+
"entry_type": "projects/p/locations/l/entryTypes/bigquery-table",
90+
"linked_resource": "//bigquery.googleapis.com/projects/my-project/datasets/d/tables/customer_table",
91+
"description": "Table containing customer details.",
92+
"location": "us",
93+
"update_time": "2024-01-01 12:00:00+00:00"
94+
}
95+
]
96+
}
7097
"""
7198
try:
7299
if not project_id:
@@ -95,11 +122,12 @@ def search_catalog(
95122

96123
# Filter by dataset IDs
97124
if dataset_ids_filter:
98-
dataset_resource_filters = [
99-
f'linked_resource:"//bigquery.googleapis.com/projects/{pid}/datasets/{did}/*"'
100-
for pid in projects_to_filter
101-
for did in dataset_ids_filter
102-
]
125+
dataset_resource_filters = []
126+
for pid in projects_to_filter:
127+
for did in dataset_ids_filter:
128+
dataset_resource_filters.append(
129+
f'linked_resource:"//bigquery.googleapis.com/projects/{pid}/datasets/{did}/*"'
130+
)
103131
if dataset_resource_filters:
104132
query_parts.append(f"({' OR '.join(dataset_resource_filters)})")
105133
# Filter by entry types
@@ -113,7 +141,8 @@ def search_catalog(
113141

114142
full_query = " AND ".join(filter(None, query_parts))
115143

116-
search_scope = f"projects/{project_id}/locations/{location}"
144+
search_location = location or settings.location or "global"
145+
search_scope = f"projects/{project_id}/locations/{search_location}"
117146

118147
request = dataplex_v1.SearchEntriesRequest(
119148
name=search_scope,
@@ -142,6 +171,6 @@ def search_catalog(
142171
except api_exceptions.GoogleAPICallError as e:
143172
logging.exception("search_catalog tool: API call failed")
144173
return {"status": "ERROR", "error_details": f"Dataplex API Error: {str(e)}"}
145-
except Exception as ex:
174+
except Exception as e:
146175
logging.exception("search_catalog tool: Unexpected error")
147-
return {"status": "ERROR", "error_details": str(ex)}
176+
return {"status": "ERROR", "error_details": str(e)}

0 commit comments

Comments
 (0)