Velox 支持 scalar(有大小没有方向)类型和复杂类型。标量类型分为一组固定的物理类型和一组可扩展的逻辑类型。物理类型决定数据在内存中的布局。逻辑类型向物理类型添加附加语义。
每个物理类型都是用c++ type实现的,不会存储实际数据,下表是支持的物理类型、其对应的c++类型和每个值所需的固定宽度字节
Physical Type | C++ Type | Fixed Width (bytes) |
---|---|---|
BOOLEAN | bool | 0.125 (i.e. 1 bit) |
TINYINT | int8_t | 1 |
SMALLINT | int16_t | 2 |
INTEGER | int32_t | 4 |
BIGINT | int64_t | 8 |
HUGEINT | int128_t | 16 |
REAL | float | 4 |
DOUBLE | double | 8 |
TIMESTAMP | struct Timestamp | 16 |
VARCHAR | struct StringView | 16 |
VARBINARY | struct StringView | 16 |
OPAQUE | std::shared_ptr | 16 |
UNKNOWN | struct UnknownValue | 0 |
除了VARCHAR and VARBINARY 所有的物理类型都有和 c++类型一对一的映射。c++类型也在vector类中用作模板参数。例如,64 位整数向量表示为 FlatVector
OPAQUE类型可用于定义自定义类型。OPAQUE类型必须与唯一的std::type_index一起指定。此类型的值必须以std::shared_ptr提供,其中T是C++类型。下面给出了有关何时使用OPAQUE类型定义自定义类型的更多详细信息。
VARCHAR、VARBINARY、OPAQUE 每个值使用可变的字节数。这些类型在 C++ 类型中存储固定宽度部分,在其他地方存储可变宽度部分。所有其他类型的每个值都使用固定宽度字节,如上表所示。VARCHAR和VARBINARY FlatVector将每个值的固定宽度部分存储在StringView中。StringView是一个结构,包含一个4字节大小字段、一个4字节前缀字段和一个指向可变宽度部分的8字节字段指针。每个值的可变宽度部分存储在stringBuffers中。OPAQUE类型将可变宽度部分存储在FlatVector之外。
UNKNOWN类型用于表示unknown type的empty或全为null的vector。例如,SELECT array() 返回 ARRAY(UNKNOWN()),因为无法确定元素的类型。这是有效的,因为array中没有元素。array方法作用:返回具有给定元素的数组
TIMESTAMP类型用于表示特定的时间点。 TIMESTAMP 定义为自 UNIX epoch 以来秒和纳秒的总和。struct Timestamp 包含一个表示秒的 64 位有符号整数和表示纳秒的另一个 64 位无符号整数。纳秒表示时间戳的高精度部分,小于1秒。纳秒的有效范围是 [0, 10^9)。纪元之前的时间戳是使用负秒值指定的。
逻辑类型由物理类型支持并包含附加语义。同一物理类型可以支持多种逻辑类型。因此,了解 C++ 类型不足以推断逻辑类型。下表显示了支持的逻辑类型及其相应的物理类型。
Logical Type | Physical Type |
---|---|
DATE | INTEGER |
DECIMAL | BIGINT if precision <= 18, HUGEINT if precision >= 19 |
INTERVAL DAY TO SECOND | BIGINT |
INTERVAL YEAR TO MONTH | INTEGER |
大多数自定义类型可以表示为逻辑类型,并且可以通过扩展现有的物理类型来构建。例如,下面描述的Presto类型是通过扩展物理类型来实现的。当没有物理类型可用于支持逻辑类型时,必须使用OPAQUE类型。
Velox 支持 ARRAY、MAP 和 ROW 复杂类型。复杂类型由标量(scalar)类型组成,可以与其他复杂类型嵌套。
例如: MAP
Array类型包含其元素类型。 Map类型包含键类型和值类型。row类型包含其字段类型及其名称。
Type 定义了velox的内置类型的一些信息提供一些接口,不存储实际的数据
枚举类型TypeKind定义类型的种类
enum class TypeKind : int8_t {
BOOLEAN = 0,
TINYINT = 1,
SMALLINT = 2,
INTEGER = 3,
BIGINT = 4,
REAL = 5,
DOUBLE = 6,
VARCHAR = 7,
VARBINARY = 8,
TIMESTAMP = 9,
HUGEINT = 10,
// Enum values for ComplexTypes start after 30 to leave
// some values space to accommodate adding new scalar/native
// types above.
ARRAY = 30,
MAP = 31,
ROW = 32,
UNKNOWN = 33,
FUNCTION = 34,
OPAQUE = 35,
INVALID = 36
};
下面是Type的继承结构
Type
|
TypeBase
/ | \
ScalarType ArrayType MapType
Type 是抽象基类继承自Tree,复杂类型子类例如ArrayType和MapType会包含子类型,从而形成Tree
TypeBase:从Type派生而来的中间类,借助TypeTraits实现方法,TypeTraits使用模板特化技术根据TypeKind定义以下属性
template
struct TypeTraits {};
template <>
struct TypeTraits {
using ImplType = ScalarType; // velox实现的 type
using NativeType = bool; // c++ type,对于无法映射的复杂类型这里是void
using DeepCopiedType = NativeType;
static constexpr uint32_t minSubTypes = 0;
static constexpr uint32_t maxSubTypes = 0;
static constexpr TypeKind typeKind = TypeKind::BOOLEAN;// TypeKind
static constexpr bool isPrimitiveType = true; // 是否为c++原生类型
static constexpr bool isFixedWidth = true;// 是否为固定长度
static constexpr const char* name = "BOOLEAN";//类型名
};
class TypeBase : public Type {
public:
using NativeType = TypeTraits;
TypeBase() : Type{KIND} {}
bool isPrimitiveType() const override {
return TypeTraits::isPrimitiveType;
}
bool isFixedWidth() const override {
return TypeTraits::isFixedWidth;
}
const char* kindName() const override {
return TypeTraits::name;
}
const char* name() const override {
return TypeTraits::name;
}
const std::vector& parameters() const override {
static const std::vector kEmpty = {};
return kEmpty;
}
};
ScalarType:标量类型类模板,标量对象只含单个元素,以下类型都从ScalarType类模板实例而来:
using IntegerType = ScalarType;
using BooleanType = ScalarType;
ArrayType:对应数组类型,包含一个TypePtr child_成分(也就是Tree的子节点),数组类型所有内部元素的类型相同(只有一个)。
MapType:对应映射类型,包含TypePtr key_ + TypePtr value_两个成分,从Key映射到Value,符合一般映射的语义。
RowType:对应行类型TypeKind=ROW,代表行的每一列的meta信息,包括2个成分。
类模板TypeFactory实现create()接口,用于创建某种具体类型,参考设计模式的工厂方法。
对于标量类型,通常只需要一个唯一的类型实例,因为标量类型不包含额外状态信息(额外是指相对于Type本身状态外)。
对于非标量类型(TypeKind>=30),比如ArrayType、MapType、RowType等类型,因为每个各MapType的Key、Value并不相同,所以需要针对每个类型创建对应的Type。
template
struct TypeFactory {
static std::shared_ptr::ImplType> create() {
return TypeTraits::ImplType::create();
}
};
template <>
struct TypeFactory {
static std::shared_ptr create() {
return std::make_shared();
}
};
利用宏和模板提供了获取类型实例的方法使得INTEGER()等价于return ScalarType
#define VELOX_SCALAR_ACCESSOR(KIND) \
std::shared_ptr> KIND()
#define VELOX_DEFINE_SCALAR_ACCESSOR(KIND) \
std::shared_ptr> KIND() { \
return ScalarType::create(); \
}
VELOX_DEFINE_SCALAR_ACCESSOR(INTEGER);
CppToType支持根据c++ type获取velox type的相关信息(保存在TypeTraits),实现方法也是模板特化
template struct CppToType {};
template <> struct CppToType : public CppToTypeBase {};
struct CppToTypeBase : public TypeTraits {
static auto create() {
return TypeFactory::create();
}
};
CppToType::typeKind // 获取c++ type对应的TypeKind
https://facebookincubator.github.io/velox/develop/types.html