Skip to content

Commit 9ae3250

Browse files
google-genai-botcopybara-github
authored andcommitted
feat: Implement BigQuery auto-schema upgrade and view creation
This change adds functionality to automatically upgrade the BigQuery table schema by adding new top-level fields and new nested fields within RECORD types. It also introduces a new utility to create per-event-type BigQuery views that unnest JSON fields for easier querying. The configuration now includes options to enable view creation and set a view prefix. PiperOrigin-RevId: 895463825
1 parent 623ed47 commit 9ae3250

File tree

5 files changed

+472
-18
lines changed

5 files changed

+472
-18
lines changed

core/src/main/java/com/google/adk/plugins/agentanalytics/BigQueryAgentAnalyticsPlugin.java

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.adk.plugins.agentanalytics;
1818

19+
import static com.google.adk.plugins.agentanalytics.BigQueryUtils.createAnalyticsViews;
20+
import static com.google.adk.plugins.agentanalytics.BigQueryUtils.maybeUpgradeSchema;
1921
import static com.google.adk.plugins.agentanalytics.JsonFormatter.convertToJsonNode;
2022
import static com.google.adk.plugins.agentanalytics.JsonFormatter.smartTruncate;
2123
import static com.google.adk.plugins.agentanalytics.JsonFormatter.toJavaObject;
@@ -143,6 +145,8 @@ private static BigQuery createBigQuery(BigQueryLoggerConfig config) throws IOExc
143145
builder.setCredentials(
144146
GoogleCredentials.getApplicationDefault().createScoped(DEFAULT_AUTH_SCOPES));
145147
}
148+
builder = builder.setLocation(config.location());
149+
builder.setProjectId(config.projectId());
146150
return builder.build().getService();
147151
}
148152

@@ -172,28 +176,37 @@ private void ensureTableExists(BigQuery bigQuery, BigQueryLoggerConfig config) {
172176
tableDefinitionBuilder.setClustering(
173177
Clustering.newBuilder().setFields(config.clusteringFields()).build());
174178
}
175-
TableInfo tableInfo = TableInfo.newBuilder(tableId, tableDefinitionBuilder.build()).build();
179+
TableInfo tableInfo =
180+
TableInfo.newBuilder(tableId, tableDefinitionBuilder.build())
181+
.setLabels(
182+
ImmutableMap.of(
183+
BigQuerySchema.SCHEMA_VERSION_LABEL_KEY, BigQuerySchema.SCHEMA_VERSION))
184+
.build();
176185
bigQuery.create(tableInfo);
177186
} else if (config.autoSchemaUpgrade()) {
178-
// TODO(b/491851868): Implement auto-schema upgrade.
179-
logger.info("BigQuery table already exists and auto-schema upgrade is enabled: " + tableId);
180-
logger.info("Auto-schema upgrade is not implemented yet.");
187+
maybeUpgradeSchema(bigQuery, table);
181188
}
182189
} catch (BigQueryException e) {
183-
if (e.getMessage().contains("invalid_grant")) {
184-
logger.log(
185-
Level.SEVERE,
186-
"Failed to authenticate with BigQuery. Please run 'gcloud auth application-default"
187-
+ " login' to refresh your credentials or provide valid credentials in"
188-
+ " BigQueryLoggerConfig.",
189-
e);
190-
} else {
191-
logger.log(
192-
Level.WARNING, "Failed to check or create/upgrade BigQuery table: " + tableId, e);
193-
}
190+
processBigQueryException(e, "Failed to check or create/upgrade BigQuery table: " + tableId);
194191
} catch (RuntimeException e) {
195192
logger.log(Level.WARNING, "Failed to check or create/upgrade BigQuery table: " + tableId, e);
196193
}
194+
195+
try {
196+
if (config.createViews()) {
197+
var unused = executor.submit(() -> createAnalyticsViews(bigQuery, config));
198+
}
199+
} catch (RuntimeException e) {
200+
logger.log(Level.WARNING, "Failed to create/update BigQuery views for table: " + tableId, e);
201+
}
202+
}
203+
204+
private void processBigQueryException(BigQueryException e, String logMessage) {
205+
if (e.getMessage().contains("invalid_grant")) {
206+
logger.log(Level.SEVERE, "Failed to authenticate with BigQuery.", e);
207+
} else {
208+
logger.log(Level.WARNING, logMessage, e);
209+
}
197210
}
198211

