讀取和寫入 Apache Parquet 格式#
Apache Parquet 專案提供了一個標準化的開源直欄式儲存格式,用於資料分析系統中。它最初是為了在 Apache Hadoop 中與 Apache Drill、Apache Hive、Apache Impala 和 Apache 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_table
和 ParquetDataset
中的 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)
目前,支援 HDFS
和 Amazon 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 檔案,分別需要將檔案加密和解密屬性傳遞至 ParquetWriter
和 ParquetFile
。
寫入加密的 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
。