資料類型#

另請參閱

資料類型 API 參考.

資料類型決定了如何解釋物理資料。它們的規範允許不同 Arrow 實作之間的二進位互通性,包括來自不同程式語言和執行階段的實作(例如,可以使用 pyarrow.jvm 橋接模組,從 Python 和 Java 存取相同的資料,而無需複製)。

在 C++ 中,關於資料類型的資訊可以用三種方式表示

  1. 使用 arrow::DataType 實例(例如,作為函數引數)

  2. 使用 arrow::DataType 具體子類別(例如,作為範本參數)

  3. 使用 arrow::Type::type 列舉值(例如,作為 switch 語句的條件)

第一種形式(使用 arrow::DataType 實例)是最慣用且靈活的。執行階段參數化類型只能用 DataType 實例完整表示。例如,arrow::TimestampType 需要在執行階段使用 arrow::TimeUnit::type 參數建構;arrow::Decimal128Type 帶有scaleprecision 參數;arrow::ListType 帶有完整的子類型(本身也是一個 arrow::DataType 實例)。

在效能至關重要的情況下,可以使用其他兩種形式,以避免支付動態類型和多型性的代價。然而,對於參數化類型,仍然可能需要一些執行階段切換。由於 Arrow 資料類型允許任意巢狀結構,因此無法在編譯時具體化所有可能的類型。

建立資料類型#

為了實例化資料類型,建議呼叫提供的 factory functions

std::shared_ptr<arrow::DataType> type;

// A 16-bit integer type
type = arrow::int16();
// A 64-bit timestamp type (with microsecond granularity)
type = arrow::timestamp(arrow::TimeUnit::MICRO);
// A list type of single-precision floating-point values
type = arrow::list(arrow::float32());

類型特徵#

如果沒有類型特徵,編寫可以處理具體 arrow::DataType 子類別的程式碼將會很冗長。Arrow 的類型特徵將 Arrow 資料類型映射到專門的陣列、純量、建構器和其他相關類型。例如,布林類型具有以下特徵

template <>
struct TypeTraits<BooleanType> {
  using ArrayType = BooleanArray;
  using BuilderType = BooleanBuilder;
  using ScalarType = BooleanScalar;
  using CType = bool;

  static constexpr int64_t bytes_required(int64_t elements) {
    return bit_util::BytesForBits(elements);
  }
  constexpr static bool is_parameter_free = true;
  static inline std::shared_ptr<DataType> type_singleton() { return boolean(); }
};

請參閱 類型特徵 以取得每個欄位的說明。

使用類型特徵,可以編寫可以處理各種 Arrow 類型的範本函數。例如,編寫一個為任何 Arrow 數值類型建立 Fibonacci 數值陣列的函數

template <typename DataType,
          typename BuilderType = typename arrow::TypeTraits<DataType>::BuilderType,
          typename ArrayType = typename arrow::TypeTraits<DataType>::ArrayType,
          typename CType = typename arrow::TypeTraits<DataType>::CType>
arrow::Result<std::shared_ptr<ArrayType>> MakeFibonacci(int32_t n) {
  BuilderType builder;
  CType val = 0;
  CType next_val = 1;
  for (int32_t i = 0; i < n; ++i) {
    builder.Append(val);
    CType temp = val + next_val;
    val = next_val;
    next_val = temp;
  }
  std::shared_ptr<ArrayType> out;
  ARROW_RETURN_NOT_OK(builder.Finish(&out));
  return out;
}

對於某些常見情況,類別本身就有類型關聯。使用

  • Scalar::TypeClass 以取得純量的資料類型類別

  • Array::TypeClass 以取得陣列的資料類型類別

  • DataType::c_type 以取得 Arrow 資料類型的關聯 C 類型

類似於 std::type_traits 中提供的類型特徵,Arrow 提供了類型謂詞,例如 is_number_type 以及包裝 std::enable_if_t 的對應範本,例如 enable_if_number。這些可以約束範本函數僅針對相關類型進行編譯,這在需要實作其他多載時很有用。例如,為任何數值(整數或浮點數)陣列編寫一個 sum 函數

template <typename ArrayType, typename DataType = typename ArrayType::TypeClass,
          typename CType = typename DataType::c_type>
arrow::enable_if_number<DataType, CType> SumArray(const ArrayType& array) {
  CType sum = 0;
  for (std::optional<CType> value : array) {
    if (value.has_value()) {
      sum += value.value();
    }
  }
  return sum;
}

請參閱 類型謂詞 以取得這些的清單。

訪問者模式#

為了處理 arrow::DataTypearrow::Scalararrow::Array,您可能需要編寫基於特定 Arrow 類型進行特化的邏輯。在這些情況下,請使用訪問者模式。Arrow 提供了範本函數

為了使用這些,請為每個專門的類型實作 Status Visit() 方法,然後將類別實例傳遞給 inline visit 函數。為了避免重複的程式碼,請使用上一節中記錄的類型特徵。作為一個簡短的範例,以下是如何對任意數值類型的欄位進行總和計算

class TableSummation {
  double partial = 0.0;
 public:

  arrow::Result<double> Compute(std::shared_ptr<arrow::RecordBatch> batch) {
    for (std::shared_ptr<arrow::Array> array : batch->columns()) {
      ARROW_RETURN_NOT_OK(arrow::VisitArrayInline(*array, this));
    }
    return partial;
  }

  // Default implementation
  arrow::Status Visit(const arrow::Array& array) {
    return arrow::Status::NotImplemented("Cannot compute sum for array of type ",
                                         array.type()->ToString());
  }

  template <typename ArrayType, typename T = typename ArrayType::TypeClass>
  arrow::enable_if_number<T, arrow::Status> Visit(const ArrayType& array) {
    for (std::optional<typename T::c_type> value : array) {
      if (value.has_value()) {
        partial += static_cast<double>(value.value());
      }
    }
    return arrow::Status::OK();
  }
};

Arrow 還提供了抽象訪問者類別(arrow::TypeVisitorarrow::ScalarVisitorarrow::ArrayVisitor)以及每個對應基本類型上的 Accept() 方法(例如 arrow::Array::Accept())。但是,這些無法使用範本函數實作,因此您通常會更喜歡使用 inline 類型訪問者。