199212
protected BigQueryWriteClient createWriteClient(BigQueryLoggerConfig config) throws IOException {

core/src/main/java/com/google/adk/plugins/agentanalytics/BigQueryLoggerConfig.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ public abstract class BigQueryLoggerConfig {
4343
// Max length for text content before truncation.
4444
public abstract int maxContentLength();
4545

46+
// BigQuery location.
47+
public abstract String location();
48+
4649
// Project ID for the BigQuery table.
4750
public abstract String projectId();
4851

@@ -93,9 +96,16 @@ public abstract class BigQueryLoggerConfig {
9396
// Automatically add new columns to existing tables when the plugin
9497
// schema evolves. Only additive changes are made (columns are never
9598
// dropped or altered).
96-
// TODO(b/491852782): Implement auto-schema upgrade.
9799
public abstract boolean autoSchemaUpgrade();
98100

101+
// Automatically create per-event-type BigQuery views that unnest
102+
// JSON columns into typed, queryable columns.
103+
public abstract boolean createViews();
104+
105+
// Prefix for auto-created per-event-type view names.
106+
// Default "v" produces views like ``v_llm_request``.
107+
public abstract String viewPrefix();
108+
99109
@Nullable
100110
public abstract Credentials credentials();
101111

@@ -105,6 +115,7 @@ public static Builder builder() {
105115
return new AutoValue_BigQueryLoggerConfig.Builder()
106116
.enabled(true)
107117
.maxContentLength(500 * 1024)
118+
.location("us") // Default location.
108119
.datasetId("agent_analytics")
109120
.tableName("events")
110121
.clusteringFields(ImmutableList.of("event_type", "agent", "user_id"))
@@ -118,8 +129,9 @@ public static Builder builder() {
118129
.customTags(ImmutableMap.of())
119130
.eventAllowlist(ImmutableList.of())
120131
.eventDenylist(ImmutableList.of())
121-
// TODO(b/491851868): Enable auto-schema upgrade once implemented.
122-
.autoSchemaUpgrade(false);
132+
.autoSchemaUpgrade(true)
133+
.createViews(false)
134+
.viewPrefix("v");
123135
}
124136

125137
/** Builder for {@link BigQueryLoggerConfig}. */
@@ -138,6 +150,9 @@ public abstract static class Builder {
138150
@CanIgnoreReturnValue
139151
public abstract Builder maxContentLength(int maxContentLength);
140152

153+
@CanIgnoreReturnValue
154+
public abstract Builder location(String location);
155+
141156
@CanIgnoreReturnValue
142157
public abstract Builder projectId(String projectId);
143158

@@ -184,6 +199,12 @@ public abstract Builder contentFormatter(
184199
@CanIgnoreReturnValue
185200
public abstract Builder autoSchemaUpgrade(boolean autoSchemaUpgrade);
186201

202+
@CanIgnoreReturnValue
203+
public abstract Builder createViews(boolean createViews);
204+
205+
@CanIgnoreReturnValue
206+
public abstract Builder viewPrefix(String viewPrefix);
207+
187208
@CanIgnoreReturnValue
188209
public abstract Builder credentials(Credentials credentials);
189210

core/src/main/java/com/google/adk/plugins/agentanalytics/BigQuerySchema.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ public final class BigQuerySchema {
4545

4646
private BigQuerySchema() {}
4747

48+
/**
49+
* The version of the BigQuery schema. Each time the schema is changed(new fields are added), this
50+
* should be incremented.
51+
*/
52+
static final String SCHEMA_VERSION = "1";
53+
54+
static final String SCHEMA_VERSION_LABEL_KEY = "adk_schema_version";
55+
4856
private static final ImmutableMap<StandardSQLTypeName, ImmutableMap<String, String>>
4957
FIELD_TYPE_TO_ARROW_FIELD_METADATA =
5058
ImmutableMap.of(

0 commit comments

Comments
 (0)