Velox Types介绍和源码解析

Velox 支持 scalar(有大小没有方向)类型和复杂类型。标量类型分为一组固定的物理类型和一组可扩展的逻辑类型。物理类型决定数据在内存中的布局。逻辑类型向物理类型添加附加语义。

Phsical Types

每个物理类型都是用c++ type实现的,不会存储实际数据,下表是支持的物理类型、其对应的c++类型和每个值所需的固定宽度字节

Physical TypeC++ TypeFixed Width (bytes)
BOOLEANbool0.125 (i.e. 1 bit)
TINYINTint8_t1
SMALLINTint16_t2
INTEGERint32_t4
BIGINTint64_t8
HUGEINTint128_t16
REALfloat4
DOUBLEdouble8
TIMESTAMPstruct Timestamp16
VARCHARstruct StringView16
VARBINARYstruct StringView16
OPAQUEstd::shared_ptr16
UNKNOWNstruct UnknownValue0

除了VARCHAR and VARBINARY 所有的物理类型都有和 c++类型一对一的映射。c++类型也在vector类中用作模板参数。例如,64 位整数向量表示为 FlatVector<int64_t>,其类型为 BIGINT。

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)。纪元之前的时间戳是使用负秒值指定的。

Logical Types

逻辑类型由物理类型支持并包含附加语义。同一物理类型可以支持多种逻辑类型。因此,了解 C++ 类型不足以推断逻辑类型。下表显示了支持的逻辑类型及其相应的物理类型。

Logical TypePhysical Type
DATEINTEGER
DECIMALBIGINT if precision <= 18, HUGEINT if precision >= 19
INTERVAL DAY TO SECONDBIGINT
INTERVAL YEAR TO MONTHINTEGER

Custom Types

大多数自定义类型可以表示为逻辑类型,并且可以通过扩展现有的物理类型来构建。例如,下面描述的Presto类型是通过扩展物理类型来实现的。当没有物理类型可用于支持逻辑类型时,必须使用OPAQUE类型。

Complex Types

Velox 支持 ARRAY、MAP 和 ROW 复杂类型。复杂类型由标量(scalar)类型组成,可以与其他复杂类型嵌套。

例如: MAP<INTEGER, ARRAY> 是一个复杂类型,其key是标量类型 INTEGER,value是元素类型为 BIGINT 的复杂类型 ARRAY。

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<T>
          				 /      |       \
		        ScalarType  ArrayType   MapType

Type 是抽象基类继承自Tree,复杂类型子类例如ArrayType和MapType会包含子类型,从而形成Tree

TypeBase:从Type派生而来的中间类,借助TypeTraits实现方法,TypeTraits使用模板特化技术根据TypeKind定义以下属性

template <TypeKind KIND>
struct TypeTraits {};

template <>
struct TypeTraits<TypeKind::BOOLEAN> {
  using ImplType = ScalarType<TypeKind::BOOLEAN>; // 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<KIND>;

  TypeBase() : Type{KIND} {}

  bool isPrimitiveType() const override {
    return TypeTraits<KIND>::isPrimitiveType;
  }

  bool isFixedWidth() const override {
    return TypeTraits<KIND>::isFixedWidth;
  }

  const char* kindName() const override {
    return TypeTraits<KIND>::name;
  }

  const char* name() const override {
    return TypeTraits<KIND>::name;
  }

  const std::vector<TypeParameter>& parameters() const override {
    static const std::vector<TypeParameter> kEmpty = {};
    return kEmpty;
  }
};

ScalarType:标量类型类模板,标量对象只含单个元素,以下类型都从ScalarType类模板实例而来:

  • 各种整型类型(对应8-64位宽度的整型,TinyintType、SmallintType、IntegerType、BigintType)
  • RealType、DoubleType
  • VarcharType、VarbinaryType
  • TimestampType、DateType、IntervalDayTimeType
using IntegerType = ScalarType<TypeKind::INTEGER>;
using BooleanType = ScalarType<TypeKind::BOOLEAN>;

ArrayType:对应数组类型,包含一个TypePtr child_成分(也就是Tree的子节点),数组类型所有内部元素的类型相同(只有一个)。

MapType:对应映射类型,包含TypePtr key_ + TypePtr value_两个成分,从Key映射到Value,符合一般映射的语义。

RowType:对应行类型TypeKind=ROW,代表行的每一列的meta信息,包括2个成分。

  • 一个string name_的列表(各列的名称)
  • 一个TypePtr children_的列表(各列的Type信息)

类型工厂:TypeFactory

类模板TypeFactory实现create()接口,用于创建某种具体类型,参考设计模式的工厂方法。

对于标量类型,通常只需要一个唯一的类型实例,因为标量类型不包含额外状态信息(额外是指相对于Type本身状态外)。

对于非标量类型(TypeKind>=30),比如ArrayType、MapType、RowType等类型,因为每个各MapType的Key、Value并不相同,所以需要针对每个类型创建对应的Type。

template <TypeKind KIND>
struct TypeFactory {
  static std::shared_ptr<const typename TypeTraits<KIND>::ImplType> create() {
    return TypeTraits<KIND>::ImplType::create();
  }
};

template <>
struct TypeFactory<TypeKind::UNKNOWN> {
  static std::shared_ptr<const UnknownType> create() {
    return std::make_shared<UnknownType>();
  }
};

利用宏和模板提供了获取类型实例的方法使得INTEGER()等价于return ScalarType<TypeKind::INTEGER>::create();

#define VELOX_SCALAR_ACCESSOR(KIND) \
  std::shared_ptr<const ScalarType<TypeKind::KIND>> KIND()
#define VELOX_DEFINE_SCALAR_ACCESSOR(KIND)                   \
  std::shared_ptr<const ScalarType<TypeKind::KIND>> KIND() { \
    return ScalarType<TypeKind::KIND>::create();             \
  }
VELOX_DEFINE_SCALAR_ACCESSOR(INTEGER); 

CppToType支持根据c++ type获取velox type的相关信息(保存在TypeTraits),实现方法也是模板特化

template <typename T> struct CppToType {};
template <> struct CppToType<int128_t> : public CppToTypeBase<TypeKind::HUGEINT> {};
struct CppToTypeBase : public TypeTraits<KIND> {
  static auto create() {
    return TypeFactory<KIND>::create();
  }
};

CppToType<T>::typeKind // 获取c++ type对应的TypeKind

参考

https://facebookincubator.github.io/velox/develop/types.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值