使用 C++ 實作

此食譜手冊的此部分涵蓋基本概念,無需考慮如何使用 Arrow C++ 實作。

使用狀態和結果

C++ 函式庫通常必須在擲回例外和傳回錯誤碼之間做選擇。Arrow 選擇傳回狀態和結果物件作為折衷方案。這讓函式可明確指出何時可能會失敗,而且比使用整數 Arrow 碼還容易使用。

務必隨時檢查傳回狀態物件的值以確保作業成功。但是,這可能會很快變得繁瑣

手動檢查每個函式的狀態
std::function<arrow::Status()> test_fn = [] {
  arrow::NullBuilder builder;
  arrow::Status st = builder.Reserve(2);
  // Tedious return value check
  if (!st.ok()) {
    return st;
  }
  st = builder.AppendNulls(-1);
  // Tedious return value check
  if (!st.ok()) {
    return st;
  }
  rout << "Appended -1 null values?" << std::endl;
  return arrow::Status::OK();
};
arrow::Status st = test_fn();
rout << st << std::endl;
程式碼輸出
Invalid: length must be positive

巨集 ARROW_RETURN_NOT_OK 會為您處理部分樣板文字。它會執行所包含的運算式並檢查所產生的 StatusResult 物件。如果失敗,則會傳回失敗。

使用 ARROW_RETURN_NOT_OK 檢查狀態
std::function<arrow::Status()> test_fn = [] {
  arrow::NullBuilder builder;
  ARROW_RETURN_NOT_OK(builder.Reserve(2));
  ARROW_RETURN_NOT_OK(builder.AppendNulls(-1));
  rout << "Appended -1 null values?" << std::endl;
  return arrow::Status::OK();
};
arrow::Status st = test_fn();
rout << st << std::endl;
程式碼輸出
Invalid: length must be positive

使用訪問者模式

Arrow 類別 arrow::DataTypearrow::Scalararrow::Array 針對每個 Arrow 類型都有專門的子類別。若要為每個子類別專門化邏輯,您可以使用訪問者模式。Arrow 提供內嵌範本函式,讓您能有效呼叫訪問者

產生隨機資料

針對提供之Schema產生隨機資料 查看範例。

推廣運算至不同 Arrow 類型

撰寫可以處理多種 array 類型之函式時,陣列參訪器可能會有幫助。不過,分別為每個類型實作參訪器可能會過於冗長。幸好,Arrow 提供了類型特質,讓您能撰寫樣板函式來處理部分子類型。下例示範了一個表格總和函式,透過利用 arrow::enable_if_number,它可以處理任何整數或浮點陣列,而且只要實作一個單一的參訪器。

使用參訪者模式能計算出表格中任何數值類型的總和
 1class TableSummation {
 2  double partial = 0.0;
 3 public:
 4
 5  arrow::Result<double> Compute(std::shared_ptr<arrow::RecordBatch> batch) {
 6    for (std::shared_ptr<arrow::Array> array : batch->columns()) {
 7      ARROW_RETURN_NOT_OK(arrow::VisitArrayInline(*array, this));
 8    }
 9    return partial;
10  }
11
12  // Default implementation
13  arrow::Status Visit(const arrow::Array& array) {
14    return arrow::Status::NotImplemented("Can not compute sum for array of type ",
15                                         array.type()->ToString());
16  }
17
18  template <typename ArrayType, typename T = typename ArrayType::TypeClass>
19  arrow::enable_if_number<T, arrow::Status> Visit(const ArrayType& array) {
20    for (std::optional<typename T::c_type> value : array) {
21      if (value.has_value()) {
22        partial += static_cast<double>(value.value());
23      }
24    }
25    return arrow::Status::OK();
26  }
27};  // TableSummation
std::shared_ptr<arrow::Schema> schema = arrow::schema({
    arrow::field("a", arrow::int32()),
    arrow::field("b", arrow::float64()),
});
int32_t num_rows = 3;
std::vector<std::shared_ptr<arrow::Array>> columns;

arrow::Int32Builder a_builder = arrow::Int32Builder();
std::vector<int32_t> a_vals = {1, 2, 3};
ARROW_RETURN_NOT_OK(a_builder.AppendValues(a_vals));
ARROW_ASSIGN_OR_RAISE(auto a_arr, a_builder.Finish());
columns.push_back(a_arr);

arrow::DoubleBuilder b_builder = arrow::DoubleBuilder();
std::vector<double> b_vals = {4.0, 5.0, 6.0};
ARROW_RETURN_NOT_OK(b_builder.AppendValues(b_vals));
ARROW_ASSIGN_OR_RAISE(auto b_arr, b_builder.Finish());
columns.push_back(b_arr);

auto batch = arrow::RecordBatch::Make(schema, num_rows, columns);

// Call
TableSummation summation;
ARROW_ASSIGN_OR_RAISE(auto total, summation.Compute(batch));

rout << "Total is " << total;
程式碼輸出
Total is 21