Apache?Arrow?Parquet存儲與使用
簡介
Parquet是一種高效的列式存儲格式,廣泛用于大數(shù)據(jù)系統(tǒng)中的數(shù)據(jù)倉庫和數(shù)據(jù)管理工具中,旨在提高數(shù)據(jù)分析的性能和效率,能夠更好地支持數(shù)據(jù)壓縮和列式查詢,同時兼顧讀寫速度和數(shù)據(jù)大小
初衷
為了讓 Hadoop 生態(tài)系統(tǒng)中的任何項目都能利用壓縮、高效的列式數(shù)據(jù)表示的優(yōu)勢
技術與原理
基于列存儲和壓縮技術,每一列的數(shù)據(jù)通過一系列壓縮算法進行壓縮,然后存儲到文件系統(tǒng)中,這種方式能夠避免存儲冗余數(shù)據(jù),并且能夠使查詢只涉及到所需的列,從而大大提高查詢效率
相關術語
Block(hdfs Block):hdfs中的數(shù)據(jù)塊File:hdfs文件,包含文件的元數(shù)據(jù),不需要包含實際的數(shù)據(jù)Row group/行組:將數(shù)據(jù)水平劃分為Row groupColumn chunk:特定列的數(shù)據(jù)塊,它們位于特定的行組中,并保證在文件中是連續(xù)的Page:列塊被分為頁,頁面在概念上是一個不可分割的單元(就壓縮和編碼而言),列塊中可以有多種交錯的頁面類型,Page為了讓數(shù)據(jù)讀取的粒度足夠小,便于單條數(shù)據(jù)或小批量數(shù)據(jù)的查詢
從層次結構上看,文件由一個或多個行組組成,行組的每列恰好包含一個列塊,列塊包含一頁或多頁
結構圖如下

文件格式如下
4-byte magic number "PAR1" <Column 1 Chunk 1 + Column Metadata> <Column 2 Chunk 1 + Column Metadata> ... <Column N Chunk 1 + Column Metadata> <Column 1 Chunk 2 + Column Metadata> <Column 2 Chunk 2 + Column Metadata> ... <Column N Chunk 2 + Column Metadata> ... <Column 1 Chunk M + Column Metadata> <Column 2 Chunk M + Column Metadata> ... <Column N Chunk M + Column Metadata> File Metadata 4-byte length in bytes of file metadata 4-byte magic number "PAR1"
Header
Header的內(nèi)容很少,只有4個字節(jié),本質(zhì)是一個magic number,用來指示文件類型
PAR1:普通的Parquet文件
PARE: 加密過的Parquet文件
File Body
實際存儲數(shù)據(jù),包含Column Chunk和Column Metadata
Footer
- 包含了諸如
schema,Block的offset和size,Column Chunk的offset和size等所有重要的元數(shù)據(jù) - 承擔了整個文件入口的職責,讀取
Parquet文件的第一步就是讀取Footer信息,轉(zhuǎn)換成元數(shù)據(jù)之后,再根據(jù)這些元數(shù)據(jù)跳轉(zhuǎn)到對應的block和column,讀取真正所要的數(shù)據(jù)
Index
Index是Parquet文件的索引塊,主要為了支持謂詞下推(Predicate Pushdown)功能
謂詞下推是一種優(yōu)化查詢性能的技術,簡單地來說就是把查詢條件發(fā)給存儲層,讓存儲層可以做初步的過濾,把肯定不滿足查詢條件的數(shù)據(jù)排除掉,從而減少數(shù)據(jù)的讀取和傳輸量
Parquet索引類型
Max-Min:Max-Min索引是對每個Page都記錄它所含數(shù)據(jù)的最大值和最小值,這樣某個Page是否不滿足查詢條件就可以通過這個Page的max和min值來判斷BloomFilter索引: 針對value比較稀疏,max-min范圍比較大的列,用Max-Min索引的效果就不太好,BloomFilter可以克服這一點,同時也可以用于單條數(shù)據(jù)的查詢
rust讀寫Parquet文件
依賴項目
https://github.com/apache/arrow-r
修改Cargo.toml如下
[dependencies] parquet = "46.0.0" parquet_derive = "46.0.0"
修改main.rs
use std::convert::TryFrom;
use std::{fs, path::Path};
use parquet::file::reader::SerializedFileReader;
use parquet::file::writer::SerializedFileWriter;
use parquet::record::RecordWriter;
use parquet_derive::ParquetRecordWriter;
const PARQUET_FILEPATH: &str = "./target/sample.parquet";
#[derive(ParquetRecordWriter)]
struct ACompleteRecord<'a> {
pub a_bool: bool,
pub a_str: &'a str,
}
fn write() {
let path = Path::new(PARQUET_FILEPATH);
let file = fs::File::create(path).unwrap();
let samples = vec![
ACompleteRecord {
a_bool: true,
a_str: "I'm true",
},
ACompleteRecord {
a_bool: false,
a_str: "I'm false",
},
];
let schema = samples.as_slice().schema().unwrap();
let mut writer = SerializedFileWriter::new(file, schema, Default::default()).unwrap();
let mut row_group = writer.next_row_group().unwrap();
samples
.as_slice()
.write_to_row_group(&mut row_group)
.unwrap();
row_group.close().unwrap();
writer.close().unwrap();
}
fn read() {
let rows = [PARQUET_FILEPATH]
.iter()
.map(|p| SerializedFileReader::try_from(*p).unwrap())
.flat_map(|r| r.into_iter());
for row in rows {
println!("{}", row.unwrap());
}
}
fn main() {
write();
read();
}運行
$ cargo run
Compiling temp v0.1.0 (/home/gong/rust-work/temp)
Finished dev [unoptimized + debuginfo] target(s) in 2.26s
Running `target/debug/temp`
{a_bool: true, a_str: "I'm true"}
{a_bool: false, a_str: "I'm false"}查看parquet文件
$ cat target/sample.parquet
PAR1,X%a_bool44<X22I'm true I'm false,I'm true I'm false
5a_str??&?&?I'm true I'm false I'm falsI'm tru4?V<H
rust_schema%a_bool
%a_str%L,&<%a_bool44<X??"&?
5a_str??&?&?I'm true I'm false??@??(parquet-rs version 46.0.0?PAR1%閱讀參考
以上就是Apache Arrow Parquet存儲與使用的詳細內(nèi)容,更多關于Apache Arrow Parquet存儲的資料請關注腳本之家其它相關文章!
相關文章
Spring boot項目redisTemplate實現(xiàn)輕量級消息隊列的方法
這篇文章主要給大家介紹了關于Spring boot項目redisTemplate實現(xiàn)輕量級消息隊列的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Spring boot具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-04-04

