github-actions[bot] commented on code in PR #68335:
URL: https://github.com/apache/doris/pull/68335#discussion_r4061188393
##########
be/src/format_v2/table/lance_reader.cpp:
##########
@@ -839,7 +766,8 @@ Status LanceTableReader::_open_scanner(const
TFileRangeDesc& range) {
return lance_error("set Lance scanner statistics callback");
}
- if (_global_rowid_output_idx.has_value() &&
lance_scanner_with_row_id(scanner, true) != 0) {
+ if (_record_batch_converter.requires_global_rowid() &&
+ lance_scanner_with_row_id(scanner, true) != 0) {
return lance_error("enable Lance row id output");
Review Comment:
This new null-counter guard makes scanner-less row-ID fetches lose cache
statistics. _init_scanner_profile is only called from _open_scanner, but
read_by_row_ids opens the dataset and calls take_rows without a scanner;
_close_dataset therefore reaches this guard with null counters and skips
lance_dataset_get_data_cache_statistics. Before the refactor the counters were
initialized in init, so phase-two I/O exposed these bytes. Please
initialize/collect the cache counters for take_rows as well, or explicitly wire
those statistics into the row-ID fetch profile.
##########
be/src/format_v2/lance/lance_reader_helper.cpp:
##########
@@ -575,78 +473,92 @@ Status compact_lance_array_if_needed(const
std::shared_ptr<arrow::Array>& array,
} // namespace
-// Normalize Lance extensions and materialize sliced arrays for Doris Arrow
SerDes.
-Status normalize_lance_arrow_array(const std::shared_ptr<arrow::Field>& field,
- const std::shared_ptr<arrow::Array>& array,
- arrow::MemoryPool* memory_pool,
- std::shared_ptr<arrow::Array>* normalized) {
+Status LanceArrowArrayNormalizer::create(const std::shared_ptr<arrow::Field>&
field,
+ LanceArrowArrayNormalizer*
normalizer) {
DORIS_CHECK(field != nullptr);
- DORIS_CHECK(array != nullptr);
- DORIS_CHECK(memory_pool != nullptr);
- DORIS_CHECK(normalized != nullptr);
+ DORIS_CHECK(normalizer != nullptr);
LanceExtensionKind extension_kind;
std::shared_ptr<arrow::DataType> storage_type;
RETURN_IF_ERROR(get_lance_extension(field, &extension_kind,
&storage_type));
+ LanceArrowArrayNormalizer result;
+ result._field_name = field->name();
+ result._storage_type = std::move(storage_type);
+ result._unwrap_registered_extension = field->type()->id() ==
arrow::Type::EXTENSION;
+ result._convert_bfloat16 = extension_kind == LanceExtensionKind::BFLOAT16;
+ result._requires_special_handling =
+ result._unwrap_registered_extension || result._convert_bfloat16;
+ result._child_normalizers.reserve(result._storage_type->num_fields());
+ for (const auto& child_field : result._storage_type->fields()) {
+ LanceArrowArrayNormalizer child_normalizer;
+ RETURN_IF_ERROR(create(child_field, &child_normalizer));
+ result._requires_special_handling |=
child_normalizer._requires_special_handling;
+ result._child_normalizers.emplace_back(std::move(child_normalizer));
+ }
+ *normalizer = std::move(result);
+ return Status::OK();
+}
+
+Status LanceArrowArrayNormalizer::normalize_for_doris(
+ const std::shared_ptr<arrow::Array>& array, arrow::MemoryPool*
memory_pool,
+ std::shared_ptr<arrow::Array>* normalized) const {
+ DORIS_CHECK(array != nullptr);
+ DORIS_CHECK(memory_pool != nullptr);
+ DORIS_CHECK(normalized != nullptr);
+
+ // The schema binding already resolved extension metadata and nested
special types. For common
+ // arrays, runtime work is limited to checking whether the visible slice
needs compaction.
+ if (!_requires_special_handling) {
+ return compact_lance_array_if_needed(array, memory_pool, normalized);
+ }
+
auto storage_array = array;
- if (type_contains_registered_extension(field->type())) {
- std::shared_ptr<arrow::Array> unwrapped_array;
- RETURN_IF_ERROR(unwrap_lance_extension_arrays(field->type(), array,
&unwrapped_array));
- storage_array = std::move(unwrapped_array);
+ if (_unwrap_registered_extension && array->type_id() ==
arrow::Type::EXTENSION) {
+ const auto extension_array =
std::dynamic_pointer_cast<arrow::ExtensionArray>(array);
+ if (extension_array == nullptr) {
+ return Status::InvalidArgument("invalid Arrow extension array: {}",
+ array->type()->ToString());
+ }
+ storage_array = extension_array->storage();
}
- if (storage_array->type_id() != storage_type->id()) {
+ // Extension and BFloat16 arrays are first converted to their physical
storage representation;
+ // nested children are then normalized recursively before Doris reads the
result.
+ if (storage_array->type_id() != _storage_type->id()) {
return Status::InvalidArgument(
- "Lance field '{}' storage type {} does not match array type
{}", field->name(),
- storage_type->ToString(), storage_array->type()->ToString());
+ "Lance field '{}' storage type {} does not match array type
{}", _field_name,
+ _storage_type->ToString(), storage_array->type()->ToString());
}
- if (extension_kind == LanceExtensionKind::BFLOAT16) {
+ if (_convert_bfloat16) {
return convert_bfloat16_array(storage_array, memory_pool, normalized);
}
Review Comment:
Because this compaction now runs before child normalizers, a sliced
LIST/STRUCT whose child is a registered ExtensionType reaches
arrow::MakeBuilder(list<extension>). Arrow 24 returns NotImplemented for
ExtensionType builders, so the existing ReadsRegisteredJsonNestedInSlicedList
path fails instead of unwrapping the child. The old routine unwrapped first.
Please unwrap/rebuild extension children before compacting the parent (or
compact with storage-type builders) and retain this regression coverage.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]