讀取和寫入 Apache Parquet 格式#

Apache Parquet 專案提供了一個標準化的開源直欄式儲存格式,用於資料分析系統中。它最初是為了在 Apache Hadoop 中與 Apache DrillApache HiveApache ImpalaApache Spark 等系統一起使用而創建的,這些系統都採用它作為高效能資料 IO 的共享標準。

Apache Arrow 是用於讀取或寫入 Parquet 檔案的資料的理想記憶體內傳輸層。我們一直在並行開發 Apache Parquet 的 C++ 實作,其中包括原生、多執行緒的 C++ 配接器,用於與記憶體內 Arrow 資料進行轉換。PyArrow 包含此程式碼的 Python 綁定,因此也支援使用 pandas 讀取和寫入 Parquet 檔案。

取得支援 Parquet 的 pyarrow#

如果您使用 pip 或 conda 安裝 pyarrow,則應已建置並捆綁 Parquet 支援

In [1]: import pyarrow.parquet as pq

如果您是從原始碼建置 pyarrow,則在編譯 C++ 函式庫時必須使用 -DARROW_PARQUET=ON,並在建置 pyarrow 時啟用 Parquet 擴充功能。如果您想使用 Parquet 加密,那麼在編譯 C++ 函式庫時也必須使用 -DPARQUET_REQUIRE_ENCRYPTION=ON。 有關更多詳細資訊,請參閱Python 開發頁面。

讀取和寫入單個檔案#

函數 read_table()write_table() 分別讀取和寫入 pyarrow.Table 物件。

讓我們看一個簡單的表格

In [2]: import numpy as np

In [3]: import pandas as pd

In [4]: import pyarrow as pa

In [5]: df = pd.DataFrame({'one': [-1, np.nan, 2.5],
   ...:                    'two': ['foo', 'bar', 'baz'],
   ...:                    'three': [True, False, True]},
   ...:                    index=list('abc'))
   ...: 

In [6]: table = pa.Table.from_pandas(df)

我們使用 write_table 將其寫入 Parquet 格式

In [7]: import pyarrow.parquet as pq

In [8]: pq.write_table(table, 'example.parquet')

這會建立一個單個 Parquet 檔案。實際上,Parquet 資料集可能由許多目錄中的許多檔案組成。 我們可以使用 read_table 讀回單個檔案

In [9]: table2 = pq.read_table('example.parquet')

In [10]: table2.to_pandas()
Out[10]: 
   one  two  three
a -1.0  foo   True
b  NaN  bar  False
c  2.5  baz   True

您可以傳遞要讀取的欄位子集,這可能比讀取整個檔案快得多(由於直欄式佈局)

In [11]: pq.read_table('example.parquet', columns=['one', 'three'])
Out[11]: 
pyarrow.Table
one: double
three: bool
----
one: [[-1,null,2.5]]
three: [[true,false,true]]

當從使用 Pandas dataframe 作為來源的檔案中讀取欄位子集時,我們使用 read_pandas 來維護任何額外的索引欄位資料

In [12]: pq.read_pandas('example.parquet', columns=['two']).to_pandas()
Out[12]: 
   two
a  foo
b  bar
c  baz

我們不需要使用字串來指定檔案的來源。它可以是以下任何一種

  • 作為字串的檔案路徑

  • 來自 PyArrow 的 NativeFile

  • Python 檔案物件

一般來說,Python 檔案物件的讀取效能最差,而字串檔案路徑或 NativeFile 的實例(尤其是記憶體映射)將表現最佳。

讀取 Parquet 和記憶體映射#

由於 Parquet 資料需要從 Parquet 格式和壓縮中解碼,因此無法直接從磁碟映射。因此,memory_map 選項在某些系統上可能會表現更好,但對於常駐記憶體消耗沒有太大幫助。

>>> pq_array = pa.parquet.read_table("area1.parquet", memory_map=True)
>>> print("RSS: {}MB".format(pa.total_allocated_bytes() >> 20))
RSS: 4299MB

>>> pq_array = pa.parquet.read_table("area1.parquet", memory_map=False)
>>> print("RSS: {}MB".format(pa.total_allocated_bytes() >> 20))
RSS: 4299MB

如果您需要處理大於記憶體的 Parquet 資料,則表格資料集和分割可能是您正在尋找的。

Parquet 檔案寫入選項#

