Implementation:Apache Paimon ViewChange
| Knowledge Sources | |
|---|---|
| Domains | View Management, DDL Operations |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
ViewChange is a sealed interface hierarchy that defines all possible modification operations that can be applied to Paimon views, analogous to SchemaChange for tables.
Description
ViewChange represents the contract for view evolution in Apache Paimon. Similar to SchemaChange, it uses Jackson JSON polymorphic type annotations to enable serialization and deserialization, making it suitable for REST APIs, catalog operations, and DDL execution. The interface provides static factory methods for creating each type of view modification, including operations on view options (SetViewOption, RemoveViewOption), view metadata (UpdateViewComment), and dialect-specific query management (AddDialect, UpdateDialect, DropDialect).
Each view change type is implemented as a final inner class with immutable fields, ensuring thread-safety and predictability. The dialect-related operations are particularly important for Paimon's multi-dialect view support, allowing views to store SQL query definitions for different compute engines (e.g., Flink SQL, Spark SQL, Hive SQL). This enables a view to be queried from multiple engines while maintaining engine-specific optimizations or syntax variations.
The interface is marked with @Public annotation, indicating its stability as part of the Paimon public API. This ensures backward compatibility and makes it suitable for use by external tools, catalog implementations, and REST endpoints that need to modify view definitions programmatically.
Usage
Use ViewChange when implementing ALTER VIEW operations, view evolution logic in catalogs, or when serializing view modifications for storage or transmission. Each static factory method creates an appropriate ViewChange instance that can be applied to a view definition.
Code Reference
Source Location
- Repository: Apache_Paimon
- File: paimon-api/src/main/java/org/apache/paimon/view/ViewChange.java
- Lines: 34-354
Signature
@Public
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY,
property = ViewChange.Actions.FIELD_TYPE)
@JsonSubTypes({
@JsonSubTypes.Type(value = ViewChange.SetViewOption.class, name = "setOption"),
@JsonSubTypes.Type(value = ViewChange.RemoveViewOption.class, name = "removeOption"),
@JsonSubTypes.Type(value = ViewChange.UpdateViewComment.class, name = "updateComment"),
@JsonSubTypes.Type(value = ViewChange.AddDialect.class, name = "addDialect"),
@JsonSubTypes.Type(value = ViewChange.UpdateDialect.class, name = "updateDialect"),
@JsonSubTypes.Type(value = ViewChange.DropDialect.class, name = "dropDialect")
})
public interface ViewChange extends Serializable {
static ViewChange setOption(String key, String value);
static ViewChange removeOption(String key);
static ViewChange updateComment(String comment);
static ViewChange addDialect(String dialect, String query);
static ViewChange updateDialect(String dialect, String query);
static ViewChange dropDialect(String dialect);
}
Import
import org.apache.paimon.view.ViewChange;
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| key | String | yes | Configuration key for SetViewOption/RemoveViewOption |
| value | String | yes | Configuration value for SetViewOption |
| comment | String | yes | Comment text for UpdateViewComment |
| dialect | String | yes | SQL dialect name (e.g., "flink", "spark", "hive") |
| query | String | yes | SQL query definition for the dialect |
Outputs
| Name | Type | Description |
|---|---|---|
| viewChange | ViewChange | Immutable view change instance representing the operation |
Usage Examples
Managing View Options
// Set a view option
ViewChange setOpt = ViewChange.setOption(
"refresh.interval",
"10min"
);
// Remove a view option
ViewChange removeOpt = ViewChange.removeOption("refresh.interval");
// Update view comment
ViewChange updateComment = ViewChange.updateComment(
"Materialized view of daily user statistics"
);
Adding Dialect-Specific Queries
// Add Flink SQL dialect
ViewChange addFlink = ViewChange.addDialect(
"flink",
"SELECT user_id, COUNT(*) as cnt FROM orders GROUP BY user_id"
);
// Add Spark SQL dialect with different syntax
ViewChange addSpark = ViewChange.addDialect(
"spark",
"SELECT user_id, COUNT(1) as cnt FROM orders GROUP BY user_id"
);
// Add Hive SQL dialect
ViewChange addHive = ViewChange.addDialect(
"hive",
"SELECT user_id, count(*) as cnt FROM orders GROUP BY user_id"
);
Updating Dialect Queries
// Update existing dialect query
ViewChange updateQuery = ViewChange.updateDialect(
"flink",
"SELECT user_id, COUNT(*) as cnt, SUM(amount) as total " +
"FROM orders GROUP BY user_id"
);
// Update to use different window function
ViewChange updateWindow = ViewChange.updateDialect(
"flink",
"SELECT user_id, " +
" COUNT(*) OVER (PARTITION BY user_id) as cnt " +
"FROM orders"
);
Removing Dialect Support
// Drop dialect support
ViewChange dropDialect = ViewChange.dropDialect("hive");
// Remove obsolete dialect
ViewChange removeOldDialect = ViewChange.dropDialect("legacy-sql");
Multi-Dialect View Creation
// Create view with multiple dialect support
public List<ViewChange> createMultiDialectView() {
List<ViewChange> changes = new ArrayList<>();
// Set view metadata
changes.add(ViewChange.updateComment(
"User order summary view"
));
// Add Flink SQL version
changes.add(ViewChange.addDialect(
"flink",
"SELECT u.user_id, u.name, " +
" COUNT(o.order_id) as order_count, " +
" SUM(o.amount) as total_amount " +
"FROM users u " +
"LEFT JOIN orders o ON u.user_id = o.user_id " +
"GROUP BY u.user_id, u.name"
));
// Add Spark SQL version (similar but may have dialect differences)
changes.add(ViewChange.addDialect(
"spark",
"SELECT u.user_id, u.name, " +
" COUNT(o.order_id) as order_count, " +
" SUM(o.amount) as total_amount " +
"FROM users u " +
"LEFT JOIN orders o ON u.user_id = o.user_id " +
"GROUP BY u.user_id, u.name"
));
return changes;
}
View Evolution Workflow
// Complete view modification workflow
public void evolveView(String viewName, String newQuery) {
List<ViewChange> changes = new ArrayList<>();
// Update comment
changes.add(ViewChange.updateComment(
"Updated view definition - " + LocalDateTime.now()
));
// Update Flink dialect
changes.add(ViewChange.updateDialect("flink", newQuery));
// Apply changes through catalog
catalog.alterView(
new ObjectPath("default", viewName),
changes
);
}
Conditional Dialect Management
// Add or update dialect based on existence
public ViewChange upsertDialect(String dialect, String query,
boolean dialectExists) {
if (dialectExists) {
return ViewChange.updateDialect(dialect, query);
} else {
return ViewChange.addDialect(dialect, query);
}
}
// Migrate from one dialect to another
public List<ViewChange> migrateDialect(String fromDialect,
String toDialect,
String newQuery) {
return Arrays.asList(
ViewChange.dropDialect(fromDialect),
ViewChange.addDialect(toDialect, newQuery)
);
}
View Configuration Management
// Configure view refresh settings
public List<ViewChange> configureRefresh(Duration interval,
boolean autoRefresh) {
List<ViewChange> changes = new ArrayList<>();
changes.add(ViewChange.setOption(
"refresh.interval",
interval.toString()
));
changes.add(ViewChange.setOption(
"refresh.auto",
String.valueOf(autoRefresh)
));
return changes;
}
// Clear view configuration
public List<ViewChange> clearConfiguration(List<String> keys) {
return keys.stream()
.map(ViewChange::removeOption)
.collect(Collectors.toList());
}
Serialization Example
// Serialize view changes to JSON
ObjectMapper mapper = new ObjectMapper();
ViewChange change = ViewChange.addDialect(
"flink",
"SELECT * FROM source_table"
);
String json = mapper.writeValueAsString(change);
// JSON includes action type and parameters
// Deserialize from JSON
ViewChange restored = mapper.readValue(json, ViewChange.class);