-
Notifications
You must be signed in to change notification settings - Fork 722
[#9113] feat(lance-rest): Support drop and rename column for Lance table #9127
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
base: main
Are you sure you want to change the base?
Changes from 10 commits
b5fbc6e
35a28d2
0234506
ea2b252
a9aff38
04942ba
b59e25b
d1a5246
cbe7892
349b820
ca7a40a
f8fdd4c
8fbed20
12099aa
708416e
c96d743
03f1fb8
0f6c8da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,13 @@ | |
| import com.google.common.collect.Maps; | ||
| import com.lancedb.lance.namespace.LanceNamespaceException; | ||
| import com.lancedb.lance.namespace.ObjectIdentifier; | ||
| import com.lancedb.lance.namespace.model.AlterTableAddColumnsRequest; | ||
| import com.lancedb.lance.namespace.model.AlterTableAddColumnsResponse; | ||
| import com.lancedb.lance.namespace.model.AlterTableAlterColumnsRequest; | ||
| import com.lancedb.lance.namespace.model.AlterTableAlterColumnsResponse; | ||
| import com.lancedb.lance.namespace.model.AlterTableDropColumnsRequest; | ||
| import com.lancedb.lance.namespace.model.AlterTableDropColumnsResponse; | ||
| import com.lancedb.lance.namespace.model.ColumnAlteration; | ||
| import com.lancedb.lance.namespace.model.CreateEmptyTableResponse; | ||
| import com.lancedb.lance.namespace.model.CreateTableRequest; | ||
| import com.lancedb.lance.namespace.model.CreateTableRequest.ModeEnum; | ||
|
|
@@ -52,17 +59,24 @@ | |
| import java.util.regex.Pattern; | ||
| import java.util.stream.Collectors; | ||
| import org.apache.arrow.vector.types.pojo.Field; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.apache.gravitino.Catalog; | ||
| import org.apache.gravitino.NameIdentifier; | ||
| import org.apache.gravitino.exceptions.NoSuchTableException; | ||
| import org.apache.gravitino.lance.common.ops.LanceTableOperations; | ||
| import org.apache.gravitino.lance.common.utils.ArrowUtils; | ||
| import org.apache.gravitino.lance.common.utils.LanceConstants; | ||
| import org.apache.gravitino.lance.common.utils.LancePropertiesUtils; | ||
| import org.apache.gravitino.rel.Column; | ||
| import org.apache.gravitino.rel.Table; | ||
| import org.apache.gravitino.rel.TableChange; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| public class GravitinoLanceTableOperations implements LanceTableOperations { | ||
|
|
||
| public static final Logger LOG = LoggerFactory.getLogger(GravitinoLanceTableOperations.class); | ||
|
|
||
| private final GravitinoLanceNamespaceWrapper namespaceWrapper; | ||
|
|
||
| public GravitinoLanceTableOperations(GravitinoLanceNamespaceWrapper namespaceWrapper) { | ||
|
|
@@ -294,6 +308,72 @@ public DropTableResponse dropTable(String tableId, String delimiter) { | |
| return response; | ||
| } | ||
|
|
||
| @Override | ||
| public AlterTableDropColumnsResponse alterTableDropColumns( | ||
| String tableId, String delimiter, AlterTableDropColumnsRequest request) { | ||
| ObjectIdentifier nsId = ObjectIdentifier.of(tableId, Pattern.quote(delimiter)); | ||
| Preconditions.checkArgument( | ||
| nsId.levels() == 3, "Expected at 3-level namespace but got: %s", nsId.levels()); | ||
|
|
||
| String catalogName = nsId.levelAtListPos(0); | ||
| Catalog catalog = namespaceWrapper.loadAndValidateLakehouseCatalog(catalogName); | ||
|
|
||
| NameIdentifier tableIdentifier = | ||
| NameIdentifier.of(nsId.levelAtListPos(1), nsId.levelAtListPos(2)); | ||
|
|
||
| TableChange[] changes = | ||
| request.getColumns().stream() | ||
| .map(colName -> TableChange.deleteColumn(new String[] {colName}, false)) | ||
| .toArray(TableChange[]::new); | ||
|
|
||
| Table table = catalog.asTableCatalog().alterTable(tableIdentifier, changes); | ||
| Long version = | ||
| Optional.ofNullable(table.properties().get(LanceConstants.LANCE_TABLE_VERSION)) | ||
| .map(Long::valueOf) | ||
| .orElse(null); | ||
| AlterTableDropColumnsResponse alterTableDropColumnsResponse = | ||
| new AlterTableDropColumnsResponse(); | ||
| alterTableDropColumnsResponse.setVersion(version); | ||
| return alterTableDropColumnsResponse; | ||
| } | ||
|
|
||
| @Override | ||
| public AlterTableAlterColumnsResponse alterTableAlterColumns( | ||
| String tableId, String delimiter, AlterTableAlterColumnsRequest request) { | ||
| ObjectIdentifier nsId = ObjectIdentifier.of(tableId, Pattern.quote(delimiter)); | ||
| Preconditions.checkArgument( | ||
| nsId.levels() == 3, "Expected at 3-level namespace but got: %s", nsId.levels()); | ||
|
|
||
| String catalogName = nsId.levelAtListPos(0); | ||
| Catalog catalog = namespaceWrapper.loadAndValidateLakehouseCatalog(catalogName); | ||
|
|
||
| NameIdentifier tableIdentifier = | ||
| NameIdentifier.of(nsId.levelAtListPos(1), nsId.levelAtListPos(2)); | ||
|
|
||
| List<TableChange> changes = buildAlterColumnChanges(request); | ||
| if (changes.isEmpty()) { | ||
| throw new IllegalArgumentException("No valid alterations found in the request."); | ||
| } | ||
| Table table = | ||
| catalog.asTableCatalog().alterTable(tableIdentifier, changes.toArray(new TableChange[0])); | ||
| Long version = | ||
| Optional.ofNullable(table.properties().get(LanceConstants.LANCE_TABLE_VERSION)) | ||
| .map(Long::valueOf) | ||
| .orElse(null); | ||
| AlterTableAlterColumnsResponse response = new AlterTableAlterColumnsResponse(); | ||
| response.setVersion(version); | ||
| return response; | ||
| } | ||
|
|
||
| @Override | ||
| public AlterTableAddColumnsResponse alterTableAddColumns( | ||
| String tableId, String delimiter, AlterTableAddColumnsRequest request) { | ||
| // We need to parse NewColumnTransform to Column, however, NewColumnTransform only contains | ||
| // the name and a string expression. | ||
| // More please see: https://docs.lancedb.com/api-reference/data/add-columns | ||
| throw new UnsupportedOperationException("Adding columns is not supported yet."); | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The implementation of these 3 methods are basically the same; can they be merged together?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean we can define the following interface to replace them all? @Override
public AlterTableAlterColumnsResponse alterTableOperations(
String tableId, String delimiter, Object request) {
if (request instanceof AlterTableAddColumnsRequest addColumnsRequest) {
// add column
} else if (request instanceof AlterTableAlterColumnsRequest alterColumnsRequest) {
return alterTableAlterColumns(tableId, delimiter, alterColumnsRequest);
} else if (request instanceof AlterTableDropColumnsRequest dropColumnsRequest) {
// drop column
return alterTableDropColumns(tableId, delimiter, dropColumnsRequest);
}
}
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, something like this. Since most of the logic are similar, if we continue to add more alter-related operations, there will be lots of duplicated codes.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't change a lot. Most of the code are duplicated, like check id and load catalog, also like getting latest version. Please think seriously about how to do it. |
||
| private List<Column> extractColumns(org.apache.arrow.vector.types.pojo.Schema arrowSchema) { | ||
| List<Column> columns = new ArrayList<>(); | ||
|
|
||
|
|
@@ -319,4 +399,28 @@ private JsonArrowSchema toJsonArrowSchema(Column[] columns) { | |
| return JsonArrowSchemaConverter.convertToJsonArrowSchema( | ||
| new org.apache.arrow.vector.types.pojo.Schema(fields)); | ||
| } | ||
|
|
||
| private List<TableChange> buildAlterColumnChanges(AlterTableAlterColumnsRequest request) { | ||
| List<ColumnAlteration> columns = request.getAlterations(); | ||
|
|
||
| List<TableChange> changes = new ArrayList<>(); | ||
| for (ColumnAlteration column : columns) { | ||
| // Column name will not be null according to LanceDB spec. | ||
| String columnName = column.getColumn(); | ||
| String newName = column.getRename(); | ||
| if (StringUtils.isNotBlank(newName)) { | ||
| changes.add(TableChange.renameColumn(new String[] {columnName}, newName)); | ||
| } | ||
|
|
||
| // The format of ColumnAlteration#castTo is unclear, so we will skip it now | ||
| // for more, please see: | ||
| // https://github.com/lance-format/lance-namespace/blob/9d9cde12520caea2fd80ea5f41a20a4db9b92524/java/lance-namespace-apache-client/api/openapi.yaml#L4508-L4511 | ||
| if (StringUtils.isNotBlank(column.getCastTo())) { | ||
| LOG.error( | ||
| "Altering column '{}' data type is not supported yet due to unclear spec.", columnName); | ||
| throw new UnsupportedOperationException("Altering column data type is not supported yet."); | ||
| } | ||
| } | ||
| return changes; | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.