write_table() 有許多選項可以在寫入 Parquet 檔案時控制各種設定。

  • version,要使用的 Parquet 格式版本。'1.0' 確保與舊版讀取器相容,而 '2.4' 及更高版本啟用更多 Parquet 類型和編碼。

  • data_page_size,用於控制欄位區塊內編碼資料頁面的近似大小。目前預設為 1MB。

  • flavor,用於設定特定於 Parquet 消費者的相容性選項,例如 Apache Spark 的 'spark'

有關更多詳細資訊,請參閱 write_table() 文件字串。

下面描述了一些其他特定於資料類型處理的選項。

省略 DataFrame 索引#

當使用 pa.Table.from_pandas 轉換為 Arrow 表格時,預設情況下會新增一個或多個特殊欄位來追蹤索引(列標籤)。儲存索引會佔用額外空間,因此如果您的索引沒有價值,您可以選擇通過傳遞 preserve_index=False 來省略它

In [13]: df = pd.DataFrame({'one': [-1, np.nan, 2.5],
   ....:                    'two': ['foo', 'bar', 'baz'],
   ....:                    'three': [True, False, True]},
   ....:                    index=list('abc'))
   ....: 

In [14]: df
Out[14]: 
   one  two  three
a -1.0  foo   True
b  NaN  bar  False
c  2.5  baz   True

In [15]: table = pa.Table.from_pandas(df, preserve_index=False)

然後我們有

In [16]: pq.write_table(table, 'example_noindex.parquet')

In [17]: t = pq.read_table('example_noindex.parquet')

In [18]: t.to_pandas()
Out[18]: 
   one  two  three
0 -1.0  foo   True
1  NaN  bar  False
2  2.5  baz   True

在這裡您可以看到索引在往返過程中沒有保留下來。

更精細的讀取和寫入#

read_table 使用 ParquetFile 類別,它具有其他功能

In [19]: parquet_file = pq.ParquetFile('example.parquet')

In [20]: parquet_file.metadata
Out[20]: 
<pyarrow._parquet.FileMetaData object at 0x7fe3e51e8180>
  created_by: parquet-cpp-arrow version 19.0.0
  num_columns: 4
  num_rows: 3
  num_row_groups: 1
  format_version: 2.6
  serialized_size: 2572

In [21]: parquet_file.schema
Out[21]: 
<pyarrow._parquet.ParquetSchema object at 0x7fe3e5829640>
required group field_id=-1 schema {
  optional double field_id=-1 one;
  optional binary field_id=-1 two (String);
  optional boolean field_id=-1 three;
  optional binary field_id=-1 __index_level_0__ (String);
}

正如您可以從 Apache Parquet 格式 中了解更多資訊一樣,Parquet 檔案由多個列群組組成。read_table 將讀取所有列群組並將它們串連成一個表格。 您可以使用 read_row_group 讀取單個列群組

In [22]: parquet_file.num_row_groups
Out[22]: 1

In [23]: parquet_file.read_row_group(0)
Out[23]: 
pyarrow.Table
one: double
two: string
three: bool
__index_level_0__: string
----
one: [[-1,null,2.5]]
two: [["foo","bar","baz"]]
three: [[true,false,true]]
__index_level_0__: [["a","b","c"]]

我們可以使用 ParquetWriter 類似地寫入具有多個列群組的 Parquet 檔案

In [24]: with pq.ParquetWriter('example2.parquet', table.schema) as writer:
   ....:    for i in range(3):
   ....:       writer.write_table(table)
   ....: 

In [25]: pf2 = pq.ParquetFile('example2.parquet')

In [26]: pf2.num_row_groups
Out[26]: 3

檢視 Parquet 檔案 Metadata#

Parquet 檔案的 FileMetaData 可以透過 ParquetFile 存取,如上所示

In [27]: parquet_file = pq.ParquetFile('example.parquet')

In [28]: metadata = parquet_file.metadata

或也可以直接使用 read_metadata() 讀取

In [29]: metadata = pq.read_metadata('example.parquet')

In [30]: metadata
Out[30]: 
<pyarrow._parquet.FileMetaData object at 0x7fe3e17126b0>
  created_by: parquet-cpp-arrow version 19.0.0
  num_columns: 4
  num_rows: 3
  num_row_groups: 1
  format_version: 2.6
  serialized_size: 2572

傳回的 FileMetaData 物件允許您檢視 Parquet 檔案 metadata,例如列組和欄塊 metadata 與統計資訊

