Arrow JDBC 轉接器#
Arrow JDBC 轉接器協助處理 JDBC 和 Arrow 資料。目前,它支援將 JDBC ResultSets 讀取到 Arrow VectorSchemaRoots。
ResultSet 到 VectorSchemaRoot 的轉換#
這可以透過 JdbcToArrow 類別存取。產生的 ArrowVectorIterator 將以批次方式將 ResultSet 轉換為 Arrow 資料。
try (ArrowVectorIterator it = JdbcToArrow.sqlToArrowVectorIterator(resultSet, allocator)) {
while (it.hasNext()) {
VectorSchemaRoot root = it.next();
// Consume the root…
}
}
批次大小和類型映射都可以自訂
JdbcToArrowConfig config = new JdbcToArrowConfigBuilder(allocator, /*calendar=*/null)
.setReuseVectorSchemaRoot(reuseVectorSchemaRoot)
.setJdbcToArrowTypeConverter((jdbcFieldInfo -> {
switch (jdbcFieldInfo.getJdbcType()) {
case Types.BIGINT:
// Assume actual value range is SMALLINT
return new ArrowType.Int(16, true);
default:
return null;
}
}))
.build();
try (ArrowVectorIterator iter = JdbcToArrow.sqlToArrowVectorIterator(rs, config)) {
while (iter.hasNext()) {
VectorSchemaRoot root = iter.next();
// Consume the root…
}
}
可以明確指定 JDBC 類型,這很有用,因為 JDBC 驅動程式可能會提供錯誤的類型資訊。例如,已觀察到 Postgres 驅動程式使用小數位數和精度為 0 的 Decimal 類型;在這些情況下,可以在讀取之前明確指定類型來處理。此外,某些 JDBC 驅動程式可能會傳回具有不一致小數位數的 BigDecimal 值。可以設定 RoundingMode 來處理這些情況
Map<Integer, JdbcFieldInfo> mapping = new HashMap<>();
mapping.put(1, new JdbcFieldInfo(Types.DECIMAL, 20, 7));
JdbcToArrowConfig config = new JdbcToArrowConfigBuilder(allocator, /*calendar=*/null)
.setBigDecimalRoundingMode(RoundingMode.UNNECESSARY)
.setExplicitTypesByColumnIndex(mapping)
.build();
try (ArrowVectorIterator iter = JdbcToArrow.sqlToArrowVectorIterator(rs, config)) {
while (iter.hasNext()) {
VectorSchemaRoot root = iter.next();
// Consume the root…
}
}
從 JDBC 類型到 Arrow 類型的映射可以透過 JdbcToArrowConfig
覆寫,但無法自訂從 JDBC 值到 Arrow 值的轉換本身,也無法為不支援的類型定義轉換。
類型映射#
JDBC 到 Arrow 類型的映射可以在執行時從 JdbcToArrowUtils.getArrowTypeFromJdbcType 取得。
JDBC 類型 |
Arrow 類型 |
注意事項 |
---|---|---|
ARRAY |
List |
(1) |
BIGINT |
Int64 |
|
BINARY |
Binary |
|
BIT |
Bool |
|
BLOB |
Binary |
|
BOOLEAN |
Bool |
|
CHAR |
Utf8 |
|
CLOB |
Utf8 |
|
DATE |
Date32 |
|
DECIMAL |
Decimal128 |
(2) |
DOUBLE |
Double |
|
FLOAT |
Float32 |
|
INTEGER |
Int32 |
|
LONGVARBINARY |
Binary |
|
LONGNVARCHAR |
Utf8 |
|
LONGVARCHAR |
Utf8 |
|
NCHAR |
Utf8 |
|
NULL |
Null |
|
NUMERIC |
Decimal128 |
|
NVARCHAR |
Utf8 |
|
REAL |
Float32 |
|
SMALLINT |
Int16 |
|
STRUCT |
Struct |
(3) |
TIME |
Time32[ms] |
|
TIMESTAMP |
Timestamp[ms] |
(4) |
TINYINT |
Int8 |
|
VARBINARY |
Binary |
|
VARCHAR |
Utf8 |
(1) 列表值類型必須明確配置,且無法推斷。使用 setArraySubTypeByColumnIndexMap 或 setArraySubTypeByColumnNameMap。
(2) 預設情況下,小數值的 scale 必須與類型中的 scale 完全匹配;精度允許為大於或等於類型精度的任何值。如果存在不匹配,預設情況下將拋出例外。這可以透過使用 setBigDecimalRoundingMode 設定不同的 RoundingMode 來配置。
(3) 未完全支援:雖然定義了類型轉換,但未定義值轉換。請參閱 ARROW-17006。
(4) 如果提供 Calendar,則時間戳記將具有 Calendar 的時區,否則它將是沒有時區的時間戳記。
VectorSchemaRoot 到 PreparedStatement 參數轉換#
轉接器可以將 VectorSchemaRoot 中的 Arrow 資料列繫結到 JDBC PreparedStatement 的參數。這可以透過 JdbcParameterBinder 類別存取。每次呼叫 next() 都會繫結來自下一列資料的參數,然後應用程式可以根據需要執行語句、呼叫 addBatch() 等。Null 值將導致使用適當的 JDBC 類型代碼(如下所列)呼叫 setNull。
final JdbcParameterBinder binder =
JdbcParameterBinder.builder(statement, root).bindAll().build();
while (binder.next()) {
statement.executeUpdate();
}
// Use a VectorLoader to update the root
binder.reset();
while (binder.next()) {
statement.executeUpdate();
}
向量到參數的映射、轉換器使用的 JDBC 類型代碼以及類型轉換本身都可以自訂
final JdbcParameterBinder binder =
JdbcParameterBinder.builder(statement, root)
.bind(/*parameterIndex*/2, /*columnIndex*/0)
.bind(/*parameterIndex*/1, customColumnBinderInstance)
.build();
類型映射#
Arrow 到 JDBC 類型的映射可以在執行時透過 ColumnBinder 上的方法取得。
Arrow 類型 |
JDBC 類型 |
注意事項 |
---|---|---|
Binary |
VARBINARY (setBytes) |
|
Bool |
BOOLEAN (setBoolean) |
|
Date32 |
DATE (setDate) |
|
Date64 |
DATE (setDate) |
|
Decimal128 |
DECIMAL (setBigDecimal) |
|
Decimal256 |
DECIMAL (setBigDecimal) |
|
FixedSizeBinary |
BINARY (setBytes) |
|
Float32 |
REAL (setFloat) |
|
Int8 |
TINYINT (setByte) |
|
Int16 |
SMALLINT (setShort) |
|
Int32 |
INTEGER (setInt) |
|
Int64 |
BIGINT (setLong) |
|
LargeBinary |
LONGVARBINARY (setBytes) |
|
LargeUtf8 |
LONGVARCHAR (setString) |
(1) |
Time[s] |
TIME (setTime) |
|
Time[ms] |
TIME (setTime) |
|
Time[us] |
TIME (setTime) |
|
Time[ns] |
TIME (setTime) |
|
Timestamp[s] |
TIMESTAMP (setTimestamp) |
(2) |
Timestamp[ms] |
TIMESTAMP (setTimestamp) |
(2) |
Timestamp[us] |
TIMESTAMP (setTimestamp) |
(2) |
Timestamp[ns] |
TIMESTAMP (setTimestamp) |
(2) |
Utf8 |
VARCHAR (setString) |
(1) 長度超過 Integer.MAX_VALUE 位元組(Java
byte[]
的最大長度)的字串將導致執行階段例外。(2) 如果時間戳記具有時區,則 JDBC 類型預設為 TIMESTAMP_WITH_TIMEZONE。如果時間戳記沒有時區,從 Arrow 值到 JDBC 值在技術上沒有正確的轉換,因為 JDBC Timestamp 是 UTC 時間,而我們沒有時區資訊。在這種情況下,預設繫結器將呼叫 setTimestamp(int, Timestamp),這將導致驅動程式使用「預設時區」(Java VM 的時區)。