Apache Arrow

https://www.kdnuggets.com/2017/02/apache-arrow-parquet-columnar-data.html

https://arrow.apache.org/

 

https://hyper-db.de/index.html#team

CMU-db,https://github.com/cmu-db/terrier

 

FlatBuffers

https://halfrost.com/flatbuffers_schema/

FlatBuffers 的主要目标是避免反序列化,数据的传输和读取都是可以直接用二进制形式

而Json需要,从对象序列化到string,传输,使用时再反序列化到对象

FlatBuffers (9490 star) 和 Cap'n Proto (5527 star)、simple-binary-encoding (1351 star) 一样,它支持“零拷贝”反序列化,在序列化过程中没有临时对象产生,没有额外的内存分配,访问序列化数据也不需要先将其复制到内存的单独部分,这使得以这些格式访问数据比需要格式的数据(如JSON,CSV 和 protobuf)快得多。

FlatBuffers 专注于移动硬件(内存大小和内存带宽比桌面端硬件更受限制),以及具有最高性能需求的应用程序:游戏

 

SIMD

SIMD,https://blog.csdn.net/tercel_zhang/article/details/80694573

single instruction multiple data,

128bit的寄存器,可以同时放4个32bit的float,对4个float同时执行指令,比如add,就实现了SIMD

SSE指令,Streaming SIMD Extensions的缩写

SSE有8个128位寄存器,XMM0 ~XMM7

可以进行,packed或scalar计算

 

Arrow Format

arrow 格式的特性,

  • Data adjacency for sequential access (scans)

  • O(1) (constant-time) random access

  • SIMD and vectorization-friendly

  • Relocatable without “pointer swizzling”, allowing for true zero-copy access in shared memory

pointer swizzling,指在序列化的时候,需要对point做处理,因为直接存下去是没意义的,下次反序列化的时候,地址变了

 

要理解Arrow的format,直接看例子,

因为是列存,所以存储的格式一定是数组形式

Fixed-size Primitive

两个需要注意的,

1. 用validity bitmap来表示每个item是否为null,如果null count=0,可以不存这bitmap

   We use least-significant bit (LSB) numbering (also known as bit-endianness). This means that within a group of 8 bits, we read right-to-left

   你只需要知道这个bitmap是从右到左的

2. Arrow需要做Padding,这个也是自然的,对cache和SIMD比较友好

The recommendation for 64 byte alignment comes from the Intel performance guide that recommends alignment of memory to match SIMD register width. The specific padding length was chosen because it matches the largest SIMD instruction registers available on widely deployed x86 architecture (Intel AVX-512).

 

看下定长的原始类型,

由于定长,偏移量可以直接算出来,所以不用记录

null也占用同样大小的空间,这里因为要Padding,所以一个定长的数组,至少要占用128字节

 

 

Variable-size List Layout

如果每一个列是个变长的list,

首先在validity的时候,[]是非null;所以只有一个null

Value array在存储数据的时候都是拉平的, 把每个list里面的item依次存下去,这里对于list的null和[]是相同的处理,就是ignore;

然后会单独存储一个offset buffer,记录每个list在Value array中的起始offset

 

 

这里有意思的是,如果是list嵌套list,如何表示? 

做法就是每多一层list嵌套,就增加一层offsets buffer来记录,

比如例子中,第一个offset buffer记录外层list是由哪些内层list组成

这样在读取数据的时候,可以直接基于这个结构,通过多次offset跳转,不用反序列化,实现zero copy?

 

 

 

Struct Layout

arrow还支持struct,结构体

比如,

Struct <
  name: VarBinary
  age: Int32
>

对于结构体的支持,就比较复杂了,因为结构体中每个field是不同类型的,如果要发挥列存或向量化的优势,必须要把每个field独立存储

所以产生child array的概念,每个field对应于一个child array

下面的例子,首先用一个bitmap表示struct本身是否为null

然后在children arrays里面分两个array分别存储,

第一个field是string变长的所以要offset buffer,第二个int是定长的

 

Union Layout

首先什么是union?和struct的区别,就是struct定义的field同时出现,Union是只出现一个 

所以直觉上,我们可以用和struct类似的方式存储Union

先用children arrays来存储每个field,然后只需要一个全局的offset buffer,因为一个slot只会出现一个field,再用一个Type buffer来记录每个slot选的是哪个field

这种记录方式,就是Dense Union

这里有个差异,Union不会直接用bitmap记录null,而是通过child array去记录,这样需要多读几跳,为了省空间?

 

 还有一种记录方式,Sparse Union

之所以叫Sparse,因为在每个child array中都会记录全局的bitmap,每个没有选中当前field的位置也都需要占空间

这样不需要全局的offset buffer,但是多占用很多空间,感觉很废的样子

好处,

While a sparse union may use significantly more space compared with a dense union, it has some advantages that may be desirable in certain use cases:

  • A sparse union is more amenable to vectorized expression evaluation in some use cases.

  • Equal-length arrays can be interpreted as a union by only defining the types array.

例子,

 

Java接口

Java以ValueVector为主,一个Vector代表一个列

 

 

VectorSchemaRoot

一个带schema的RecordBatch的封装

 

 可以通过unload和load,对RecordBatch进行转换,

 

posted on 2019-04-17 19:57  fxjwind  阅读(1750)  评论(0编辑  收藏  举报