In [31]: metadata.row_group(0)
Out[31]: 
<pyarrow._parquet.RowGroupMetaData object at 0x7fe3e17758f0>
  num_columns: 4
  num_rows: 3
  total_byte_size: 282
  sorting_columns: ()

In [32]: metadata.row_group(0).column(0)
Out[32]: 
<pyarrow._parquet.ColumnChunkMetaData object at 0x7fe3e1775cb0>
  file_offset: 0
  file_path: 
  physical_type: DOUBLE
  num_values: 3
  path_in_schema: one
  is_stats_set: True
  statistics:
    <pyarrow._parquet.Statistics object at 0x7fe3e1775d50>
      has_min_max: True
      min: -1.0
      max: 2.5
      null_count: 1
      distinct_count: None
      num_values: 2
      physical_type: DOUBLE
      logical_type: None
      converted_type (legacy): NONE
  compression: SNAPPY
  encodings: ('PLAIN', 'RLE', 'RLE_DICTIONARY')
  has_dictionary_page: True
  dictionary_page_offset: 4
  data_page_offset: 36
  total_compressed_size: 104
  total_uncompressed_size: 100

資料類型處理#

將類型讀取為 DictionaryArray#

read_tableParquetDataset 中的 read_dictionary 選項會導致欄位以 DictionaryArray 讀取,轉換為 pandas 時,這會變成 pandas.Categorical。此選項僅適用於字串和二進位欄位類型,對於具有許多重複字串值的欄位,它可以顯著降低記憶體使用量並提高效能。

pq.read_table(table, where, read_dictionary=['binary_c0', 'stringb_c2'])

儲存時間戳記#

某些 Parquet 讀取器可能僅支援以毫秒 ('ms') 或微秒 ('us') 解析度儲存的時間戳記。由於 pandas 使用奈秒來表示時間戳記,這偶爾可能會造成困擾。依預設 (在寫入 1.0 版本的 Parquet 檔案時),奈秒將轉換為微秒 ('us')。

此外,我們提供 coerce_timestamps 選項,讓您可以選擇所需的解析度

pq.write_table(table, where, coerce_timestamps='ms')

如果轉換為較低解析度的值可能會導致資料遺失,依預設會引發例外。可以透過傳遞 allow_truncated_timestamps=True 來抑制此行為

pq.write_table(table, where, coerce_timestamps='ms',
               allow_truncated_timestamps=True)

使用較新的 Parquet 格式版本 2.6 時,可以儲存具有奈秒的時間戳記,而無需轉換

pq.write_table(table, where, version='2.6')

但是,許多 Parquet 讀取器尚不支援此較新的格式版本,因此預設設定是寫入 1.0 版本的檔案。當需要跨不同處理框架的相容性時,建議使用預設的 1.0 版本。

較舊的 Parquet 實作使用基於 INT96 的時間戳記儲存,但現在已棄用。這包括某些舊版本的 Apache Impala 和 Apache Spark。若要以此格式寫入時間戳記,請在 write_table 中將 use_deprecated_int96_timestamps 選項設定為 True

pq.write_table(table, where, use_deprecated_int96_timestamps=True)

壓縮、編碼和檔案相容性#

最常用的 Parquet 實作在寫入檔案時使用字典編碼;如果字典變得太大,它們會「回退」到純文字編碼。是否使用字典編碼可以使用 use_dictionary 選項切換

pq.write_table(table, where, use_dictionary=False)

列組中欄位內的資料頁面可以在編碼通過後 (字典、RLE 編碼) 進行壓縮。在 PyArrow 中,我們預設使用 Snappy 壓縮,但也支援 Brotli、Gzip、ZSTD、LZ4 和未壓縮

pq.write_table(table, where, compression='snappy')
pq.write_table(table, where, compression='gzip')
pq.write_table(table, where, compression='brotli')
pq.write_table(table, where, compression='zstd')
pq.write_table(table, where, compression='lz4')
pq.write_table(table, where, compression='none')

Snappy 通常會產生更好的效能,而 Gzip 可能會產生更小的檔案。

這些設定也可以在每個欄位的基礎上設定

pq.write_table(table, where, compression={'foo': 'snappy', 'bar': 'gzip'},
               use_dictionary=['foo', 'bar'])

分割資料集 (多個檔案)#

多個 Parquet 檔案構成一個 Parquet *資料集*。這些資料集可能以多種方式呈現

  • Parquet 絕對檔案路徑的清單

  • 包含巢狀目錄的目錄名稱,定義分割資料集

