• <xmp id="om0om">
  • <table id="om0om"><noscript id="om0om"></noscript></table>
  • 數據科學

    使用 RAPIDS 的 Parquet 字符串數據的編碼和壓縮指南

    Parquet Writer 提供了默認關閉的編碼和壓縮選項。啟用這些選項可以為數據提供更好的無損壓縮,但了解用于特定用例的選項對于確保它們按預期執行是至關重要的。

    在本文中,我們將探討哪些編碼和壓縮選項最適合您的字符串數據。字符串數據在數據科學中無處不在,用于表示小片段信息,如名稱、地址和數據標簽,以及大片段信息,如 DNA 序列、JSON 對象和完整文檔。

    首先,我們解釋每個選項。

    • 編碼步驟重新組織數據,以減少其字節大小,同時保留對每個數據點的訪問權限。
    • 壓縮步驟進一步減少了以字節為單位的總大小,但每個壓縮塊必須先被解壓縮,然后數據才能再次被訪問。

    在 Parquet 格式中,有兩種 delta 編碼,旨在優化字符串數據的存儲。為了幫助分析每個選項,我們構建了一項工程研究,使用 libcudf 和 cudf.pandas 對來自公開來源的字符串數據進行分析,以比較 Parquet 的編碼和壓縮方法的有效性,使用文件大小、讀取時間和寫入時間作為指標。

    什么是 RAPIDS libcudf 和 cudf.pandas?

    RAPIDS 開源加速數據科學庫套件中,libcudf 是用于列式數據處理的 CUDA C++ 庫。RAPIDS libcudf 基于 Apache Arrow 內存格式,支持 GPU 加速的讀取器、寫入器、關系代數函數和列轉換。

    在本文中,我們使用 parquet_io C++ 示例 來演示 libcudf API,并評估編碼和壓縮方法。對于讀/寫吞吐量,我們使用 Python read_parquet 函數來顯示零代碼更改性能結果,比較 pandas 和 RAPIDS cudf.pandas 的性能。RAPIDS cudf.pandas 是一個開源的 GPU 加速數據幀庫,可以將現有 pandas 代碼加速高達 150 倍。

    Kaggle 字符串數據和基準測試

    字符串數據非常復雜,編碼和壓縮的有效性取決于數據本身。

    考慮到這一點,我們很早就決定編譯一個字符串列數據集,以比較編碼和壓縮方法。最初,我們探索了幾種數據生成器,但發現數據生成器中有關字符串可壓縮性、基數和長度的決定對文件大小結果產生了巨大影響。

    作為數據生成器的替代方案,我們基于公共數據集組裝了一個包含 149 個字符串列的數據集,總文件大小為 4.6 GB,總字符數為 12 億。我們對每個編碼和壓縮選項進行了比較,比較的項目包括文件大小、讀取時間和寫入時間。

    我們在本文中使用 parquet-cpp-arrow 16.1.0 對 RAPIDS libcudf 24.08 和 pandas 2.2.2 中的 Parquet 讀取器/寫入器堆棧進行了比較。我們發現 libcudf 和 arrow-cpp 之間的編碼大小差異小于 1%。與 libzstd 1.4.8+dfsg-3build1 相比,在 nvCOMP 3.0.6 中使用 ZSTD 實現時,文件大小增加了 3%至 8%。

    總體而言,我們發現本文中關于編碼和壓縮選擇的結論對 CPU Parquet 編寫者和 GPU Parquet 編寫者均適用。

    Parquet 中的字符串編碼

    在 Parquet 中,字符串數據使用字節數組物理類型表示。這意味著字符串數據是以字節的形式存儲的。有關編碼布局的更多信息,請參閱 編碼

    原始字節數組表示包括單字節和多字節字符。Parquet 中有多種編碼方法可用于字節數組數據,其中大多數編寫者默認對字符串數據采用 RLE_DICTIONARY 編碼。

    字典編碼使用字典頁面將字符串值映射到整數,然后寫入使用此字典的數據頁面。如果字典頁面增大(通常超過 1MiB),則 Writer 會回退到 PLAIN 編碼。在這里,32 位大小與原始字節數組交錯。

    在 Parquet V2 規范中,針對字節數組物理類型,添加了兩種新的編碼,這兩種編碼可用于對字符串數據進行編碼。

    • DELTA_LENGTH_BYTE_ARRAY (DLBA):相比 PLAIN 編碼,DLBA 提供了一個簡單的改進。它使用 DELTA_BINARY_PACKED 對整數大小的數據進行分組并進行編碼,并將字節數組數據連接到一個緩沖區中。DLBA 編碼的目標是幫助壓縮階段實現更好的壓縮比,即通過對類似數據進行分組。
    • DELTA_BYTE_ARRAY(DBA):存儲前一個字符串的前綴長度和后綴字節數組。DBA 編碼在排序或半排序數據中效果很好,其中許多字符串值與前一行共享部分前綴。

    按編碼和壓縮劃分的總文件大小

    Bar chart shows the file size sum in GB for NONE, SNAPPY and ZSTD compression methods with default, DLBA, and DBA encoding methods. “Choose best” brings ~3% file size reduction versus “default” by selecting the encoding that yields the smallest file size for each file.
    圖 1. RAPIDS libcudf Parquet Writer 中 149 個字符串列的總文件大小按編碼方法和壓縮方法劃分

    默認情況下,大多數 Parquet 編寫者對字符串列使用字典編碼和 SNAPPY 壓縮。對于數據集中的 149 個字符串列,默認設置會產生總計 4.6 GB 的文件大小。對于壓縮,我們發現 ZSTD 的性能優于 SNAPPY,而 SNAPPY 優于 NONE。

    對于這組字符串列,壓縮對文件大小的影響比編碼更大,其中PLAIN-SNAPPYPLAIN-ZSTD的表現優于未壓縮條件。

    此數據集的最佳單一設置為 default-ZSTD。通過對有好處的文件選擇增量編碼,可以進一步將文件大小總和減少 2.9%。如果僅過濾平均字符串長度少于 50 個字符的字符串列,選擇 best-ZSTD 將顯示文件大小總和相對于 default-ZSTD 減少 3.8%(從 1.32 GB 到 1.27 GB)。

    何時為字符串選擇增量編碼

    默認的字典編碼方法適用于具有低基數和短字符串長度的數據。然而,對于具有高基數或長字符串長度的數據,通常可以通過增量編碼來縮小文件大小。

    對于 arrow-cppparquet-javacudf >=24.06,字典編碼使用 1-MiB 字典頁面大小限制。如果行組中的不同值可以適合此大小,字典編碼可能會生成最小的文件大小。然而,高基數數據不太可能適合 1-MiB 限制,因為長字符串會限制適合 1-MiB 限制的值的數量。

    Scatter plot showing the optimal encoding method when using ZSTD compression for each of 149 string columns. For each point, the x-axis shows “chars/string (average),” the y-axis shows “distinct count”, and the shape of each point indicates whether the best encoding was “Dictionary with plain fallback”, “Delta length byte array” or “Delta byte array”.
    圖 2. 使用 ZSTD 壓縮時的字符串數據最佳編碼方法

    在圖 2 中,每個點分別代表一個字符串列,并根據該列的兩個屬性進行繪制:distinct countchar/string 的平均值。虛線橢圓形被放置以突出顯示近似聚類。

    對于字符串列,當增量編碼產生最小文件大小時,我們發現文件大小縮減最為明顯的是當每個字符串的平均字符數少于 50 時。字符數量包括多字節字符。

    DLBA 編碼的主要好處是將所有大小數據集中到單個緩沖區中,從而提高存儲效率。特別是對于短字符串列,數據大小所占的比例更高。DBA 編碼也顯示了對平均每字符串約 50 個字符的字符串列的最大文件大小縮減,例如有一種情況比字典編碼的默認值小 80%。

    縱觀這些示例,對于具有排序或半排序值(例如升序 ID、格式化時間和時間片段)的列,DBA 編碼可提供最大的文件大小縮減。

    Scatter plot of file size reduction versus chars/string (average), measured as delta-encoded ZSTD-compress versus dictionary-encoded ZSTD-compressed. Both “Delta length byte array” and “Delta byte array” encoding methods are shown.
    圖 3. 使用增量編碼相比具有普通回退的字典編碼,可以減少文件大小。

    在圖 3 中,每個點都代表了一個文件,該文件經過 delta 編碼和 ZSTD 壓縮后獲得了最小的文件大小。虛線是數據的二次最佳擬合線。

    讀取器和寫入器性能

    除了文件大小的數據外,我們還收集了文件寫入時間和讀取時間的數據,其中,GPU 加速的 cudf.pandas 庫的性能比 pandas 好。

    我們沒有將 C++ 與 Python 腳本運行時進行比較,而是使用相同的 Python 腳本與 pandas 和零代碼更改 cudf.pandas 測量了 Parquet 文件處理吞吐量。字符串數據集包括 149 個文件,其中字符串數據的總字符數為 12 億,使用最佳編碼和壓縮方法時磁盤上的總文件大小為 2.7 GB。文件讀取和寫入時間是使用 Samsung 1.9TB PCI-E Gen4 NVMe SSD 數據源、Intel Xeon Platinum 8480CL CPU 和 NVIDIA H100 80GB HBM3 GPU 收集的。處理時間測量為執行讀取或寫入步驟的時間,并對所有文件進行求和。在讀取每個文件之前,操作系統緩存被清除。

    • 使用 pyarrow Parquet 引擎的 Pandas 顯示了 22 MB/s 的讀取吞吐量和 27 MB/s 的寫入吞吐量。
    • Cudf.pandas 在 24.06 中使用默認的 CUDA 內存資源,顯示讀取吞吐量達到 390 MB/s,寫入吞吐量達到 200 MB/s。
    • 將 cudf.pandas 與 RMM 池 結合使用時(通過設置環境變量 CUDF_PANDAS_RMM_MODE="pool"),我們觀察到讀取吞吐量達到 552 MB/s,寫入吞吐量達到 263 MB/s。
    Bar chart showing Parquet file write and read throughput for pandas, cudf.pandas, and cudf.pandas with an RMM pool. The Parquet files used “Choose best” encoding and ZSTD compression.
    圖 4. 字符串數據集的 Parquet 文件處理吞吐量(以 MB/s 為單位)

    字符串數據的編碼和壓縮指南

    基于本文中的比較,我們推薦在處理字符串數據時使用以下編碼和壓縮設置。

    • 對于編碼,Parquet 中字符串的默認字典編碼非常適合處理每列少于 ~100K 個獨立值的字符串數據。
    • 當獨立值超過 10 萬個時,增量增量長度編碼通常會產生最小的文件大小。增量增量長度編碼提供了最大的優勢(10-30% 小文件),對于短字符串(每字符串少于 30 個字符)。
    • 對于壓縮而言,無論采用何種編碼方法,ZSTD 都能生成較小的文件大小,相比 Snappy 和未壓縮選項,因此是一個很好的選擇。

    除了文件大小的數據外,我們還收集了文件寫入時間和讀取時間的數據,結果表明,GPU 加速的 cudf.pandas 相比默認的 pandas,其 Parquet 讀取速度提高了 17-25 倍。

    結束語

    如果您正在尋找最快的方法來試用 GPU 加速的 Parquet 讀取器和寫入器,請參閱 RAPIDS cudf.pandasRAPIDS cuDF,以了解 Google Colab 上的加速數據科學。

    RAPIDS libcudf 提供靈活的 GPU 加速工具,用于以 Parquet、ORC、JSON 和 CSV 等格式讀取和寫入列式數據。要開始使用 RAPIDS libcudf,請構建和運行一些 示例。如果您已在使用 cuDF,可以訪問?GitHub 上的 /rapidsai/cudf/tree/HEAD/cpp/examples/parquet_io,構建和運行新的 C++ parquet_io 示例。

    有關 CUDA 加速數據幀的更多信息,請參閱 cuDF 文檔/rapidsai/cudf GitHub 存儲庫。為了更輕松地進行測試和部署, RAPIDS Docker 容器 也適用于版本和夜間構建。要參與討論,請參閱 RAPIDS Slack 工作空間

    致謝

    非常感謝勞倫斯利弗莫爾國家實驗室的 Ed Seidl,他為 RAPIDS libcudf 貢獻了 V2 標頭支持、增量編碼器和解碼器,以及許多關鍵功能。

    ?

    0

    標簽

    人人超碰97caoporen国产