This is an automated email from the ASF dual-hosted git repository.
yuqi1129 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 8e2d4ddafb [#11912] feat(clickhouse): support set data skipping index
type (#11916)
8e2d4ddafb is described below
commit 8e2d4ddafbb5c1d2973320c34316ddeac10b494a
Author: StormSpirit <[email protected]>
AuthorDate: Fri Jul 10 08:55:38 2026 +0800
[#11912] feat(clickhouse): support set data skipping index type (#11916)
### What changes were proposed in this pull request?
- Add set data skipping index type to the Index API
- Support set index in CREATE TABLE, ALTER TABLE, and table loading
- Refactor index DDL generation into a shared helper
### Why are the changes needed?
Fix: #11912
The ClickHouse catalog only supports minmax and bloom_filter skip
indexes. Tables with set indexes load without error but index metadata
is silently dropped, and explicit creation attempts fail. The set index
type has no required parameters (unlike ngrambf_v1/tokenbf_v1), making
it safe to add without a parameter-passing mechanism.
### Does this PR introduce any user-facing change?
Yes. ClickHouse tables with set data skipping indexes can now be created
and loaded through Gravitino with index metadata preserved.
### How was this patch tested?
**Unit tests** (`TestClickHouseTableOperations`):
- `testGetClickHouseIndexType`: verifies index type string-to-enum
mapping (minmax, bloom_filter, set)
**Integration tests** (`CatalogClickHouseIT`):
- `testCreateAndLoadWithPartitionSortAndIndexes`: extended with SET
index create/load round-trip
- `testAlterTableAddIndexWithSetIndex`: ALTER TABLE ADD INDEX with SET
type
Both test classes require `-PskipDockerTests=false` to run.
---------
Signed-off-by: jiangxt2 <[email protected]>
---
.../org/apache/gravitino/rel/indexes/Index.java | 3 +
.../catalog/clickhouse/ClickHouseConstants.java | 3 +
.../operations/ClickHouseTableOperations.java | 66 +++++++++++++++++-----
.../test/CatalogClickHouseClusterIT.java | 18 ++++++
.../integration/test/CatalogClickHouseIT.java | 45 +++++++++++++--
.../operations/TestClickHouseTableOperations.java | 40 +++++++++++++
docs/jdbc-clickhouse-catalog.md | 3 +-
7 files changed, 157 insertions(+), 21 deletions(-)
diff --git a/api/src/main/java/org/apache/gravitino/rel/indexes/Index.java
b/api/src/main/java/org/apache/gravitino/rel/indexes/Index.java
index d299683889..9f725c19cc 100644
--- a/api/src/main/java/org/apache/gravitino/rel/indexes/Index.java
+++ b/api/src/main/java/org/apache/gravitino/rel/indexes/Index.java
@@ -129,5 +129,8 @@ public interface Index {
/** Bloom filter data skipping index */
DATA_SKIPPING_BLOOM_FILTER,
+
+ /** Set data skipping index */
+ DATA_SKIPPING_SET,
}
}
diff --git
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/ClickHouseConstants.java
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/ClickHouseConstants.java
index 38428e82aa..a2fca9f7b7 100644
---
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/ClickHouseConstants.java
+++
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/ClickHouseConstants.java
@@ -57,5 +57,8 @@ public class ClickHouseConstants {
// The name of the data skipping index type for bloom filter index in
clickhouse.
public static final String DATA_SKIPPING_BLOOM_FILTER = "bloom_filter";
+
+ // The name of the data skipping index type for set index in clickhouse.
+ public static final String DATA_SKIPPING_SET = "set";
}
}
diff --git
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
index 6eb48dcea0..1472b6061e 100644
---
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
+++
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
@@ -20,6 +20,7 @@ package org.apache.gravitino.catalog.clickhouse.operations;
import static
org.apache.gravitino.catalog.clickhouse.ClickHouseConstants.IndexConstants.DATA_SKIPPING_BLOOM_FILTER;
import static
org.apache.gravitino.catalog.clickhouse.ClickHouseConstants.IndexConstants.DATA_SKIPPING_MINMAX_VALUE;
+import static
org.apache.gravitino.catalog.clickhouse.ClickHouseConstants.IndexConstants.DATA_SKIPPING_SET;
import static
org.apache.gravitino.catalog.clickhouse.ClickHouseTablePropertiesMetadata.CLICKHOUSE_ENGINE_KEY;
import static
org.apache.gravitino.catalog.clickhouse.ClickHouseTablePropertiesMetadata.ENGINE_PROPERTY_ENTRY;
import static
org.apache.gravitino.catalog.clickhouse.ClickHouseTablePropertiesMetadata.GRAVITINO_ENGINE_KEY;
@@ -479,23 +480,27 @@ public class ClickHouseTableOperations extends
JdbcTableOperations {
sqlBuilder.append(" PRIMARY KEY (").append(fieldStr).append(")");
break;
case DATA_SKIPPING_MINMAX:
- Preconditions.checkArgument(
- StringUtils.isNotBlank(index.name()), "Data skipping index name
must not be blank");
// The GRANULARITY value is always 1 here currently as we can't set
it by Index: there is
// no field for it.
// TODO(yuqi) add a properties field to Index to support user
defined GRANULARITY value.
- sqlBuilder.append(
- " INDEX %s %s TYPE minmax GRANULARITY 1"
- .formatted(quoteIdentifier(index.name()), fieldStr));
+ sqlBuilder
+ .append(" ")
+ .append(buildDataSkippingIndexDdl(index.name(), fieldStr,
"minmax", 1));
break;
case DATA_SKIPPING_BLOOM_FILTER:
// The GRANULARITY value is always 3 here currently.
// TODO(yuqi) add a properties field to Index to support user
defined GRANULARITY value.
- Preconditions.checkArgument(
- StringUtils.isNotBlank(index.name()), "Data skipping index name
must not be blank");
- sqlBuilder.append(
- " INDEX %s %s TYPE bloom_filter GRANULARITY 3"
- .formatted(quoteIdentifier(index.name()), fieldStr));
+ sqlBuilder
+ .append(" ")
+ .append(buildDataSkippingIndexDdl(index.name(), fieldStr,
"bloom_filter", 3));
+ break;
+ case DATA_SKIPPING_SET:
+ // The max unique values (N) is always 0 (unlimited) here currently
as we can't set it
+ // by Index: there is no field for it. ClickHouse requires set(N)
syntax.
+ // TODO(yuqi) add a properties field to Index to support user
defined max unique values.
+ sqlBuilder
+ .append(" ")
+ .append(buildDataSkippingIndexDdl(index.name(), fieldStr,
"set(0)", 1));
break;
default:
throw new IllegalArgumentException(
@@ -858,12 +863,16 @@ public class ClickHouseTableOperations extends
JdbcTableOperations {
String fieldStr = getIndexFieldStr(addIndex.getFieldNames());
switch (addIndex.getType()) {
case DATA_SKIPPING_MINMAX:
- return "ADD INDEX %s %s TYPE minmax GRANULARITY 1"
- .formatted(quoteIdentifier(addIndex.getName()), fieldStr);
+ return "ADD " + buildDataSkippingIndexDdl(addIndex.getName(),
fieldStr, "minmax", 1);
case DATA_SKIPPING_BLOOM_FILTER:
- return "ADD INDEX %s %s TYPE bloom_filter GRANULARITY 3"
- .formatted(quoteIdentifier(addIndex.getName()), fieldStr);
+ return "ADD " + buildDataSkippingIndexDdl(addIndex.getName(),
fieldStr, "bloom_filter", 3);
+
+ case DATA_SKIPPING_SET:
+ // The max unique values (N) is always 0 (unlimited) here currently as
we can't set it
+ // by Index: there is no field for it. ClickHouse requires set(N)
syntax.
+ // TODO(yuqi) add a properties field to Index to support user defined
max unique values.
+ return "ADD " + buildDataSkippingIndexDdl(addIndex.getName(),
fieldStr, "set(0)", 1);
case PRIMARY_KEY:
throw new UnsupportedOperationException(
@@ -1290,7 +1299,19 @@ public class ClickHouseTableOperations extends
JdbcTableOperations {
return secondaryIndexes;
}
- private Index.IndexType getClickHouseIndexType(String rawType) {
+ /**
+ * Maps a ClickHouse data skipping index type string to the corresponding
Gravitino {@link
+ * Index.IndexType}. Returns {@code DATA_SKIPPING_MINMAX} for blank/null
input (ClickHouse
+ * default). Also handles the {@code set(N)} parameterized format that some
ClickHouse versions
+ * may return from {@code system.data_skipping_indices}.
+ *
+ * @param rawType the index type string from ClickHouse metadata (e.g.
"minmax", "bloom_filter",
+ * "set", "set(0)")
+ * @return the corresponding Gravitino IndexType
+ * @throws IllegalArgumentException if the type is not supported
+ */
+ @VisibleForTesting
+ Index.IndexType getClickHouseIndexType(String rawType) {
if (StringUtils.isBlank(rawType)) {
return Index.IndexType.DATA_SKIPPING_MINMAX;
}
@@ -1300,11 +1321,26 @@ public class ClickHouseTableOperations extends
JdbcTableOperations {
return Index.IndexType.DATA_SKIPPING_MINMAX;
case DATA_SKIPPING_BLOOM_FILTER:
return Index.IndexType.DATA_SKIPPING_BLOOM_FILTER;
+ case DATA_SKIPPING_SET:
+ return Index.IndexType.DATA_SKIPPING_SET;
default:
+ // ClickHouse may return "set(N)" with parameter in some versions;
+ // match on prefix to handle both "set" and "set(N)" formats.
+ if (rawType.startsWith(DATA_SKIPPING_SET + "(")) {
+ return Index.IndexType.DATA_SKIPPING_SET;
+ }
throw new IllegalArgumentException("Unsupported data skipping index
type: " + rawType);
}
}
+ private String buildDataSkippingIndexDdl(
+ String indexName, String fieldStr, String typeName, int granularity) {
+ Preconditions.checkArgument(
+ StringUtils.isNotBlank(indexName), "Data skipping index name must not
be blank");
+ return "INDEX %s %s TYPE %s GRANULARITY %d"
+ .formatted(quoteIdentifier(indexName), fieldStr, typeName,
granularity);
+ }
+
private StringBuilder appendColumnDefinition(JdbcColumn column,
StringBuilder sqlBuilder) {
// Add Nullable data type
String dataType = typeConverter.fromGravitino(column.dataType());
diff --git
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseClusterIT.java
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseClusterIT.java
index 48d6ee8f89..7cfdde2b7b 100644
---
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseClusterIT.java
+++
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseClusterIT.java
@@ -506,6 +506,24 @@ public class CatalogClickHouseClusterIT extends BaseIT {
Arrays.stream(loaded.index())
.anyMatch(index -> Objects.equals(index.name(), "idx_col_1_new")));
+ tableCatalog.alterTable(
+ tableIdentifier,
+ TableChange.addIndex(
+ Index.IndexType.DATA_SKIPPING_SET, "idx_col_2_set", new String[][]
{{"col_2"}}));
+ loaded = tableCatalog.loadTable(tableIdentifier);
+ Assertions.assertTrue(
+ Arrays.stream(loaded.index())
+ .anyMatch(
+ index ->
+ Objects.equals(index.name(), "idx_col_2_set")
+ && index.type() == Index.IndexType.DATA_SKIPPING_SET
+ && Arrays.deepEquals(index.fieldNames(), new
String[][] {{"col_2"}})));
+ tableCatalog.alterTable(tableIdentifier,
TableChange.deleteIndex("idx_col_2_set", false));
+ loaded = tableCatalog.loadTable(tableIdentifier);
+ Assertions.assertFalse(
+ Arrays.stream(loaded.index())
+ .anyMatch(index -> Objects.equals(index.name(), "idx_col_2_set")));
+
RuntimeException autoIncrementTrueException =
Assertions.assertThrows(
RuntimeException.class,
diff --git
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
index eeb31d5731..b62c6d31da 100644
---
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
+++
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
@@ -509,7 +509,9 @@ public class CatalogClickHouseIT extends BaseIT {
new Index[] {
Indexes.primary(Indexes.DEFAULT_PRIMARY_KEY_NAME, new String[][]
{{"user_id"}}),
Indexes.of(
- Index.IndexType.DATA_SKIPPING_MINMAX, "idx_amount", new
String[][] {{"amount"}})
+ Index.IndexType.DATA_SKIPPING_MINMAX, "idx_amount", new
String[][] {{"amount"}}),
+ Indexes.of(
+ Index.IndexType.DATA_SKIPPING_SET, "idx_userid_set", new
String[][] {{"user_id"}})
};
catalog
@@ -554,6 +556,13 @@ public class CatalogClickHouseIT extends BaseIT {
idx ->
idx.type() == Index.IndexType.DATA_SKIPPING_MINMAX
&& Arrays.deepEquals(idx.fieldNames(), new String[][]
{{"amount"}})));
+ Assertions.assertTrue(
+ Arrays.stream(loadedIndexes)
+ .anyMatch(
+ idx ->
+ idx.type() == Index.IndexType.DATA_SKIPPING_SET
+ && idx.name().equals("idx_userid_set")
+ && Arrays.deepEquals(idx.fieldNames(), new String[][]
{{"user_id"}})));
}
@Test
@@ -1334,7 +1343,8 @@ public class CatalogClickHouseIT extends BaseIT {
};
Index[] indexes =
new Index[] {
- Indexes.of(Index.IndexType.DATA_SKIPPING_MINMAX, "idx_note", new
String[][] {{"note"}})
+ Indexes.of(Index.IndexType.DATA_SKIPPING_MINMAX, "idx_note", new
String[][] {{"note"}}),
+ Indexes.of(Index.IndexType.DATA_SKIPPING_SET, "idx_note_set", new
String[][] {{"note"}})
};
TableCatalog tableCatalog = catalog.asTableCatalog();
tableCatalog.createTable(
@@ -1352,12 +1362,18 @@ public class CatalogClickHouseIT extends BaseIT {
tableCatalog.alterTable(
tableIdentifier,
TableChange.updateColumnComment(new String[] {"score"}, "score column
changed"));
- tableCatalog.alterTable(tableIdentifier,
TableChange.deleteIndex("idx_note", false));
+ tableCatalog.alterTable(
+ tableIdentifier,
+ TableChange.deleteIndex("idx_note", false),
+ TableChange.deleteIndex("idx_note_set", false));
Table loaded = tableCatalog.loadTable(tableIdentifier);
Assertions.assertTrue(loaded.columns()[1].nullable());
Assertions.assertEquals("score column changed",
loaded.columns()[1].comment());
Assertions.assertFalse(
Arrays.stream(loaded.index()).anyMatch(index ->
Objects.equals(index.name(), "idx_note")));
+ Assertions.assertFalse(
+ Arrays.stream(loaded.index())
+ .anyMatch(index -> Objects.equals(index.name(), "idx_note_set")));
Assertions.assertDoesNotThrow(
() ->
@@ -1416,7 +1432,8 @@ public class CatalogClickHouseIT extends BaseIT {
Indexes.of(
Index.IndexType.DATA_SKIPPING_BLOOM_FILTER,
"idx_note_bloom",
- new String[][] {{"note"}})
+ new String[][] {{"note"}}),
+ Indexes.of(Index.IndexType.DATA_SKIPPING_SET, "idx_score_set", new
String[][] {{"score"}})
};
TableCatalog tableCatalog = catalog.asTableCatalog();
tableCatalog.createTable(
@@ -1433,15 +1450,27 @@ public class CatalogClickHouseIT extends BaseIT {
tableIdentifier,
TableChange.addIndex(
Index.IndexType.DATA_SKIPPING_MINMAX, "idx_new", new String[][]
{{"score"}}));
+ tableCatalog.alterTable(
+ tableIdentifier,
+ TableChange.addIndex(
+ Index.IndexType.DATA_SKIPPING_SET, "idx_new_set", new String[][]
{{"note"}}));
Table loaded = tableCatalog.loadTable(tableIdentifier);
Assertions.assertTrue(
Arrays.stream(loaded.index()).anyMatch(index ->
Objects.equals(index.name(), "idx_new")));
+ Assertions.assertTrue(
+ Arrays.stream(loaded.index())
+ .anyMatch(
+ index ->
+ Objects.equals(index.name(), "idx_new_set")
+ && index.type() == Index.IndexType.DATA_SKIPPING_SET));
tableCatalog.alterTable(
tableIdentifier,
TableChange.deleteIndex("idx_score_minmax", false),
TableChange.deleteIndex("idx_note_bloom", false),
- TableChange.deleteIndex("idx_new", false));
+ TableChange.deleteIndex("idx_score_set", false),
+ TableChange.deleteIndex("idx_new", false),
+ TableChange.deleteIndex("idx_new_set", false));
loaded = tableCatalog.loadTable(tableIdentifier);
Assertions.assertFalse(
Arrays.stream(loaded.index())
@@ -1449,8 +1478,14 @@ public class CatalogClickHouseIT extends BaseIT {
Assertions.assertFalse(
Arrays.stream(loaded.index())
.anyMatch(index -> Objects.equals(index.name(),
"idx_note_bloom")));
+ Assertions.assertFalse(
+ Arrays.stream(loaded.index())
+ .anyMatch(index -> Objects.equals(index.name(), "idx_score_set")));
Assertions.assertFalse(
Arrays.stream(loaded.index()).anyMatch(index ->
Objects.equals(index.name(), "idx_new")));
+ Assertions.assertFalse(
+ Arrays.stream(loaded.index())
+ .anyMatch(index -> Objects.equals(index.name(), "idx_new_set")));
RuntimeException autoIncrementTrueException =
Assertions.assertThrows(
diff --git
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
index 93c928a539..b9e12b200a 100644
---
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
+++
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
@@ -1099,6 +1099,7 @@ public class TestClickHouseTableOperations extends
TestClickHouse {
Indexes.primary(Indexes.DEFAULT_PRIMARY_KEY_NAME, new String[][]
{{"c1"}}),
Indexes.of(IndexType.DATA_SKIPPING_MINMAX, "idx_c2", new String[][]
{{"c2"}}),
Indexes.of(IndexType.DATA_SKIPPING_BLOOM_FILTER, "idx_c3", new
String[][] {{"c3"}}),
+ Indexes.of(IndexType.DATA_SKIPPING_SET, "idx_c4", new String[][]
{{"c2"}}),
};
String sql =
@@ -1115,6 +1116,7 @@ public class TestClickHouseTableOperations extends
TestClickHouse {
Assertions.assertTrue(sql.contains("PARTITION BY `c1`"));
Assertions.assertTrue(sql.contains("INDEX `idx_c2` `c2` TYPE minmax
GRANULARITY 1"));
Assertions.assertTrue(sql.contains("INDEX `idx_c3` `c3` TYPE bloom_filter
GRANULARITY 3"));
+ Assertions.assertTrue(sql.contains("INDEX `idx_c4` `c2` TYPE set(0)
GRANULARITY 1"));
}
@Test
@@ -1338,6 +1340,15 @@ public class TestClickHouseTableOperations extends
TestClickHouse {
Assertions.assertTrue(
bloomSql.contains("ADD INDEX `idx_bf` `c2` TYPE bloom_filter
GRANULARITY 3"));
+ String setSql =
+ ops.buildAlterSql(
+ "db",
+ "tbl",
+ new TableChange[] {
+ TableChange.addIndex(IndexType.DATA_SKIPPING_SET, "idx_set", new
String[][] {{"c2"}})
+ });
+ Assertions.assertTrue(setSql.contains("ADD INDEX `idx_set` `c2` TYPE
set(0) GRANULARITY 1"));
+
Assertions.assertThrows(
IllegalArgumentException.class,
() ->
@@ -1360,6 +1371,35 @@ public class TestClickHouseTableOperations extends
TestClickHouse {
}));
}
+ @Test
+ public void testGetClickHouseIndexType() {
+ StubClickHouseTableOperations ops = new StubClickHouseTableOperations();
+ ops.initialize(
+ null,
+ new ClickHouseExceptionConverter(),
+ new ClickHouseTypeConverter(),
+ new ClickHouseColumnDefaultValueConverter(),
+ new HashMap<>());
+
+ // Exact matches
+ Assertions.assertEquals(IndexType.DATA_SKIPPING_MINMAX,
ops.getClickHouseIndexType("minmax"));
+ Assertions.assertEquals(
+ IndexType.DATA_SKIPPING_BLOOM_FILTER,
ops.getClickHouseIndexType("bloom_filter"));
+ Assertions.assertEquals(IndexType.DATA_SKIPPING_SET,
ops.getClickHouseIndexType("set"));
+
+ // set(N) variants — ClickHouse may return type with parameter in some
versions
+ Assertions.assertEquals(IndexType.DATA_SKIPPING_SET,
ops.getClickHouseIndexType("set(0)"));
+ Assertions.assertEquals(IndexType.DATA_SKIPPING_SET,
ops.getClickHouseIndexType("set(100)"));
+
+ // Blank/null defaults to MINMAX
+ Assertions.assertEquals(IndexType.DATA_SKIPPING_MINMAX,
ops.getClickHouseIndexType(""));
+ Assertions.assertEquals(IndexType.DATA_SKIPPING_MINMAX,
ops.getClickHouseIndexType(null));
+
+ // Unsupported type
+ Assertions.assertThrows(
+ IllegalArgumentException.class, () ->
ops.getClickHouseIndexType("unknown_type"));
+ }
+
@Test
public void testAlterTableNullabilityValidationFails() {
StubClickHouseTableOperations ops = new StubClickHouseTableOperations();
diff --git a/docs/jdbc-clickhouse-catalog.md b/docs/jdbc-clickhouse-catalog.md
index b6859cdaf1..4075ff2b38 100644
--- a/docs/jdbc-clickhouse-catalog.md
+++ b/docs/jdbc-clickhouse-catalog.md
@@ -172,7 +172,7 @@ See [Manage Relational Metadata Using
Gravitino](./manage-relational-metadata-us
| Mapping | Gravitino table maps to a ClickHouse table
|
| Engines | **MergeTree family** (`MergeTree` default,
`ReplacingMergeTree`, `SummingMergeTree`, `AggregatingMergeTree`,
`CollapsingMergeTree`, `VersionedCollapsingMergeTree`, `GraphiteMergeTree`):
fully supported, data persists across restarts. **Log family** (`TinyLog`,
`StripeLog`, `Log`): supported, data and table definition persist across
restarts. **`Null`**: supported, table persists, data is always discarded by
design. **`Set`**: supported, table definition persists. [...]
| Ordering/Partition | MergeTree-family requires exactly one `ORDER BY`
column; only single-column identity `PARTITION BY` is supported on MergeTree
engines. Other engines reject `ORDER BY`/`PARTITION BY`.
|
-| Indexes | Primary key; data-skipping indexes
`DATA_SKIPPING_MINMAX` and `DATA_SKIPPING_BLOOM_FILTER` (fixed granularities).
|
+| Indexes | Primary key; data-skipping indexes
`DATA_SKIPPING_MINMAX`, `DATA_SKIPPING_BLOOM_FILTER`, and `DATA_SKIPPING_SET`
(fixed granularities).
|
| Distribution | Gravitino enforces `Distributions.NONE`; no custom
distribution strategies.
|
| Column defaults | Supported.
|
| Unsupported | Engine change after creation; removing table
properties; auto-increment columns.
|
@@ -242,6 +242,7 @@ If you need Gravitino to manage an existing cluster
database or table, recreate
- Data-skipping indexes:
- `DATA_SKIPPING_MINMAX` (`GRANULARITY` fixed to 1)
- `DATA_SKIPPING_BLOOM_FILTER` (`GRANULARITY` fixed to 3)
+ - `DATA_SKIPPING_SET` (`GRANULARITY` fixed to 1)
### Partitioning, Sorting, and Distribution