跳到內容

處理儲存在雲端儲存系統(如 Amazon Simple Storage Service (S3) 和 Google Cloud Storage (GCS))中的資料是一項非常常見的任務。因此,Arrow C++ 函式庫提供了一套工具組,旨在讓雲端儲存空間的使用像使用本機檔案系統一樣簡單。

為了實現這一點,Arrow C++ 函式庫包含了一個用於檔案系統的通用介面,而 arrow 套件將此介面公開給 R 使用者。例如,如果您願意,您可以建立一個 LocalFileSystem 物件,讓您以通常的方式與本機檔案系統互動:複製、移動和刪除檔案、獲取有關檔案和資料夾的資訊等等(詳情請參閱 help("FileSystem", package = "arrow"))。一般來說,您可能不需要此功能,因為您已經有工具可以處理本機檔案系統,但此介面在遠端檔案系統的上下文中變得更加有用。目前,S3FileSystem 類別為 Amazon S3 提供了特定的實作,而 GcsFileSystem 則為 Google Cloud Storage 提供了實作。

本文概述了如何使用 Arrow 工具組處理 S3 和 GCS 資料。

Linux 上的 S3 和 GCS 支援

在開始之前,請確保您的 arrow 安裝已啟用對 S3 和/或 GCS 的支援。對於大多數使用者來說,這預設為真,因為 CRAN 上託管的 Windows 和 macOS 二進位套件包含 S3 和 GCS 支援。您可以透過輔助函式檢查是否已啟用支援

如果這些函式返回 TRUE,則相關支援已啟用。

在某些情況下,您可能會發現您的系統未啟用支援。最常見的情況發生在 Linux 上從原始碼安裝 arrow 時。在這種情況下,S3 和 GCS 支援並不總是預設啟用,並且涉及額外的系統需求。有關如何解決此問題的詳細資訊,請參閱安裝文章

連線到雲端儲存空間

處理檔案系統的一種方法是建立 ?FileSystem 物件。?S3FileSystem 物件可以使用 s3_bucket() 函式建立,該函式會自動偵測儲存貯體的 AWS 區域。同樣地,?GcsFileSystem 物件可以使用 gs_bucket() 函式建立。產生的 FileSystem 將把路徑視為相對於儲存貯體路徑的路徑(因此,例如,在列出目錄時,您不需要在路徑前加上儲存貯體路徑)。

有了 FileSystem 物件,您可以使用 $path() 方法指向其中的特定檔案,並將結果傳遞給檔案讀取器和寫入器 (read_parquet()write_feather() 等)。

通常,使用者在真實世界分析中使用雲端儲存空間的原因是為了存取大型資料集。在資料集文章中討論了一個範例,但新使用者可能更喜歡在學習 arrow 雲端儲存空間介面如何運作時,使用更小的資料集。為此,本文中的範例依賴於一個多檔案 Parquet 資料集,該資料集儲存了透過 ggplot2 套件提供的 diamonds 資料副本,文件記錄在 help("diamonds", package = "ggplot2") 中。此資料集的雲端儲存空間版本由 5 個 Parquet 檔案組成,總大小不到 1MB。

diamonds 資料集託管在 S3 和 GCS 上,在一個名為 voltrondata-labs-datasets 的儲存貯體中。若要建立引用該儲存貯體的 S3FileSystem 物件,請使用以下命令

bucket <- s3_bucket("voltrondata-labs-datasets")

若要對 GCS 版本的資料執行此操作,命令如下

bucket <- gs_bucket("voltrondata-labs-datasets", anonymous = TRUE)

請注意,如果未設定憑證,則 GCS 需要 anonymous = TRUE

在此儲存貯體中,有一個名為 diamonds 的資料夾。我們可以呼叫 bucket$ls("diamonds") 來列出儲存在此資料夾中的檔案,或呼叫 bucket$ls("diamonds", recursive = TRUE) 來遞迴搜尋子資料夾。請注意,在 GCS 上,您應始終設定 recursive = TRUE,因為目錄通常不會出現在結果中。

以下是我們列出 GCS 儲存貯體中儲存的檔案時得到的結果

bucket$ls("diamonds", recursive = TRUE)
## [1] "diamonds/cut=Fair/part-0.parquet"     
## [2] "diamonds/cut=Good/part-0.parquet"     
## [3] "diamonds/cut=Ideal/part-0.parquet"    
## [4] "diamonds/cut=Premium/part-0.parquet"  
## [5] "diamonds/cut=Very Good/part-0.parquet"