按年份和月份分割的資料集在磁碟上可能如下所示

dataset_name/
  year=2007/
    month=01/
       0.parq
       1.parq
       ...
    month=02/
       0.parq
       1.parq
       ...
    month=03/
    ...
  year=2008/
    month=01/
    ...
  ...

寫入分割資料集#

您可以為任何 pyarrow 檔案系統寫入分割資料集,該檔案系統是檔案儲存區 (例如,本機、HDFS、S3)。在未新增檔案系統時的預設行為是使用本機檔案系統。

# Local dataset write
pq.write_to_dataset(table, root_path='dataset_name',
                    partition_cols=['one', 'two'])

在這種情況下,根路徑指定資料將儲存到的父目錄。分割欄位是要用於分割資料集的欄位名稱。欄位會按照給定的順序分割。分割拆分由分割欄位中的唯一值決定。

若要使用另一個檔案系統,您只需要新增檔案系統參數,個別的表格寫入會使用 with 陳述式包裝,因此不需要 pq.write_to_dataset 函數。

# Remote file-system example
from pyarrow.fs import HadoopFileSystem
fs = HadoopFileSystem(host, port, user=user, kerb_ticket=ticket_cache_path)
pq.write_to_dataset(table, root_path='dataset_name',
                    partition_cols=['one', 'two'], filesystem=fs)

相容性注意事項:如果使用 pq.write_to_dataset 建立將由 HIVE 使用的表格,則分割欄位值必須與您執行的 HIVE 版本允許的字元集相容。

寫入 _metadata_common_metadata 檔案#

某些處理框架 (例如 Spark 或 Dask) (選擇性地) 將 _metadata_common_metadata 檔案用於分割資料集。

這些檔案包含完整資料集的結構描述資訊 (適用於 _common_metadata),以及分割資料集中所有檔案的所有列組 metadata (也可能包含) (適用於 _metadata)。實際檔案是僅包含 metadata 的 Parquet 檔案。請注意,這不是 Parquet 標準,而是這些框架在實務中設定的慣例。

使用這些檔案可以更有效率地建立 Parquet 資料集,因為它可以使用儲存的結構描述和所有列組的檔案路徑,而不是推斷結構描述和爬梳目錄以尋找所有 Parquet 檔案 (對於存取檔案成本高昂的檔案系統而言尤其如此)。

write_to_dataset() 函數不會自動寫入這類 metadata 檔案,但您可以使用它來收集 metadata 並手動組合和寫入它們

# Write a dataset and collect metadata information of all written files
metadata_collector = []
pq.write_to_dataset(table, root_path, metadata_collector=metadata_collector)

# Write the ``_common_metadata`` parquet file without row groups statistics
pq.write_metadata(table.schema, root_path / '_common_metadata')

# Write the ``_metadata`` parquet file with row groups statistics of all files
pq.write_metadata(
    table.schema, root_path / '_metadata',
    metadata_collector=metadata_collector
)

當不使用 write_to_dataset() 函數,而是使用 write_table()ParquetWriter 寫入分割資料集的個別檔案時,也可以使用 metadata_collector 關鍵字來收集已寫入檔案的 FileMetaData。在這種情況下,您需要在組合 metadata 之前,確保自行設定列組 metadata 中包含的檔案路徑,並且所有不同檔案和收集的 FileMetaData 物件的結構描述應相同

metadata_collector = []
pq.write_table(
    table1, root_path / "year=2017/data1.parquet",
    metadata_collector=metadata_collector
)

# set the file path relative to the root of the partitioned dataset
metadata_collector[-1].set_file_path("year=2017/data1.parquet")

# combine and write the metadata
metadata = metadata_collector[0]
for _meta in metadata_collector[1:]:
    metadata.append_row_groups(_meta)
metadata.write_metadata_file(root_path / "_metadata")

# or use pq.write_metadata to combine and write in a single step
pq.write_metadata(
    table1.schema, root_path / "_metadata",
    metadata_collector=metadata_collector
)

從分割資料集讀取#

ParquetDataset 類別接受目錄名稱或檔案路徑清單,並且可以探索和推斷一些常見的分割結構,例如 Hive 產生的結構

dataset = pq.ParquetDataset('dataset_name/')
table = dataset.read()

您也可以使用 pyarrow.parquet 公開的便利函數 read_table,避免額外的資料集物件建立步驟。

table = pq.read_table('dataset_name')

