This is an automated email from the ASF dual-hosted git repository.
jerryshao pushed a commit to branch branch-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-1.3 by this push:
new 3631f0d586 [Cherry-pick to branch-1.3] [#14066] fix(starrocks): Map
index types when loading StarRocks tables (#14067) (#14199)
3631f0d586 is described below
commit 3631f0d58673d9dc9d2fabca657d90bb4bebed6f
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon Oct 26 14:47:14 2026 +0800
[Cherry-pick to branch-1.3] [#14066] fix(starrocks): Map index types when
loading StarRocks tables (#14067) (#14199)
**Cherry-pick Information:**
- Original commit: d4d95ebfe5c92e18e2ae2e8ae88d95aeb0c0251d
- Target branch: `branch-1.3`
- Status: ⚠️ **Has conflicts - manual resolution required**
**Do not merge** until conflict markers are resolved and the
`cherry-pick-conflict` label is removed.
Please review and resolve the conflicts before merging.
Co-authored-by: Yuhui <[email protected]>
Co-authored-by: Jerry Shao <[email protected]>
---
.../org/apache/gravitino/rel/indexes/Index.java | 9 +++--
catalogs/catalog-jdbc-starrocks/build.gradle.kts | 1 +
.../operations/StarRocksTableOperations.java | 45 ++++++++++++++++++++-
.../operation/TestStarRocksTableOperations.java | 25 ++++++++++++
.../TestStarRocksTableOperationsSqlGeneration.java | 46 ++++++++++++++++++++++
.../gravitino/api/rel/indexes/index.py | 9 +++++
.../tests/unittests/dto/rel/test_index_serdes.py | 18 +++++++++
docs/jdbc-starrocks-catalog.md | 10 ++++-
8 files changed, 157 insertions(+), 6 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 9f725c19cc..173f87c590 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
@@ -92,7 +92,8 @@ public interface Index {
/**
* Bitmap index is a type of database index that uses bit arrays (bitmaps)
to represent the
* presence or absence of values in a column, enabling efficient querying
and data retrieval.
- * Currently, this type is only applicable to Lance.
+ * Currently, this type is applicable to Lance, is accepted when creating
Doris tables, and is
+ * reported when loading StarRocks tables.
*/
BITMAP,
/**
@@ -103,12 +104,14 @@ public interface Index {
/**
* INVERTED index is a data structure used to optimize full-text searches
by mapping terms to
* their locations within a dataset, allowing for quick retrieval of
documents containing
- * specific words or phrases. Currently, this type is only applicable to
Lance.
+ * specific words or phrases. Currently, this type is applicable to Lance
and Doris, and is
+ * reported when loading StarRocks tables.
*/
INVERTED,
/**
* VECTOR index is used to optimize similarity searches in
high-dimensional vector spaces.
- * Currently, this type is only applicable to Lance.
+ * Currently, this type is applicable to Lance and Doris, and is reported
when loading StarRocks
+ * tables.
*/
VECTOR,
/** IVF_FLAT (Inverted File with Flat quantization) is an indexing method
used for efficient */
diff --git a/catalogs/catalog-jdbc-starrocks/build.gradle.kts
b/catalogs/catalog-jdbc-starrocks/build.gradle.kts
index 03b7d260bb..60a45284da 100644
--- a/catalogs/catalog-jdbc-starrocks/build.gradle.kts
+++ b/catalogs/catalog-jdbc-starrocks/build.gradle.kts
@@ -50,6 +50,7 @@ dependencies {
testImplementation(libs.awaitility)
testImplementation(libs.junit.jupiter.api)
testImplementation(libs.junit.jupiter.params)
+ testImplementation(libs.mockito.core)
testImplementation(libs.mysql.driver)
testImplementation(libs.postgresql.driver)
testImplementation(libs.testcontainers)
diff --git
a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/operations/StarRocksTableOperations.java
b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/operations/StarRocksTableOperations.java
index 71551d036f..d3a8c2f290 100644
---
a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/operations/StarRocksTableOperations.java
+++
b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/operations/StarRocksTableOperations.java
@@ -32,10 +32,12 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import javax.annotation.Nullable;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
@@ -260,12 +262,24 @@ public class StarRocksTableOperations extends
JdbcTableOperations {
try (PreparedStatement preparedStatement =
connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery()) {
+ // SHOW INDEX lists only secondary indexes, one row per single-column
index; table keys are
+ // not included.
List<Index> indexes = new ArrayList<>();
while (resultSet.next()) {
String indexName = resultSet.getString("Key_name");
String columnName = resultSet.getString("Column_name");
- indexes.add(
- Indexes.of(Index.IndexType.PRIMARY_KEY, indexName, new String[][]
{{columnName}}));
+ String starRocksIndexType = resultSet.getString("Index_type");
+ Index.IndexType indexType = mapStarRocksIndexType(starRocksIndexType);
+ if (indexType == null) {
+ LOG.warn(
+ "Skip StarRocks index '{}' on table {}.{} with unsupported type
'{}'",
+ indexName,
+ databaseName,
+ tableName,
+ starRocksIndexType);
+ continue;
+ }
+ indexes.add(Indexes.of(indexType, indexName, new String[][]
{{columnName}}));
}
return indexes;
} catch (SQLException e) {
@@ -630,4 +644,31 @@ public class StarRocksTableOperations extends
JdbcTableOperations {
.build();
return appendColumnDefinition(newColumn, sqlBuilder).toString();
}
+
+ /**
+ * Maps the {@code Index_type} value of StarRocks {@code SHOW INDEX} to a
Gravitino index type.
+ * The value may carry index properties, e.g. {@code GIN("parser" =
"english")}; only the type
+ * name is used and the properties are not kept, since StarRocks indexes
cannot be created or
+ * altered through Gravitino.
+ *
+ * @param indexType the {@code Index_type} value returned by StarRocks
+ * @return the Gravitino index type, or null if the type has no Gravitino
equivalent
+ */
+ @Nullable
+ private static Index.IndexType mapStarRocksIndexType(@Nullable String
indexType) {
+ if (indexType == null) {
+ return null;
+ }
+ String typeName = StringUtils.substringBefore(indexType, "(").trim();
+ switch (typeName.toUpperCase(Locale.ROOT)) {
+ case "BITMAP":
+ return Index.IndexType.BITMAP;
+ case "GIN":
+ return Index.IndexType.INVERTED;
+ case "VECTOR":
+ return Index.IndexType.VECTOR;
+ default:
+ return null;
+ }
+ }
}
diff --git
a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperations.java
b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperations.java
index fb4a4c0ae4..06a5b74200 100644
---
a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperations.java
+++
b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperations.java
@@ -846,4 +846,29 @@ public class TestStarRocksTableOperations extends
TestStarRocks {
TABLE_OPERATIONS.drop(databaseName, tableName);
}
}
+
+ @ParameterizedTest
+ @ValueSource(strings = {"PRIMARY", "UNIQUE", "DUPLICATE"})
+ void testLoadTableReportsOnlySecondaryIndexes(String keyType) throws
SQLException {
+ String tableName = GravitinoITUtils.genRandomName("starrocks_index");
+ try (Connection connection = DATA_SOURCE.getConnection();
+ Statement statement = connection.createStatement()) {
+ statement.executeUpdate(
+ String.format(
+ "CREATE TABLE `%s`.`%s` (`id` INT NOT NULL, `region` VARCHAR(32)
NOT NULL, "
+ + "INDEX `idx_region` (`region`) USING BITMAP) "
+ + "%s KEY(`id`, `region`) DISTRIBUTED BY HASH(`id`) BUCKETS
1 "
+ + "PROPERTIES (\"replication_num\" = \"1\")",
+ databaseName, tableName, keyType));
+ }
+ try {
+ JdbcTable table = TABLE_OPERATIONS.load(databaseName, tableName);
+ Assertions.assertEquals(1, table.index().length);
+ Assertions.assertEquals(Index.IndexType.BITMAP, table.index()[0].type());
+ Assertions.assertEquals("idx_region", table.index()[0].name());
+ Assertions.assertArrayEquals(new String[][] {{"region"}},
table.index()[0].fieldNames());
+ } finally {
+ TABLE_OPERATIONS.drop(databaseName, tableName);
+ }
+ }
}
diff --git
a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java
b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java
index 114f8e50f8..f69fe01191 100644
---
a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java
+++
b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java
@@ -19,6 +19,9 @@
package org.apache.gravitino.catalog.starrocks.operation;
import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -46,6 +49,7 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EmptySource;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.NullSource;
+import org.mockito.Mockito;
public class TestStarRocksTableOperationsSqlGeneration {
@@ -100,6 +104,11 @@ public class TestStarRocksTableOperationsSqlGeneration {
return generateAlterTableSql("database", tableName, changes);
}
+ List<Index> indexes(Connection connection, String databaseName, String
tableName)
+ throws SQLException {
+ return getIndexes(connection, databaseName, tableName);
+ }
+
@Override
protected JdbcTable getOrCreateTable(
String databaseName, String tableName, JdbcTable lazyLoadCreateTable) {
@@ -411,6 +420,43 @@ public class TestStarRocksTableOperationsSqlGeneration {
"StarRocks does not support adding an auto-increment column: col2",
exception.getMessage());
}
+ @Test
+ void testGetIndexesMapsTypesAndSkipsUnsupported() throws SQLException {
+ TestableStarRocksTableOperations ops = new
TestableStarRocksTableOperations();
+ Connection connection = Mockito.mock(Connection.class);
+ PreparedStatement statement = Mockito.mock(PreparedStatement.class);
+ ResultSet resultSet = Mockito.mock(ResultSet.class);
+ Mockito.when(connection.prepareStatement("SHOW INDEX FROM `table` FROM
`database`"))
+ .thenReturn(statement);
+ Mockito.when(statement.executeQuery()).thenReturn(resultSet);
+ Mockito.when(resultSet.next()).thenReturn(true, true, true, true, true,
true, false);
+ Mockito.when(resultSet.getString("Key_name"))
+ .thenReturn("idx_region", "idx_ngram", "idx_text", "idx_vector",
"idx_unknown", "idx_null");
+ Mockito.when(resultSet.getString("Column_name"))
+ .thenReturn("region", "name", "text", "embedding", "c5", "c6");
+ Mockito.when(resultSet.getString("Index_type"))
+ .thenReturn(
+ "BITMAP",
+ "NGRAMBF(\"gram_num\" = \"4\")",
+ "GIN(\"parser\" = \"english\")",
+ "VECTOR(\"index_type\" = \"hnsw\", \"dim\" = \"3\")",
+ "UNKNOWN",
+ null);
+
+ List<Index> indexes = ops.indexes(connection, "database", "table");
+
+ Assertions.assertEquals(3, indexes.size());
+ Assertions.assertEquals(Index.IndexType.BITMAP, indexes.get(0).type());
+ Assertions.assertEquals("idx_region", indexes.get(0).name());
+ Assertions.assertArrayEquals(new String[][] {{"region"}},
indexes.get(0).fieldNames());
+ Assertions.assertEquals(Index.IndexType.INVERTED, indexes.get(1).type());
+ Assertions.assertEquals("idx_text", indexes.get(1).name());
+ Assertions.assertArrayEquals(new String[][] {{"text"}},
indexes.get(1).fieldNames());
+ Assertions.assertEquals(Index.IndexType.VECTOR, indexes.get(2).type());
+ Assertions.assertEquals("idx_vector", indexes.get(2).name());
+ Assertions.assertArrayEquals(new String[][] {{"embedding"}},
indexes.get(2).fieldNames());
+ }
+
@Test
void testRenameColumnQuotesIdentifiers() {
TestableStarRocksTableOperations ops = new
TestableStarRocksTableOperations("id", "order-id");
diff --git a/clients/client-python/gravitino/api/rel/indexes/index.py
b/clients/client-python/gravitino/api/rel/indexes/index.py
index 777e3b4813..e011fc5464 100644
--- a/clients/client-python/gravitino/api/rel/indexes/index.py
+++ b/clients/client-python/gravitino/api/rel/indexes/index.py
@@ -50,6 +50,15 @@ class Index(ABC):
columns that are not designated as the primary key. The uniqueness
constraint imposed by
UNIQUE KEY helps in avoiding redundancy and ensuring data accuracy in
the database."""
+ BITMAP = "BITMAP"
+ """Bitmap index, which uses bit arrays to represent the presence of
values in a column."""
+
+ INVERTED = "INVERTED"
+ """Inverted index, which maps terms to their locations to speed up
full-text searches."""
+
+ VECTOR = "VECTOR"
+ """Vector index, which speeds up similarity searches in
high-dimensional vector spaces."""
+
@abstractmethod
def type(self) -> IndexType:
"""Returns the type of the index. eg: `PRIMARY_KEY` and `UNIQUE_KEY`.
diff --git a/clients/client-python/tests/unittests/dto/rel/test_index_serdes.py
b/clients/client-python/tests/unittests/dto/rel/test_index_serdes.py
index 790f102a24..f09e83d141 100644
--- a/clients/client-python/tests/unittests/dto/rel/test_index_serdes.py
+++ b/clients/client-python/tests/unittests/dto/rel/test_index_serdes.py
@@ -116,3 +116,21 @@ class TestIndexSerdes(unittest.TestCase):
json_dict = json.loads(json_string)
serialized_dict = json.loads(mock_data_class.to_json())
self.assertDictEqual(json_dict, serialized_dict)
+
+ def test_index_serdes_bitmap_inverted_vector(self):
+ for index_type in (
+ Index.IndexType.BITMAP,
+ Index.IndexType.INVERTED,
+ Index.IndexType.VECTOR,
+ ):
+ index = IndexSerdes.deserialize(
+ {
+ "indexType": index_type.value,
+ "name": "idx",
+ "fieldNames": [["col"]],
+ }
+ )
+ self.assertEqual(index_type, index.type())
+ self.assertEqual(
+ index_type.value, IndexSerdes.serialize(index)["indexType"]
+ )
diff --git a/docs/jdbc-starrocks-catalog.md b/docs/jdbc-starrocks-catalog.md
index ad2d9850ce..6b41d8ac30 100644
--- a/docs/jdbc-starrocks-catalog.md
+++ b/docs/jdbc-starrocks-catalog.md
@@ -149,7 +149,15 @@ Unsupported for now.
### Table Indexes
-Unsupported. Creating a table with non-empty index definitions is rejected
before the table is created.
+Creating a table with non-empty index definitions is rejected before the table
is created.
+
+When loading a table, Gravitino reports StarRocks secondary indexes with the
following type mapping. Indexes of other types (e.g. `NGRAMBF`) are not
reported, and table keys are not reported as indexes.
+
+| StarRocks Index Type | Gravitino Index Type |
+|----------------------|----------------------|
+| `BITMAP` | `BITMAP` |
+| `GIN` | `INVERTED` |
+| `VECTOR` | `VECTOR` |
### Table Partitioning