這裡有 5 個 Parquet 檔案,每個檔案對應於 diamonds 資料集中的一個「cut」類別。我們可以透過呼叫 bucket$path() 來指定特定檔案的路徑

parquet_good <- bucket$path("diamonds/cut=Good/part-0.parquet")

我們可以使用 read_parquet() 從此路徑直接讀取到 R 中

diamonds_good <- read_parquet(parquet_good)
diamonds_good
## # A tibble: 4,906 × 9
##    carat color clarity depth table price     x     y     z
##    <dbl> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
##  1  0.23 E     VS1      56.9    65   327  4.05  4.07  2.31
##  2  0.31 J     SI2      63.3    58   335  4.34  4.35  2.75
##  3  0.3  J     SI1      64      55   339  4.25  4.28  2.73
##  4  0.3  J     SI1      63.4    54   351  4.23  4.29  2.7 
##  5  0.3  J     SI1      63.8    56   351  4.23  4.26  2.71
##  6  0.3  I     SI2      63.3    56   351  4.26  4.3   2.71
##  7  0.23 F     VS1      58.2    59   402  4.06  4.08  2.37
##  8  0.23 E     VS1      64.1    59   402  3.83  3.85  2.46
##  9  0.31 H     SI1      64      54   402  4.29  4.31  2.75
## 10  0.26 D     VS2      65.2    56   403  3.99  4.02  2.61
## # … with 4,896 more rows
## # ℹ Use `print(n = ...)` to see more rows

請注意,與檔案在本機時相比,這會讀取得更慢。

直接使用 URI 連線

在大多數使用情況下,在 arrow 中連線到雲端儲存空間最簡單和最自然的方式是使用 s3_bucket()gs_bucket() 返回的 FileSystem 物件,尤其是在需要多個檔案操作時。但是,在某些情況下,您可能想要透過指定 URI 直接下載檔案。arrow 允許這樣做,並且像 read_parquet()write_feather()open_dataset() 等函式都將接受指向 S3 或 GCS 上託管的雲端資源的 URI。S3 URI 的格式如下

s3://[access_key:secret_key@]bucket/path[?region=]

對於 GCS,URI 格式如下所示

gs://[access_key:secret_key@]bucket/path
gs://anonymous@bucket/path

例如,本文前面下載的儲存「good cut」diamonds 的 Parquet 檔案在 S3 和 CGS 上都可用。相關的 URI 如下

uri <- "s3://voltrondata-labs-datasets/diamonds/cut=Good/part-0.parquet"
uri <- "gs://anonymous@voltrondata-labs-datasets/diamonds/cut=Good/part-0.parquet"

請注意,對於公共儲存貯體,GCS 上需要「anonymous」。無論您使用哪個版本,您都可以將此 URI 傳遞給 read_parquet(),就像檔案儲存在本機一樣

df <- read_parquet(uri)

URI 接受查詢參數(? 後面的部分)中的其他選項,這些選項會向下傳遞以設定底層檔案系統。它們以 & 分隔。例如,

s3://voltrondata-labs-datasets/?endpoint_override=https%3A%2F%2Fstorage.googleapis.com&allow_bucket_creation=true

等同於

bucket <- S3FileSystem$create(
  endpoint_override="https://storage.googleapis.com",
  allow_bucket_creation=TRUE
)
bucket$path("voltrondata-labs-datasets/")

兩者都告訴 S3FileSystem 物件,它應該允許建立新的儲存貯體,並與 Google Storage 而不是 S3 通訊。後者之所以有效,是因為 GCS 實作了與 S3 相容的 API – 請參閱下方的模擬 S3 的檔案系統 – 但如果您想要更好地支援 GCS,則應參考 GcsFileSystem,但使用以 gs:// 開頭的 URI。

另請注意,URI 中的參數需要進行 百分比編碼,這就是為什麼 :// 寫為 %3A%2F%2F

對於 S3,只有以下選項可以包含在 URI 中作為查詢參數:regionschemeendpoint_overrideaccess_keysecret_keyallow_bucket_creationallow_bucket_deletion。對於 GCS,支援的參數為 schemeendpoint_overrideretry_limit_seconds