注意:原始表格中的分割欄位在載入時,其類型會轉換為 Arrow 字典類型 (pandas categorical)。分割欄位的順序不會透過儲存/載入程序保留。如果從遠端檔案系統讀取到 pandas dataframe 中,您可能需要執行 sort_index 以維持列順序 (只要在寫入時啟用 preserve_index 選項)。

其他功能

  • 對所有欄位 (使用列組統計資訊) 而不僅僅是對分割鍵進行篩選。

  • 精細分割:除了類似 Hive 的分割之外,還支援目錄分割方案 (例如「/2019/11/15/」而不是「/year=2019/month=11/day=15/」),以及指定分割鍵結構描述的能力。

注意

  • 當您想要在讀取欄位的子集時將分割鍵包含在結果中時,需要將分割鍵明確包含在 columns 關鍵字中

與 Spark 搭配使用#

Spark 對它將讀取的 Parquet 檔案類型施加了一些限制。flavor='spark' 選項將自動設定這些選項,並清除 Spark SQL 不支援的欄位字元。

多執行緒讀取#

預設情況下,每個讀取函數都使用多執行緒平行讀取欄位。根據 IO 的速度以及解碼特定檔案中的欄位有多昂貴 (特別是使用 GZIP 壓縮時),這可以產生顯著更高的資料輸送量。

可以透過指定 use_threads=False 來停用此功能。

注意

要同時使用的執行緒數目由 Arrow 自動推斷,並且可以使用 cpu_count() 函數檢查。

從雲端儲存空間讀取#

除了本機檔案之外,pyarrow 還透過 filesystem 關鍵字支援其他檔案系統,例如雲端檔案系統

from pyarrow import fs

s3  = fs.S3FileSystem(region="us-east-2")
table = pq.read_table("bucket/object/key/prefix", filesystem=s3)

目前,支援 HDFSAmazon S3 相容 儲存空間。如需更多詳細資訊,請參閱 檔案系統介面 文件。對於這些內建檔案系統,如果指定為 URI,也可以從檔案路徑推斷檔案系統

table = pq.read_table("s3://bucket/object/key/prefix")

如果存在與 fsspec 相容的實作可用,仍然可以支援其他檔案系統。如需更多詳細資訊,請參閱 將與 fsspec 相容的檔案系統與 Arrow 搭配使用。Azure Blob 儲存空間就是一個範例,可以透過 adlfs 套件介接。

from adlfs import AzureBlobFileSystem

abfs = AzureBlobFileSystem(account_name="XXXX", account_key="XXXX", container_name="XXXX")
table = pq.read_table("file.parquet", filesystem=abfs)

Parquet 模組化加密 (欄位加密)#

從 Apache Arrow 4.0.0 開始,C++ 中的 Parquet 檔案支援欄位加密,而從 Apache Arrow 6.0.0 開始,PyArrow 中也支援欄位加密。

Parquet 使用信封加密實務,其中檔案部分使用「資料加密金鑰」(DEK) 加密,而 DEK 使用「主加密金鑰」(MEK) 加密。DEK 由 Parquet 為每個加密的檔案/欄位隨機產生。MEK 由使用者選擇的金鑰管理服務 (KMS) 產生、儲存和管理。

讀取和寫入加密的 Parquet 檔案,分別需要將檔案加密和解密屬性傳遞至 ParquetWriterParquetFile

寫入加密的 Parquet 檔案

encryption_properties = crypto_factory.file_encryption_properties(
                                 kms_connection_config, encryption_config)
with pq.ParquetWriter(filename, schema,
                     encryption_properties=encryption_properties) as writer:
   writer.write_table(table)

讀取加密的 Parquet 檔案

decryption_properties = crypto_factory.file_decryption_properties(
                                                 kms_connection_config)
parquet_file = pq.ParquetFile(filename,
                              decryption_properties=decryption_properties)

為了建立加密和解密屬性,應建立 pyarrow.parquet.encryption.CryptoFactory,並使用 KMS Client 詳細資訊初始化,如下所述。

KMS Client#

主加密金鑰應保留在使用者組織中部署的生產級金鑰管理系統 (KMS) 中進行管理。使用 Parquet 加密需要實作 KMS 伺服器的用戶端類別。任何 KmsClient 實作都應實作 pyarrow.parquet.encryption.KmsClient 定義的非正式介面,如下所示

import pyarrow.parquet.encryption as pe

