資料類型#
另請參閱
資料類型決定了如何解釋物理資料。它們的規範允許不同 Arrow 實作之間的二進位互通性,包括來自不同程式語言和執行階段的實作(例如,可以使用 pyarrow.jvm
橋接模組,從 Python 和 Java 存取相同的資料,而無需複製)。
在 C++ 中,關於資料類型的資訊可以用三種方式表示
使用
arrow::DataType
實例(例如,作為函數引數)使用
arrow::DataType
具體子類別(例如,作為範本參數)使用
arrow::Type::type
列舉值(例如,作為 switch 語句的條件)
第一種形式(使用 arrow::DataType
實例)是最慣用且靈活的。執行階段參數化類型只能用 DataType 實例完整表示。例如,arrow::TimestampType
需要在執行階段使用 arrow::TimeUnit::type
參數建構;arrow::Decimal128Type
帶有scale 和 precision 參數;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::DataType
、arrow::Scalar
或 arrow::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::TypeVisitor
、arrow::ScalarVisitor
、arrow::ArrayVisitor
)以及每個對應基本類型上的 Accept()
方法(例如 arrow::Array::Accept()
)。但是,這些無法使用範本函數實作,因此您通常會更喜歡使用 inline 類型訪問者。