在循环中创建 ArrayBuilder

Creating ArrayBuilders in a Loop

有没有办法创建 arrow::ArrayBuilder 对象的动态容器?这是一个例子

int main(int argc, char** argv) {
  std::size_t rowCount = 5;
  arrow::MemoryPool* pool = arrow::default_memory_pool();  
  std::vector<arrow::Int64Builder> builders;
  for (std::size_t i = 0; i < 2; i++) {
    arrow::Int64Builder tmp(pool);
    tmp.Reserve(rowCount);
    builders.push_back(tmp);
  }

  return 0;
}

这会产生 error: variable ‘arrow::Int64Builder tmp’ has initializer but incomplete type

理想情况下,我正在尝试构建一个集合来容纳各种构建器,并根据我收到的按行数据构建 table。我的猜测是这不是构建器的预期​​用途,但我在 Arrow 文档中找不到任何确定的内容

你的包含是什么样子的?该错误消息似乎表明您没有包含正确的文件。 arrow:Int64Builder 的完整定义在 arrow/array/builder_primitive.h 中,但您通常只需包含 arrow/api.h 即可获得所有内容。

以下为我编译:

#include <iostream>

#include <arrow/api.h>

arrow::Status Main() {
    std::size_t rowCount = 5;
    arrow::MemoryPool* pool = arrow::default_memory_pool();
    std::vector<arrow::Int64Builder> builders;
    for (std::size_t i = 0; i < 2; i++) {
      arrow::Int64Builder tmp(pool);
      ARROW_RETURN_NOT_OK(tmp.Reserve(rowCount));
      builders.push_back(std::move(tmp));
    }
  return arrow::Status::OK();
}

int main() {
  auto status = Main();
  if (!status.ok()) {
    std::cerr << "Err: " << status << std::endl;
    return 1;
  }
  return 0;
}

您的示例的一个小改动是构建器没有复制构造函数/无法复制。所以我不得不 std::move 把它放到向量中。

此外,如果您想要一个包含许多不同类型构建器的集合,那么您可能需要 std::vector<std::unique_ptr<arrow::ArrayBuilder>> 并且您需要在堆上构建构建器。

您可能 运行 遇到的一个挑战是构建器对 Append 方法都有不同的签名(例如 Int64BuilderAppend(long)StringBuilderAppend(arrow::util::string_view))。结果 arrow::ArrayBuilder 实际上没有任何 Append 方法(如果您碰巧已经将数据作为 Arrow C++ 标量,则有一些方法采用标量)。但是,您可以通过在需要追加时转换为适当的类型来克服这个问题。

更新:

如果您真的想避免强制转换并且您提前知道架构,您可以按照...

std::vector<std::function<arrow::Status(const Row&)>> append_funcs;
std::vector<std::shared_ptr<arrow::ArrayBuilder>> builders;
for (std::size_t i = 0; i < schema.fields().size(); i++) {
  const auto& field = schema.fields()[i];
  if (isInt32(field)) {
    auto int_builder = std::make_shared<Int32Builder>();
    append_funcs.push_back([int_builder] (const Row& row) ({
      int val = row.GetCell<int>(i);
      return int_builder->Append(val);
    });
    builders.push_back(std::move(int_builder));
  } else if {
    // Other types go here
  }
}

// Later
for (const auto& row : rows) {
  for (const auto& append_func : append_funcs) {
    ARROW_RETURN_NOT_OK(append_func(row));
  }
}

注意:Row是我编的,因为我不知道你的数据原来是什么格式。我还编了 isInt32 因为我不记得如何检查它了。

这里使用 shared_ptr 而不是 unique_ptr 因为你需要两个副本,一个在 lambda 的捕获中,另一个在 builders 数组中。