class MyKmsClient(pe.KmsClient):

   """An example KmsClient implementation skeleton"""
   def __init__(self, kms_connection_configuration):
      pe.KmsClient.__init__(self)
      # Any KMS-specific initialization based on
      # kms_connection_configuration comes here

   def wrap_key(self, key_bytes, master_key_identifier):
      wrapped_key = ... # call KMS to wrap key_bytes with key specified by
                        # master_key_identifier
      return wrapped_key

   def unwrap_key(self, wrapped_key, master_key_identifier):
      key_bytes = ... # call KMS to unwrap wrapped_key with key specified by
                      # master_key_identifier
      return key_bytes

具體實作將在執行階段由使用者提供的 Factory 函數載入。此 Factory 函數將用於初始化 pyarrow.parquet.encryption.CryptoFactory,以建立檔案加密和解密屬性。

例如,為了使用上面定義的 MyKmsClient

def kms_client_factory(kms_connection_configuration):
   return MyKmsClient(kms_connection_configuration)

crypto_factory = CryptoFactory(kms_client_factory)

可以在 Apache Arrow GitHub 儲存庫中找到開放原始碼 KMS 的此類類別的 範例。生產 KMS 用戶端應與組織的安全性管理員合作設計,並由具有存取控制管理經驗的開發人員建置。一旦建立此類別,就可以透過 Factory 方法將其傳遞給應用程式,並由一般 PyArrow 使用者利用,如上面的加密 parquet 寫入/讀取範例所示。

KMS 連線組態#

KMS 的連線組態 (pyarrow.parquet.encryption.KmsConnectionConfig 在建立檔案加密和解密屬性時使用) 包括以下選項

  • kms_instance_url,KMS 執行個體的 URL。

  • kms_instance_id,將用於加密的 KMS 執行個體的 ID (如果有多個 KMS 執行個體可用)。

  • key_access_token,將傳遞至 KMS 的授權權杖。

  • custom_kms_conf,具有 KMS 類型特定組態的字串字典。

加密組態#

pyarrow.parquet.encryption.EncryptionConfiguration (在建立檔案加密屬性時使用) 包括以下選項

  • footer_key,用於頁尾加密/簽署的主金鑰 ID。

  • column_keys,要使用哪個金鑰加密哪些欄位。字典,其中主金鑰 ID 作為金鑰,欄位名稱清單作為值,例如 {key1: [col1, col2], key2: [col3]}

  • encryption_algorithm,Parquet 加密演算法。可以是 AES_GCM_V1 (預設) 或 AES_GCM_CTR_V1

  • plaintext_footer,是否以純文字寫入檔案頁尾 (否則會加密)。

  • double_wrapping,是否使用雙重包裝 - 其中資料加密金鑰 (DEK) 使用金鑰加密金鑰 (KEK) 加密,而金鑰加密金鑰又使用主加密金鑰 (MEK) 加密。如果設定為 false,則使用單一包裝 - 其中 DEK 直接使用 MEK 加密。

  • cache_lifetime,快取實體 (金鑰加密金鑰、本機包裝金鑰、KMS 用戶端物件) 的生命週期,表示為 datetime.timedelta

  • internal_key_material,是否將金鑰材料儲存在 Parquet 檔案頁尾內;此模式不會產生其他檔案。如果設定為 false,金鑰材料會儲存在相同資料夾中的個別檔案中,這可以為不可變的 Parquet 檔案啟用金鑰輪換。

  • data_key_length_bits,資料加密金鑰 (DEK) 的長度,由 Parquet 金鑰管理工具隨機產生。可以是 128、192 或 256 位元。

注意

double_wrapping 為 true 時,Parquet 會實作「雙重信封加密」模式,以最大程度地減少程式與 KMS 伺服器的互動。在此模式下,DEK 使用「金鑰加密金鑰」(KEK,由 Parquet 隨機產生) 加密。KEK 在 KMS 中使用「主加密金鑰」(MEK) 加密;結果和 KEK 本身會快取在程序記憶體中。

加密組態範例

encryption_config = pq.EncryptionConfiguration(
   footer_key="footer_key_name",
   column_keys={
      "column_key_name": ["Column1", "Column2"],
   },
)

解密組態#

pyarrow.parquet.encryption.DecryptionConfiguration (在建立檔案解密屬性時使用) 是選用的,它包括以下選項

  • cache_lifetime,快取實體 (金鑰加密金鑰、本機包裝金鑰、KMS 用戶端物件) 的生命週期,表示為 datetime.timedelta