使用 Storage Write API (REST)
本文說明如何使用 BigQuery Storage Write API (REST) 將資料串流至 BigQuery。這個 API 先前稱為舊版 tabledata.insertAll 方法。
新專案建議使用 BigQuery Storage Write API (gRPC),而不要使用 Storage Write API (REST)。Storage Write API (gRPC) 的定價較低,且功能更完善,包括單次傳送語意,以及將資料串流至 Apache Iceberg 受管理資料表。如果您要將現有專案從 Storage Write API (REST) 遷移至 Storage Write API (gRPC),建議選取預設串流。Storage Write API (REST) 仍完全支援。
事前準備
確認您具備目的地資料表所屬資料集的寫入權限。除非您使用範本資料表,否則該資料表在開始寫入資料之前就必須存在。如要進一步瞭解範本資料表,請參閱使用範本資料表自動建立資料表。
請參閱串流資料的配額政策。
授予身分與存取權管理 (IAM) 角色,讓使用者擁有執行本文件各項工作所需的權限。
免付費方案不支援串流功能。如果不啟用計費功能,當您嘗試進行資料串流作業時,系統會顯示下列錯誤訊息:BigQuery: Streaming insert is not allowed in the free tier.
所需權限
如要將資料串流至 BigQuery,您需要下列 IAM 權限:
bigquery.tables.updateData(可將資料插入表格)bigquery.tables.get(可取得表格中繼資料)bigquery.datasets.get(可取得資料集的中繼資料)bigquery.tables.create(如果您使用範本資料表自動建立資料表,則為必要目錄)
下列每個預先定義的 IAM 角色都包含將資料串流至 BigQuery 所需的權限:
roles/bigquery.dataEditorroles/bigquery.dataOwnerroles/bigquery.admin
如要進一步瞭解 BigQuery 中的 IAM 角色和權限,請參閱預先定義的角色和權限一文。
將資料串流至 BigQuery
C#
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 C# 設定說明操作。詳情請參閱 BigQuery C# API 參考說明文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證作業」。
Go
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 Go 設定說明操作。詳情請參閱 BigQuery Go API 參考說明文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證作業」。
Java
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 Java 設定說明操作。詳情請參閱 BigQuery Java API 參考說明文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證作業」。
Node.js
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 Node.js 設定說明操作。詳情請參閱 BigQuery Node.js API 參考說明文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證作業」。
PHP
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 PHP 設定說明操作。詳情請參閱 BigQuery PHP API 參考說明文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證作業」。
Python
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 Python 設定說明操作。詳情請參閱 BigQuery Python API 參考說明文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證作業」。
Ruby
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 Ruby 設定說明操作。詳情請參閱 BigQuery Ruby API 參考說明文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證作業」。
插入資料列時,不需要填入 insertID 欄位。
以下範例說明如何在串流時,避免為每個資料列傳送 insertID。
Java
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 Java 設定說明操作。詳情請參閱 BigQuery Java API 參考說明文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證作業」。
Python
在試用這個範例之前,請先按照「使用用戶端程式庫的 BigQuery 快速入門導覽課程」中的 Python 設定說明操作。詳情請參閱 BigQuery Python API 參考說明文件。
如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證作業」。
傳送日期和時間資料
如果是日期和時間欄位,請在 Storage Write API (REST) 中將資料格式設為:
| 類型 | 格式 |
|---|---|
DATE |
格式為 "YYYY-MM-DD" 的字串 |
DATETIME |
格式為 "YYYY-MM-DD [HH:MM:SS]" 的字串 |
TIME |
格式為 "HH:MM:SS" 的字串 |
TIMESTAMP |
自 1970 年 1 月 1 日 (Unix Epoch) 起算的秒數,或 "YYYY-MM-DD HH:MM[:SS]" 形式的字串 |
傳送範圍資料
如為 RANGE<T> 類型的欄位,請在 Storage Write API (REST) 中將資料格式設為含有 start 和 end 兩個欄位的 JSON 物件。start 和 end 欄位中遺漏或 NULL 值代表無界限。
這些欄位必須採用相同的支援 JSON 格式,也就是 T 類型,其中 T 可以是 DATE、DATETIME 和 TIMESTAMP。
在下列範例中,f_range_date 欄位代表表格中的 RANGE<DATE> 資料欄。使用 Storage Write API (REST) 將資料列插入這個資料欄。
{
"f_range_date": {
"start": "1970-01-02",
"end": null
}
}
串流資料可用性
BigQuery 成功確認 Storage Write API (REST) 要求後,您就能立即使用 GoogleSQL 查詢,即時分析資料。如果您使用隨選運算價格,查詢串流緩衝區中的資料時,系統不會針對串流緩衝區處理的位元組收費。如果採用容量型定價,預留項目會耗用運算單元,在串流緩衝區中處理資料。
最近串流至擷取時間分區資料表的資料列,_PARTITIONTIME 虛擬資料欄暫時會顯示 NULL 值。對於這類資料列,BigQuery 會在背景中指派 PARTITIONTIME 資料欄的最終非空值,通常會在幾分鐘內完成。在極少數情況下,這項作業最多可能需要 90 分鐘。
最近串流的資料列可能無法複製到表格,通常會持續幾分鐘。在極少數情況下,這項作業最多可能需要 90 分鐘。如要查看表格副本是否有資料,請檢查 tables.get 回應中名為 streamingBuffer 的區段。如果沒有「streamingBuffer」部分,表示資料可供複製。
您也可以使用 streamingBuffer.oldestEntryTime 欄位,找出串流緩衝區中記錄的年齡。
盡可能去除重複資料
插入資料列時,如果提供 insertId,BigQuery 會使用這個 ID,盡可能在最多一分鐘內進行重複資料刪除作業。也就是說,如果您在該時間範圍內,將相同資料列和相同 insertId 多次串流至同一個資料表,BigQuery 可能會將該資料列的多個例項重複資料刪除,只保留其中一個例項。
系統會預期具有相同 insertId 的資料列也相同。如果兩列的 insertId 相同,BigQuery 會保留哪一列則不確定。
一般來說,重複資料刪除功能適用於分散式系統中的重試情境,在某些錯誤情況下 (例如系統與 BigQuery 之間的網路錯誤,或 BigQuery 內部錯誤),無法判斷串流資料即時插入作業的狀態。如果重試插入作業,請對同一組資料列使用相同的 insertId,以便 BigQuery 嘗試移除重複資料。詳情請參閱「排解串流插入問題」。
BigQuery 提供的重複資料刪除功能是盡力而為,不應做為確保資料中沒有重複項目的機制。此外,為確保資料的可靠性和可用性,BigQuery 可能隨時降低盡力去重複作業的品質。
如果對資料重複刪除有嚴格要求,可以改用支援交易的 Google Cloud Datastore 服務。
停用盡可能清除重複的功能
如要停用盡量去重複功能,請勿填入插入的每一列的 insertId 欄位。建議使用這個方法插入資料。
Apache Beam 和 Dataflow
如要在使用 Apache Beam 的 Java BigQuery I/O 連接器時停用盡量去重複功能,請使用 ignoreInsertIds() 方法。
手動移除重複內容
為確保串流完成後沒有重複的資料列,請使用下列手動程序:
- 在資料表結構定義中新增
insertId做為資料欄,並在每列資料中加入insertId值。 - 在串流作業停止後,執行下列查詢以檢查是否有重複內容:
如果結果大於 1,表示有重複項目。#standardSQL SELECT MAX(count) FROM( SELECT ID_COLUMN, count(*) as count FROM `TABLE_NAME` GROUP BY ID_COLUMN)
- 如要移除重複項目,請執行下列查詢。指定目的地資料表、允許大型結果,並停用結果扁平化。
#standardSQL SELECT * EXCEPT(row_number) FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY ID_COLUMN) row_number FROM `TABLE_NAME`) WHERE row_number = 1
移除重複項目的查詢注意事項:
- 針對重複項目移除查詢,較安全的策略是指定新表格。
或者,您也可以使用寫入處置
WRITE_TRUNCATE指定來源表格。 - 重複項目移除查詢會在資料表結構定義結尾新增
row_number欄,並將值設為1。這項查詢會使用 GoogleSQL 的SELECT * EXCEPT陳述式,從目的地資料表排除row_number資料欄。#standardSQL前置字元可為這項查詢啟用 GoogleSQL。此外,您也可以選取特定的資料欄名稱來略過此資料欄。 - 如要在移除重複項目後查詢即時資料,您也可以使用重複項目移除查詢來對資料表建立資料檢視。請注意,系統會根據您在檢視畫面中選取的資料欄,計算檢視畫面查詢費用,這可能會導致掃描的位元組大小過大。
將資料串流至時間分區資料表
將資料串流至時間分區資料表時,每個分區都有串流緩衝區。當您執行載入、查詢或複製作業,並將 writeDisposition 屬性設為 WRITE_TRUNCATE,以覆寫分割區時,系統會保留串流緩衝區。如要移除串流緩衝區,請在分割區上呼叫 tables.get,確認串流緩衝區為空白。
擷取時間分區
將資料串流至擷取時間分區資料表時,BigQuery 會根據目前的 UTC 時間推斷目的地分區。
新資料抵達時,會暫時放置在 __UNPARTITIONED__ 分區的串流緩衝區中。當未分區資料量足夠時,BigQuery 會將資料分區到正確的分區。不過,資料移出 __UNPARTITIONED__ 分割區所需的時間沒有服務水準協議。查詢可以透過篩除__UNPARTITIONED__分區中的 NULL 值,從查詢中排除串流緩衝區中的資料,方法是使用其中一個虛擬資料欄 (_PARTITIONTIME 或 _PARTITIONDATE,視您偏好的資料類型而定)。
如果將資料串流至每日分區資料表,您可以透過 Storage Write API (REST) 提供分區修飾符,覆寫日期推論結果。在 tableId 參數中加入裝飾器。舉例來說,您可以使用分區修飾符,將資料串流至 table1 資料表 2021-03-01 對應的分區:
table1$20210301
使用分區修飾符以串流方式傳輸資料時,可以根據目前的世界標準時間,以串流方式將資料傳輸至過去 31 天和未來 16 天之間 (相對於目前日期) 的分區。如要針對前述允許範圍外的日期寫入分區,請改用載入或查詢工作,如「附加並覆寫分區資料表資料」一文所述。
使用分區裝飾器串流處理資料時,僅支援每日分區資料表。不支援按小時、月或年分區的資料表。
如要進行測試,可以使用 bq 指令列工具 bq insert CLI 指令。舉例來說,下列指令會將單一資料列串流至 2017 年 1 月 1 日 ($20170101) 的分區,並載入名為 mydataset.mytable 的分區資料表:
echo '{"a":1, "b":2}' | bq insert 'mydataset.mytable$20170101'
按時間單位資料欄分區
您可以將資料串流至以 DATE、DATETIME 或 TIMESTAMP 欄分區的資料表,時間範圍為過去 10 年到未來 1 年。超出這個範圍的資料會遭到拒絕。
資料串流時,系統會先將資料放入 __UNPARTITIONED__ 分區。當未分區的資料量足夠時,BigQuery 會自動重新分區資料,並將資料放入適當的分區。不過,資料移出 __UNPARTITIONED__ 分割區所需的時間並無服務水準協議。
- 注意:每日分區的處理方式與每小時、每月和每年分區不同。只有超出日期範圍 (過去 7 天至未來 3 天) 的資料會擷取至 UNPARTITIONED 分區,等待重新分區。另一方面,如果是以小時為單位的分區資料表,資料一律會擷取至 UNPARTITIONED 分區,然後再重新分區。
使用範本表格自動建立表格
範本資料表提供機制,可將邏輯資料表分割成多個較小的資料表,以建立較小的資料集 (例如依使用者 ID)。範本表格有許多限制,詳情請參閱本節後續內容。建議改用分區資料表和分群資料表來達成這個行為。
如要透過 BigQuery API 使用範本資料表,請在 Storage Write API (REST) 要求中加入 templateSuffix 參數。如果是 bq 指令列工具,請將 template_suffix 標記新增至 insert 指令。如果 BigQuery 偵測到 templateSuffix 參數或 template_suffix 旗標,就會將目標資料表視為基本範本。這項作業會建立新資料表,與目標資料表共用相同結構定義,且名稱包含指定的後置字串:
<targeted_table_name> + <templateSuffix>
只要使用範本資料表,您就可以省去個別建立資料表以及為每個資料表指定結構定義的負擔。您只需要建立一個範本,並提供不同的後置字元,BigQuery 就能為您建立新資料表。BigQuery 會將資料表放在同一個專案和資料集中。
使用範本表格建立的表格通常會在幾秒內提供。 在極少數情況下,可能需要較長時間才能使用。
變更範本資料表結構定義
如果您變更範本資料表結構定義,後續生成的所有資料表都會使用更新後的結構定義。先前產生的資料表不會受到影響,除非現有資料表仍有串流緩衝區。
如果現有資料表仍有串流緩衝區,以回溯相容的方式修改範本資料表結構定義時,系統也會更新這些主動串流產生的資料表結構定義。不過,如果以不回溯相容的方式修改範本資料表結構定義,使用舊結構定義的任何緩衝資料都會遺失。此外,您也無法將新資料串流至使用舊架構 (但現在不相容) 的現有產生資料表。
變更範本資料表結構定義後,請等待變更傳播完成,再嘗試插入新資料或查詢產生的資料表。插入新欄位的要求應該會在幾分鐘內成功,而查詢新欄位的嘗試可能需要最多 90 分鐘。
如要變更產生的資料表結構定義,請等到透過範本資料表串流傳輸資料停止,且 tables.get() 回應中沒有產生的資料表串流統計資料部分,再變更結構定義。這表示資料表上沒有緩衝資料。
分區資料表和分群資料表不受上述限制影響,建議使用這類資料表。
範本資料表詳細資料
- 範本後置值
templateSuffix(或--template_suffix) 值只能包含英文字母 (a-z、A-Z)、數字 (0-9) 或底線 (_)。資料表名稱和資料表尾碼的總長度上限為 1024 個字元。- 配額
範本表格受串流配額限制。您的專案每秒最多可使用範本表格建立 10 個表格,與
tables.insertAPI 類似。這項配額僅適用於建立中的資料表,不適用於修改中的資料表。如果應用程式每秒需要建立超過 10 個資料表,建議使用叢集資料表。舉例來說,您可以將高基數資料表 ID 放入單一叢集資料表的主鍵欄。
- 存留時間 (TTL)
已產生的資料表會沿用資料集的到期時間。與一般串流資料一樣,產生的表格無法立即複製。
- 簡化
只有在目的地資料表的參照方式一致時,系統才會執行簡化功能。 舉例來說,如果您同時使用範本資料表和一般 Storage Write API (REST) 指令,將資料串流至產生的資料表,系統不會對範本資料表和一般 Storage Write API (REST) 指令插入的資料列進行重複資料刪除作業。
- 瀏覽次數
範本資料表和產生的資料表不應是檢視畫面。
排解串流插入問題
以下各節將說明如何排解使用 Storage Write API (REST) 將資料串流至 BigQuery 時發生的錯誤。如要進一步瞭解如何解決串流資料即時插入的配額錯誤,請參閱「串流資料即時插入配額錯誤」。
失敗的 HTTP 回應代碼
如果收到失敗的 HTTP 回應代碼 (例如網路錯誤),就無法判斷串流資料即時插入作業是否成功。如果嘗試重新傳送要求,資料表中可能會出現重複的資料列。為避免表格重複,請在傳送要求時設定 insertId 屬性。BigQuery 會使用 insertId 屬性進行重複資料刪除作業。
如果收到權限錯誤、無效的表格名稱錯誤或超出配額錯誤,系統就不會插入任何資料列,且整個要求都會失敗。
成功的 HTTP 回應代碼
即使收到成功 HTTP 回應代碼,您仍須檢查回應的 insertErrors 屬性,判斷資料列插入作業是否成功,因為 BigQuery 可能只會部分成功插入資料列。您可能會遇到下列其中一種情況:
- 所有資料列都已成功插入:如果
insertErrors屬性是空白清單,表示所有資料列都已成功插入。 - 部分資料列插入成功:除非任何資料列發生結構定義不符的情況,否則系統不會插入
insertErrors屬性中指出的資料列,但會成功插入所有其他資料列。errors屬性包含每個失敗資料列的詳細資訊。index屬性會針對發生該錯誤的要求,提供從 0 開始的資料列索引。 - 未成功插入任何資料列:如果 BigQuery 在要求中發現個別資料列的結構定義不符,系統不會插入任何資料列,且每個資料列都會傳回
insertErrors項目,即使資料列的結構定義相符也一樣。如果資料列沒有結構定義不符的問題,reason屬性會設為stopped,您可以照常重新傳送。如果資料列失敗,則會包含結構定義不符的詳細資訊。如要瞭解各 BigQuery 資料類型支援的通訊協定緩衝區類型,請參閱「支援的通訊協定緩衝區和 Arrow 資料類型」。
串流資料插入的中繼資料錯誤
由於 BigQuery 串流 API 的設計目的是為了提高插入率,因此與串流系統互動時,基礎資料表的中繼資料修改作業最終會保持一致。通常中繼資料變更會在幾分鐘內傳播,但在此期間,API 回應可能會反映資料表的不一致狀態。
這類情況包括:
- 結構定義變更:如果資料表最近收到串流插入內容,修改該資料表的結構定義可能會導致回應出現結構定義不符錯誤,因為串流系統可能不會立即偵測到結構定義變更。
- 建立或刪除資料表:串流至不存在的資料表會傳回
notFound回應的變體。後續串流插入內容可能無法立即辨識回覆中建立的表格。同樣地,刪除或重新建立資料表可能會導致串流插入作業在一段時間內傳送至舊資料表。新表格中可能不會顯示串流插入內容。 - 資料表截斷:截斷資料表資料 (使用
writeDisposition值為WRITE_TRUNCATE的查詢工作) 也可能導致在一致性期間內插入的後續資料遭到捨棄。
資料遺失或無法使用
串流插入作業會暫時存放在寫入最佳化儲存空間中,這類儲存空間的可用性特徵與代管儲存空間不同。BigQuery 中的某些作業不會與寫入最佳化儲存空間互動,例如表格複製作業和 tabledata.list 等 API 方法。目的地資料表或輸出內容中沒有最近的串流資料。
串流資料即時插入配額錯誤
本節提供相關提示,協助排解將資料串流至 BigQuery 時發生的配額錯誤。
在特定區域中,如果您並未在每個資料列的 insertId 欄位中填入資料,則串流資料插入會含有較高的配額。如要進一步瞭解串流資料插入的配額,請參閱串流資料插入。BigQuery 串流的配額相關錯誤取決於 insertId 是否存在。
錯誤訊息
如果 insertId 欄位為空白,則可能會發生下列配額錯誤:
| 配額限制 | 錯誤訊息 |
|---|---|
| 每項專案每秒位元組數 | 在區域 REGION 中專案 PROJECT_ID gaia_id 為 GAIA_ID 的實體超過每秒插入位元組數的配額。 |
如果在 insertId 欄位填入資料,則可能會發生下列配額錯誤:
| 配額限制 | 錯誤訊息 |
|---|---|
| 每項專案每秒資料列數量 | 您在 REGION 的專案 PROJECT_ID 超過每秒串流資料插入資料列的配額。 |
| 每個資料表每秒資料列數量 | 您的資料表:TABLE_ID超出每秒串流資料即時插入列的配額。 |
| 每個資料表每秒位元組數 | 您的資料表:TABLE_ID 超出每秒串流資料即時插入位元組的配額。 |
insertId 欄位的用途是簡化插入的資料列。如果同一個 insertId 的多個插入項目均於幾分鐘之內抵達,則 BigQuery 會寫入單一版本的記錄。但是,我們無法保證系統會自動刪除重複的內容。為了達到最大的串流總處理量,建議您不要加入 insertId,改成手動刪除重複內容。詳情請參閱確保資料一致性一文。
診斷
使用 STREAMING_TIMELINE_BY_* 檢視表來分析串流流量。這些檢視畫面會彙整以一分鐘為間隔的串流統計資料,並依error_code分組。配額錯誤會顯示在 error_code 等於 RATE_LIMIT_EXCEEDED 或 QUOTA_EXCEEDED 的結果中。
根據已達到的特定配額上限查看 total_rows 或 total_input_bytes。如果錯誤是表格層級配額,請依 table_id 篩選。
舉例來說,下列查詢會顯示每分鐘擷取的位元組總數,以及配額錯誤總數:
SELECT start_timestamp, error_code, SUM(total_input_bytes) as sum_input_bytes, SUM(IF(error_code IN ('QUOTA_EXCEEDED', 'RATE_LIMIT_EXCEEDED'), total_requests, 0)) AS quota_error FROM `region-REGION_NAME`.INFORMATION_SCHEMA.STREAMING_TIMELINE_BY_PROJECT WHERE start_timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP, INTERVAL 1 DAY) GROUP BY start_timestamp, error_code ORDER BY 1 DESC
解析度
如要解決這項配額錯誤,請按照下列步驟操作:
如果您使用
insertId欄位進行重複資料刪除,且專案位於支援較高串流配額的區域,建議您移除insertId欄位。這個解決方案可能需要額外步驟,才能手動移除重複資料。詳情請參閱手動移除重複內容。如果您並非使用
insertId,或是無法加以移除,請監控 24 小時內的串流流量,並分析配額錯誤:如果看到的大多是
RATE_LIMIT_EXCEEDED錯誤,而非QUOTA_EXCEEDED錯誤,且整體流量低於配額的 80%,這些錯誤可能表示流量暫時暴增。您可以在每次重試之間使用指數輪詢重試作業,以處理這些錯誤。如果您使用 Dataflow 工作插入資料,請考慮使用載入工作,而非串流插入。詳情請參閱「設定插入方法」。如果您使用 Dataflow 和自訂 I/O 連接器,建議改用內建的 I/O 連接器。詳情請參閱「自訂 I/O 模式」。
如果看到
QUOTA_EXCEEDED錯誤,或整體流量持續超過配額的 80%,請提交配額增加要求。詳情請參閱「要求調整配額」。您也可以考慮使用較新的 Storage Write API 取代串流插入,這項 API 的輸送量較高、價格較低,而且提供許多實用功能。