在 GCS 中,一個有用的選項是 retry_limit_seconds,它設定請求在返回錯誤之前可以花費重試的秒數。目前的預設值為 15 分鐘,因此在許多互動式上下文中,最好設定較低的值

gs://anonymous@voltrondata-labs-datasets/diamonds/?retry_limit_seconds=10

驗證

S3 驗證

若要存取私有 S3 儲存貯體,您通常需要兩個秘密參數:access_key(類似於使用者 ID)和 secret_key(類似於權杖或密碼)。有幾種選項可以傳遞這些憑證

  • 將它們包含在 URI 中,例如 s3://access_key:secret_key@bucket-name/path/to/file。如果您的密碼包含「/」等特殊字元,請務必 URL 編碼 您的密碼 (例如,URLencode("123/456", reserved = TRUE))。

  • 將它們作為 access_keysecret_key 傳遞給 S3FileSystem$create()s3_bucket()

  • 將它們設定為名為 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY 的環境變數。

  • 根據 AWS 文件,在 ~/.aws/credentials 檔案中定義它們。

  • 透過將 role_arn 識別碼傳遞給 S3FileSystem$create()s3_bucket(),使用 AccessRole 進行暫時存取。

GCS 驗證

使用 GCS 進行驗證的最簡單方法是執行 gcloud 命令來設定應用程式預設憑證

gcloud auth application-default login

若要手動設定憑證,您可以傳遞 access_tokenexpiration(用於使用在其他地方產生的臨時權杖),或傳遞 json_credentials(用於參考下載的憑證檔案)。

如果您尚未設定憑證,則要存取公共儲存貯體,您必須傳遞 anonymous = TRUE 或在 URI 中將 anonymous 作為使用者

bucket <- gs_bucket("voltrondata-labs-datasets", anonymous = TRUE)
fs <- GcsFileSystem$create(anonymous = TRUE)
df <- read_parquet("gs://anonymous@voltrondata-labs-datasets/diamonds/cut=Good/part-0.parquet")

使用 Proxy 伺服器

如果您需要使用 Proxy 伺服器連線到 S3 儲存貯體,您可以將 URI 以 http://user:password@host:port 的形式提供給 proxy_options。例如,可以像這樣使用在連接埠 1316 上執行的本機 Proxy 伺服器

bucket <- s3_bucket(
  bucket = "voltrondata-labs-datasets", 
  proxy_options = "https://127.0.0.1:1316"
)

模擬 S3 的檔案系統

S3FileSystem 機制使您能夠使用任何提供與 S3 相容介面的檔案系統。例如,MinIO 是一個模擬 S3 API 的物件儲存伺服器。如果您要在本機以預設設定執行 minio server,則可以使用如下所示的 S3FileSystem 與其連線

minio <- S3FileSystem$create(
  access_key = "minioadmin",
  secret_key = "minioadmin",
  scheme = "http",
  endpoint_override = "localhost:9000"
)

或者,作為 URI,它將是

s3://minioadmin:minioadmin@?scheme=http&endpoint_override=localhost%3A9000

(請注意 endpoint_override: 的 URL 逸出)。

在其他應用程式中,這對於在遠端 S3 儲存貯體上執行程式碼之前,在本機測試程式碼非常有用。

停用環境變數

如上所述,可以使用環境變數來設定存取權限。但是,如果您希望透過 URI 或其他方法傳遞連線詳細資訊,但同時也定義了現有的 AWS 環境變數,則這些變數可能會干擾您的工作階段。例如,您可能會看到類似以下的錯誤訊息

Error: IOError: When resolving region for bucket 'analysis': AWS Error [code 99]: curlCode: 6, Couldn't resolve host name 

您可以使用 Sys.unsetenv() 取消設定這些環境變數,例如

Sys.unsetenv("AWS_DEFAULT_REGION")
Sys.unsetenv("AWS_S3_ENDPOINT")

預設情況下,AWS SDK 嘗試檢索有關使用者組態的 Metadata,這在透過 URI 傳遞連線詳細資訊時(例如,在存取 MINIO 儲存貯體時)可能會導致衝突。若要停用 AWS 環境變數的使用,您可以將環境變數 AWS_EC2_METADATA_DISABLED 設定為 TRUE

Sys.setenv(AWS_EC2_METADATA_DISABLED = TRUE)

延伸閱讀