提升 BigQuery DataFrames 效能

BigQuery DataFrames 可讓您使用與 pandas 相容的 API,在 BigQuery 中分析及轉換資料。如要加快資料處理速度並提高成本效益,可以使用多種技巧來提升效能。

本文將說明下列最佳化效能的方法:

使用部分排序模式

BigQuery DataFrames 具有排序模式功能,可強制執行特定資料列順序,以進行視窗函式和聯結等作業。您可以將 ordering_mode 屬性設為 strict (稱為嚴格排序模式,這是預設值) 或 partial (稱為部分排序模式),藉此指定排序模式。使用 partial 設定可提高查詢效率。

部分排序模式與嚴格排序模式不同。嚴格排序模式會以特定順序排列所有資料列。這個總排序可讓 BigQuery DataFrame 更適合搭配 pandas 使用,讓您使用 DataFrame.iloc 屬性依序存取資料列。不過,總排序及其預設的循序索引會導致欄或列的篩選器無法減少掃描的資料量。除非您將這些篩選器套用為 read_gbqread_gbq_table 函式的參數,否則系統會防止這類情況發生。如要排序 DataFrame 中的所有資料列,BigQuery DataFrames 會建立所有資料列的雜湊。這項作業可能會導致系統完整掃描資料,並忽略資料列和資料欄篩選器。

部分排序模式會停止為所有資料列建立總排序,並關閉需要總排序的功能,例如 DataFrame.iloc 屬性。部分排序模式也會將 DefaultIndexKind 類別設為空值索引,而非連續索引。

使用部分排序模式篩選 DataFrame 物件時,BigQuery DataFrames 不會計算連續索引中缺少的資料列。部分排序模式也不會根據索引自動合併資料。這些方法可提高查詢效率。 不過,無論您使用預設的嚴格排序模式或部分排序模式,BigQuery DataFrames API 的運作方式都與熟悉的 pandas API 類似。

無論是部分或嚴格排序模式,您都須支付所用 BigQuery 資源的費用。不過,使用部分排序模式處理大型叢集和分區資料表時,可以降低成本。這是因為叢集和分區欄的列篩選條件會減少處理的資料量。

啟用部分排序模式

如要使用部分排序,請在對 BigQuery DataFrames 執行任何其他作業前,將 ordering_mode 屬性設為 partial,如下列程式碼範例所示:

import bigframes.pandas as bpd

bpd.options.bigquery.ordering_mode = "partial"

部分排序模式缺少連續索引,因此可防止不相關的 BigQuery DataFrame 物件隱含聯結。您必須明確呼叫 DataFrame.merge 方法,才能聯結衍生自不同資料表運算式的兩個 BigQuery DataFrame 物件。

Series.unique()」和「Series.drop_duplicates()」功能不支援部分排序模式。請改用 groupby 方法尋找不重複的值,如下列範例所示:

# Avoid order dependency by using groupby instead of drop_duplicates.
unique_col = df.groupby(["column"], as_index=False).size().drop(columns="size")

在部分排序模式下,每次執行 DataFrame.head(n)Series.head(n) 函式時,輸出內容可能不盡相同。如要下載隨機的小型資料樣本,請使用 DataFrame.peek()Series.peek() 方法

如需使用 ordering_mode = "partial" 屬性的詳細教學課程,請參閱「使用 BigQuery DataFrames 分析 PyPI 的套件下載次數」。

疑難排解

由於處於部分排序模式的 BigQuery DataFrames 有時會缺少排序或索引,因此使用某些與 pandas 相容的方法時,可能會遇到下列問題。

需要訂單錯誤

部分功能 (例如 DataFrame.head()DataFrame.iloc 函式) 需要排序。如需必須排序的功能清單,請參閱「支援的 pandas API」中的「需要排序」欄。

如果物件沒有排序,作業會失敗,並顯示類似以下的 OrderRequiredError 訊息:OrderRequiredError: Op iloc requires an ordering. Use .sort_values or .sort_index to provide an ordering.

如錯誤訊息所述,您可以使用 DataFrame.sort_values() 方法提供排序方式,依一或多個資料欄排序。其他方法 (例如 DataFrame.groupby()) 會根據分組依據鍵隱含提供總排序。

如果排序並非所有資料列的完全穩定總排序,後續作業可能會顯示類似以下的 AmbiguousWindowWarning 訊息:AmbiguousWindowWarning: Window ordering may be ambiguous, this can cause unstable results.

如果您的工作可以處理結果不一定相同的情況,或是可以手動檢查排序是否為全序,您可以透過下列方式篩除 AmbiguousWindowWarning 訊息:

import warnings

import bigframes.exceptions

warnings.simplefilter(
    "ignore", category=bigframes.exceptions.AmbiguousWindowWarning
)

空值索引錯誤

部分功能 (例如 DataFrame.unstack()Series.interpolate() 屬性) 需要索引。如需索引的必要功能清單,請參閱「支援的 pandas API」中的「需要索引」欄。

使用需要部分排序模式索引的作業時,作業會引發類似下列內容的 NullIndexError 訊息: NullIndexError: DataFrame cannot perform interpolate as it has no index. Set an index using set_index.

如錯誤訊息所述,您可以使用 DataFrame.set_index() 方法提供索引,依一或多個資料欄排序。其他方法 (例如 DataFrame.groupby()) 會根據群組依據鍵隱含提供索引,除非設定 as_index=False 參數。

在昂貴的作業後快取結果

BigQuery DataFrames 會在本機儲存作業,並延後執行查詢,直到符合特定條件為止。這可能會導致不同查詢重複執行相同作業。

為避免重複執行耗費資源的作業,請使用 cache() 方法儲存中間結果,如以下範例所示:

# Assume you have 3 large dataframes "users", "group" and "transactions"

# Expensive join operations
final_df = users.join(groups).join(transactions)
final_df.cache()
# Subsequent derived results will reuse the cached join
print(final_df.peek())
print(len(final_df[final_df["completed"]]))
print(final_df.groupby("group_id")["amount"].mean().peek(30))

這個方法會建立臨時 BigQuery 資料表來儲存結果。系統會向您收取 BigQuery 中這個臨時資料表的儲存費用。

使用 peek() 方法預覽資料

BigQuery DataFrames 提供兩種 API 方法來預覽資料:

  • peek(n) 會傳回 n 列資料,其中 n 是列數。
  • head(n) 會根據內容傳回前 n 個資料列,其中 n 是資料列數。

只有在資料順序很重要時才使用 head() 方法,例如要取得資料欄中五個最大值時。在其他情況下,請使用 peek() 方法,更有效率地擷取資料,如下列程式碼範例所示:

import bigframes.pandas as bpd

# Read the "Penguins" table into a dataframe
df = bpd.read_gbq("bigquery-public-data.ml_datasets.penguins")

# Preview 3 random rows
df.peek(3)

使用部分排序模式時,您也可以使用 peek() 方法下載隨機的小型資料樣本。

延後 repr() 資料擷取作業

您可以在 BigQuery DataFrames 中使用 repr() 方法,搭配筆記本或 IDE 偵錯工具。這項呼叫會觸發 head() 呼叫,以擷取實際資料。這項擷取作業可能會拖慢疊代編碼和偵錯程序,而且還會產生費用。

如要防止 repr() 方法擷取資料,請將 repr_mode 屬性設為 "deferred",如以下範例所示:

import bigframes.pandas as bpd

bpd.options.display.repr_mode = "deferred"

在延遲模式中,您只能透過明確的 peek()head() 呼叫預覽資料

後續步驟