Apache?Arrow?Parquet存儲(chǔ)與使用
簡(jiǎn)介
Parquet
是一種高效的列式存儲(chǔ)格式,廣泛用于大數(shù)據(jù)系統(tǒng)中的數(shù)據(jù)倉(cāng)庫(kù)和數(shù)據(jù)管理工具中,旨在提高數(shù)據(jù)分析的性能和效率,能夠更好地支持?jǐn)?shù)據(jù)壓縮和列式查詢,同時(shí)兼顧讀寫(xiě)速度和數(shù)據(jù)大小
初衷
為了讓 Hadoop
生態(tài)系統(tǒng)中的任何項(xiàng)目都能利用壓縮、高效的列式數(shù)據(jù)表示的優(yōu)勢(shì)
技術(shù)與原理
基于列存儲(chǔ)和壓縮技術(shù),每一列的數(shù)據(jù)通過(guò)一系列壓縮算法進(jìn)行壓縮,然后存儲(chǔ)到文件系統(tǒng)中,這種方式能夠避免存儲(chǔ)冗余數(shù)據(jù),并且能夠使查詢只涉及到所需的列,從而大大提高查詢效率
相關(guān)術(shù)語(yǔ)
Block
(hdfs Block
):hdfs
中的數(shù)據(jù)塊File
:hdfs
文件,包含文件的元數(shù)據(jù),不需要包含實(shí)際的數(shù)據(jù)Row group
/行組:將數(shù)據(jù)水平劃分為Row group
Column chunk
:特定列的數(shù)據(jù)塊,它們位于特定的行組中,并保證在文件中是連續(xù)的Page
:列塊被分為頁(yè),頁(yè)面在概念上是一個(gè)不可分割的單元(就壓縮和編碼而言),列塊中可以有多種交錯(cuò)的頁(yè)面類型,Page
為了讓數(shù)據(jù)讀取的粒度足夠小,便于單條數(shù)據(jù)或小批量數(shù)據(jù)的查詢
從層次結(jié)構(gòu)上看,文件由一個(gè)或多個(gè)行組組成,行組的每列恰好包含一個(gè)列塊,列塊包含一頁(yè)或多頁(yè)
結(jié)構(gòu)圖如下
文件格式如下
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個(gè)字節(jié),本質(zhì)是一個(gè)magic number
,用來(lái)指示文件類型
PAR1
:普通的Parquet
文件
PARE
: 加密過(guò)的Parquet
文件
File Body
實(shí)際存儲(chǔ)數(shù)據(jù),包含Column Chunk
和Column Metadata
Footer
- 包含了諸如
schema
,Block
的offset
和size
,Column Chunk
的offset
和size
等所有重要的元數(shù)據(jù) - 承擔(dān)了整個(gè)文件入口的職責(zé),讀取
Parquet
文件的第一步就是讀取Footer
信息,轉(zhuǎn)換成元數(shù)據(jù)之后,再根據(jù)這些元數(shù)據(jù)跳轉(zhuǎn)到對(duì)應(yīng)的block
和column
,讀取真正所要的數(shù)據(jù)
Index
Index
是Parquet
文件的索引塊,主要為了支持謂詞下推(Predicate Pushdown
)功能
謂詞下推是一種優(yōu)化查詢性能的技術(shù),簡(jiǎn)單地來(lái)說(shuō)就是把查詢條件發(fā)給存儲(chǔ)層,讓存儲(chǔ)層可以做初步的過(guò)濾,把肯定不滿足查詢條件的數(shù)據(jù)排除掉,從而減少數(shù)據(jù)的讀取和傳輸量
Parquet
索引類型
Max-Min
:Max-Min
索引是對(duì)每個(gè)Page
都記錄它所含數(shù)據(jù)的最大值和最小值,這樣某個(gè)Page
是否不滿足查詢條件就可以通過(guò)這個(gè)Page
的max
和min
值來(lái)判斷BloomFilter
索引: 針對(duì)value
比較稀疏,max-min
范圍比較大的列,用Max-Min
索引的效果就不太好,BloomFilter
可以克服這一點(diǎn),同時(shí)也可以用于單條數(shù)據(jù)的查詢
rust讀寫(xiě)Parquet文件
依賴項(xiàng)目
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(); }
運(yùn)行
$ 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存儲(chǔ)與使用的詳細(xì)內(nèi)容,更多關(guān)于Apache Arrow Parquet存儲(chǔ)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實(shí)現(xiàn)List去重的幾種方法總結(jié)
這篇文章主要為大家詳細(xì)介紹了Java中List去重的幾種常用方法總結(jié),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)和參考價(jià)值,需要的小伙伴可以了解一下2023-09-09Java8新特性之接口中的默認(rèn)方法和靜態(tài)方法詳解
今天帶大家學(xué)習(xí)的是Java8新特性的相關(guān)知識(shí),文章圍繞著Java接口中的默認(rèn)方法和靜態(tài)方法展開(kāi),文中有非常詳細(xì)的的代碼示例,需要的朋友可以參考下2021-06-06Java數(shù)據(jù)結(jié)構(gòu)常見(jiàn)幾大排序梳理
Java常見(jiàn)的排序算法有:直接插入排序、希爾排序、選擇排序、冒泡排序、歸并排序、快速排序、堆排序等。本文詳解介紹它們的實(shí)現(xiàn)以及圖解,需要的可以參考一下2022-03-03spring boot 監(jiān)控處理方案實(shí)例詳解
這篇文章主要介紹了spring boot 監(jiān)控處理方案的相關(guān)資料,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-07-07JAVA使用動(dòng)態(tài)代理對(duì)象進(jìn)行敏感字過(guò)濾代碼實(shí)例
這篇文章主要介紹了JAVA使用動(dòng)態(tài)代理對(duì)象進(jìn)行敏感字過(guò)濾代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09淺談spring的重試機(jī)制無(wú)效@Retryable@EnableRetry
這篇文章主要介紹了淺談spring的重試機(jī)制無(wú)效@Retryable@EnableRetry,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09