-
Notifications
You must be signed in to change notification settings - Fork 2k
[Server-Side Planning] Add metadata abstraction and factory pattern #5671
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
[Server-Side Planning] Add metadata abstraction and factory pattern #5671
Conversation
be90679 to
6ce4f27
Compare
|
Updated: Rebased on fixed Row 2. Fixed typo in |
|
Fixed regressions from Row 1 review:
|
6ce4f27 to
088a11a
Compare
|
Fixed additional regressions from Row 1:
Note: |
088a11a to
8169989
Compare
15009c6 to
6fd96c6
Compare
β¦able and add tests (#5622) ## π₯ Stacked PR Use this [link](https://github.com/delta-io/delta/pull/5622/files) to review all changes. **Stack:** - **[Integrate DeltaCatalog with ServerSidePlannedTable and add tests](#5622 [[Files changed](https://github.com/delta-io/delta/pull/5622/files)] β¬ οΈ _This PR_ - [Add metadata abstraction and factory pattern](#5671) [[Files changed](https://github.com/delta-io/delta/pull/5671/files/c94cf91814aa5bf3080f5191f75535f0cc5d2d51..f06cc6576c63ab1075bace94fb88d1a4a64ef308)] --- ## Summary Integrates server-side planning into DeltaCatalog.loadTable(): - Detect Unity Catalog tables without credentials - Return ServerSidePlannedTable instead of normal DeltaTableV2 - Add ENABLE_SERVER_SIDE_PLANNING config flag for testing - Move ServerSidePlannedTable to serverSidePlanning package ## Decision Logic ServerSidePlanning is used when: 1. `ENABLE_SERVER_SIDE_PLANNING` config is true (force flag for testing) 2. OR: Unity Catalog table without credentials (actual use case) ## Key Changes - `DeltaCatalog.loadTable()`: Add ServerSidePlannedTable.tryCreate() call - `ServerSidePlannedTable.shouldUseServerSidePlanning()`: Decision logic - Package refactor: Move from catalog/ to serverSidePlanning/ - Add `DeltaSQLConf.ENABLE_SERVER_SIDE_PLANNING` config ## Testing 4 tests covering: - Full query execution through DeltaCatalog - Normal path unchanged when disabled - Decision logic for all scenarios - Read-only enforcement (INSERT fails) ``` spark/testOnly org.apache.spark.sql.delta.serverSidePlanning.ServerSidePlannedTableSuite ``` Note: Tests verified in fork. Upstream master has kernel-api compilation issues (pre-existing, not related to these changes). Co-authored-by: Claude <[email protected]>
6fd96c6 to
802aa73
Compare
| * Test implementation of ServerSidePlanningMetadata with injectable values. | ||
| * Used in unit tests to mock UC metadata without a real UC instance. | ||
| */ | ||
| case class TestMetadata( |
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.
Removed UCMetadata from this PR as that contained references to iceberg-rest endpoint. We'll introduce that with the later catalog-specific PRs.
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.
why is this not a simple case class? and why does it need tests of its own when its such a simple class?
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.
and wht is the testmetadata even used for in this PR? if its not used, but is going to be used later, please introduce it later.
| * @param spark The SparkSession | ||
| * @param catalogName The name of the catalog (e.g., "spark_catalog", "unity") | ||
| * @return A ServerSidePlanningClient configured for the specified catalog | ||
| * @param metadata Metadata extracted from loadTable response |
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.
metadata necessary for serverside planning
(does not matter who extracted it)
| /** | ||
| * Authentication token for the planning endpoint. | ||
| */ | ||
| def authToken: Option[String] |
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.
in future we may want to generalize this to allow different auth mechanisms other than token.
| } | ||
| } | ||
|
|
||
| test("TestMetadata returns injected values") { |
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.
this is test of a test class... i dont think it makes sense. especially when the class is soo simple.
| * This interface captures all information from the catalog's loadTable response | ||
| * that is needed to create and configure a ServerSidePlanningClient. | ||
| */ | ||
| trait ServerSidePlanningMetadata { |
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.
does this need to be public?
| assert(metadata.tableProperties == Map("key1" -> "value1", "key2" -> "value2")) | ||
| } | ||
|
|
||
| test("DefaultMetadata provides empty defaults for non-UC catalogs") { |
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 DefaultMetadata has no logic inside it that is tied to UC. ServerSidePlanningMetadata.fromTable() is what you need to test .. isnt it? DefaultMetadata is just implementation details
β¦able and add tests (delta-io#5622) ## π₯ Stacked PR Use this [link](https://github.com/delta-io/delta/pull/5622/files) to review all changes. **Stack:** - **[Integrate DeltaCatalog with ServerSidePlannedTable and add tests](delta-io#5622 [[Files changed](https://github.com/delta-io/delta/pull/5622/files)] β¬ οΈ _This PR_ - [Add metadata abstraction and factory pattern](delta-io#5671) [[Files changed](https://github.com/delta-io/delta/pull/5671/files/c94cf91814aa5bf3080f5191f75535f0cc5d2d51..f06cc6576c63ab1075bace94fb88d1a4a64ef308)] --- ## Summary Integrates server-side planning into DeltaCatalog.loadTable(): - Detect Unity Catalog tables without credentials - Return ServerSidePlannedTable instead of normal DeltaTableV2 - Add ENABLE_SERVER_SIDE_PLANNING config flag for testing - Move ServerSidePlannedTable to serverSidePlanning package ## Decision Logic ServerSidePlanning is used when: 1. `ENABLE_SERVER_SIDE_PLANNING` config is true (force flag for testing) 2. OR: Unity Catalog table without credentials (actual use case) ## Key Changes - `DeltaCatalog.loadTable()`: Add ServerSidePlannedTable.tryCreate() call - `ServerSidePlannedTable.shouldUseServerSidePlanning()`: Decision logic - Package refactor: Move from catalog/ to serverSidePlanning/ - Add `DeltaSQLConf.ENABLE_SERVER_SIDE_PLANNING` config ## Testing 4 tests covering: - Full query execution through DeltaCatalog - Normal path unchanged when disabled - Decision logic for all scenarios - Read-only enforcement (INSERT fails) ``` spark/testOnly org.apache.spark.sql.delta.serverSidePlanning.ServerSidePlannedTableSuite ``` Note: Tests verified in fork. Upstream master has kernel-api compilation issues (pre-existing, not related to these changes). Co-authored-by: Claude <[email protected]>
Introduces metadata abstraction pattern for ServerSidePlannedTable to support different catalog types without hardcoding catalog-specific logic. **Metadata Abstraction:** - ServerSidePlanningMetadata trait encapsulates catalog-specific information - DefaultMetadata implementation for all catalogs (returns empty optional values) - TestMetadata implementation for unit testing with injectable values - Factory pattern: ServerSidePlanningMetadata.fromTable() creates appropriate metadata **Factory Pattern Changes:** - ServerSidePlanningClient factory changed from buildForCatalog(catalogName) to buildClient(metadata) - Enables catalog-specific configuration without changing client interface **Unity Catalog Integration:** Unity Catalog-specific metadata implementation will be added in Row 8 with Iceberg REST catalog integration. This PR focuses on the abstraction pattern only. **Tests (7 total):** - Full query execution through DeltaCatalog - Decision logic for server-side planning - DefaultMetadata returns None for all optional fields - TestMetadata returns injected values - Read-only enforcement - Normal path unchanged when disabled - All metadata factory method logic **Note:** Spark module only - excludes iceberg module changes for Row 7/8. π€ Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
802aa73 to
6d76fce
Compare
|
Thanks for the review @tdas! Addressed your feedback:
Note on authToken comment: Captured for future PR - we may want to generalize auth mechanisms. Commit: 6d76fce |
| } | ||
| } | ||
|
|
||
| test("fromTable returns metadata with empty defaults for non-UC catalogs") { |
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.
what fromTable? you have to say ServerSidePlanningMetadata.fromTable?
please address in the follow up PR
## Stacked PR Use this [link](https://github.com/delta-io/delta/pull/5672/files) to review all changes. **Stack:** - [Integrate DeltaCatalog with ServerSidePlannedTable and add tests](#5622) [[Files changed](https://github.com/delta-io/delta/pull/5622/files)] - [Add metadata abstraction and factory pattern](#5671) [[Files changed](https://github.com/delta-io/delta/pull/5671/files)] - **[Add filter pushdown infrastructure](#5672 [[Files changed](https://github.com/delta-io/delta/pull/5672/files)] <-- _This PR_ - [Add projection pushdown infrastructure](#5685) [[Files changed](https://github.com/delta-io/delta/pull/5685/files/f5bc498a47be8fc7457269939d510a2ccaba52ba..5b3a008a94a7d35f91868e93205b75fc65569ebb)] --- ## Summary Adds generic filter pushdown infrastructure to ServerSidePlanningClient: - Add filter parameter to **ServerSidePlanningClient.planScan()** interface - Use Spark's **Filter** type as catalog-agnostic representation - Implement **SupportsPushDownFilters** in ServerSidePlannedScanBuilder - Capture filter in **TestServerSidePlanningClient** companion object for test verification - Tests verifying filters are passed through to planning client correctly ## Key Changes **Modified files (4):** - `ServerSidePlanningClient.scala` - Added filter parameter - `ServerSidePlannedTable.scala` - Implements SupportsPushDownFilters, passes filters through to planning client - `TestServerSidePlanningClient.scala` - Added companion object to capture filter for test verification - `ServerSidePlannedTableSuite.scala` - Added 3 filter passthrough tests ## Design ### Conservative Filter Handling We return all filters as "residuals" (meaning Spark will re-apply them after the catalog returns results). This is conservative but correct: - We don't know yet what the catalog can handle - Better to redundantly filter (slow but correct) than claim we handle filters we don't (fast but wrong) - Future PRs will add catalog capabilities to avoid redundant filtering ### Filter Combining When multiple filters are pushed (e.g., `WHERE id > 1 AND value < 30`), we combine them into a single And filter before sending to the planning client. This keeps the interface simple (single Option[Filter] instead of Array[Filter]). ## Testing 8 tests total (spark module only): - Full query execution through DeltaCatalog - Decision logic for server-side planning - ServerSidePlanningMetadata.fromTable() returns metadata with defaults - ServerSidePlannedTable is read-only - Normal path unchanged when feature disabled - **Simple EqualTo filter (WHERE id = 2)** - **Compound And filter (WHERE id > 1 AND value < 30)** - **No filter when no WHERE clause** ## Behavior **Filter passthrough working:** - Filters from SQL WHERE clauses are captured and passed to planning client - Test infrastructure validates filter objects are passed correctly - Planning client receives filters but doesn't apply logic yet (next PR) - Spark re-applies filters as residuals (conservative approach ensures correctness) **No behavior changes to existing functionality:** - Zero impact on existing Delta behavior - Feature only activates when config flag enabled - This PR enables future catalog implementations to receive and process filter pushdown --- **Commit:** f5bc498 --------- Co-authored-by: Claude <[email protected]>
## π₯ Stacked PR Use this [link](https://github.com/delta-io/delta/pull/5685/files) to review all changes. **Stack:** - [#5621 - ServerSidePlanningClient interface and DSv2 table](#5621) [[Files changed](https://github.com/delta-io/delta/pull/5621/files)] - β Merged - [#5622 - Integrate DeltaCatalog with ServerSidePlanning](#5622) [[Files changed](https://github.com/delta-io/delta/pull/5622/files)] - β Merged - [#5671 - Add metadata abstraction and factory pattern](#5671) [[Files changed](https://github.com/delta-io/delta/pull/5671/files)] - β Merged - [#5672 - Add filter pushdown infrastructure](#5672) [[Files changed](https://github.com/delta-io/delta/pull/5672/files)] - β Merged - **[#5685 - Add projection pushdown infrastructure](#5685 [[Files changed](https://github.com/delta-io/delta/pull/5685/files)] β¬ οΈ _This PR_ --- # [Server-Side Planning] Add projection pushdown infrastructure This PR adds infrastructure for pushing down column projections (SELECT column list) to the server-side planning client. ## What This PR Does 1. **Add projection parameter to `planScan()` interface** - New optional `projection: Option[StructType]` parameter - Allows catalogs to receive required column information 2. **Implement `SupportsPushDownRequiredColumns` in `ServerSidePlannedScanBuilder`** - Spark calls `pruneColumns(requiredSchema)` when columns are pruned - Stores required schema to pass to server 3. **Pass projection through to `planScan()` call** - Only send projection if columns are actually pruned (not SELECT *) - Catalog can use this to optimize file reading (skip columns, etc.) 4. **Extend test infrastructure** - `TestServerSidePlanningClient` now captures both filter AND projection - Companion object provides `getCapturedFilter()` and `getCapturedProjection()` - Added 3 new tests for projection pushdown ## Files Changed ### Modified Files (4 files) - `spark/src/main/scala/.../ServerSidePlanningClient.scala` - Add projection parameter - `spark/src/main/scala/.../ServerSidePlannedTable.scala` - Implement SupportsPushDownRequiredColumns - `spark/src/test/scala/.../TestServerSidePlanningClient.scala` - Add projection capturing - `spark/src/test/scala/.../ServerSidePlannedTableSuite.scala` - Add projection tests ## Tests Total: **11 tests** (8 existing + 3 new projection tests) **New projection tests:** - `"projection pushed when selecting specific columns"` - Verifies projection for `SELECT id, name` - `"no projection pushed when selecting all columns"` - Verifies `None` for `SELECT *` - `"projection and filter pushed together"` - Verifies both work simultaneously **Existing tests** (from previous PRs): - Simple EqualTo filter - Compound And filter - No filter when no WHERE clause - Full query through DeltaCatalog - Normal path unchanged when disabled - Decision logic tests - Read-only verification - Metadata factory test ## Design Notes **Conservative approach:** Like filter pushdown, we pass all required columns to the catalog but don't claim we've eliminated any. Spark will still validate the schema post-read. This ensures correctness while allowing catalogs to optimize (skip columns, read less data, etc.) **Interface design:** Uses `StructType` (Spark's standard schema representation) to remain catalog-agnostic. Each catalog can interpret the projection in their own way. --------- Co-authored-by: Claude <[email protected]>
π₯ Stacked PR
Use this link to review all changes.
Stack:
Summary
Introduces metadata abstraction pattern for ServerSidePlannedTable:
ServerSidePlanningMetadatatrait for catalog-specific configurationbuildForCatalog()tobuildClient(metadata)Key Changes
New file:
ServerSidePlanningMetadata.scala- Trait + DefaultMetadata + factory methodModified files:
ServerSidePlanningClient.scala- Update factory interface to accept metadataServerSidePlannedTable.scala- Use metadata factory, pass metadata to client builderServerSidePlannedTableSuite.scala- Test fromTable() methodArchitecture
Design Principles
1. Metadata as Interface
ServerSidePlanningMetadatatrait captures what's needed to create a planning client:planningEndpointUri- REST endpoint (empty for default)authToken- Authentication token (None for default)catalogName- For configuration lookupstableProperties- Additional table properties2. Factory Method for Metadata
ServerSidePlanningMetadata.fromTable()extracts metadata from loaded table:3. Package-Private Implementation
Trait and classes are
private[serverSidePlanning]- implementation details hidden from outside.Testing
6 tests covering:
Behavior
No functional changes:
Commit: 6d76fce