使用 Storage Write API (REST)
BigQuery Storage Write API (REST) 舊稱舊版 tabledata.insertAll 方法,可讓您將資料列串流至 BigQuery 資料表,而不必執行載入工作。BigQuery 確認寫入要求後,串流資料就會立即開放進行即時 GoogleSQL 分析。
如果是新專案,請使用 BigQuery Storage Write API (gRPC),享有更低的價格、僅限一次的傳遞語意,以及串流至 Apache Iceberg 代管資料表的功能。如要將現有專案從 Storage Write API (REST) 遷移至 Storage Write API (gRPC),請選取「default stream」(預設串流)。
事前準備
確認您具備目的地資料表所屬資料集的寫入權限。除非您使用範本資料表,否則該資料表在開始寫入資料之前就必須存在。如要進一步瞭解範本資料表,請參閱使用範本資料表自動建立資料表。
請查看串流資料的配額政策。
授予 Identity and Access Management (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-01-01 (Unix 紀元) 起算的秒數,或格式為 "YYYY-MM-DD HH:MM[:SS]" 的字串 |
傳送範圍資料
如果是 RANGE<T> 類型的欄位,請將 Storage Write API (REST) 中的資料格式設為包含 start 和 end 兩個欄位的 JSON 物件。如果 start 和 end 欄位的值遺漏或為空值,代表沒有邊界。這些欄位必須採用 T 類型的相同支援 JSON 格式,其中 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 資料欄的最終非 NULL 值,通常會在幾分鐘內完成。在極少數情況下,這項作業最多可能需要 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 的 BigQuery I/O 連接器 Java 版時,如要停用盡力去重功能,請使用 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指定來源資料表。 - 重複項目移除查詢會在資料表結構定義結尾,新增值為
1的row_number欄。查詢會使用 GoogleSQL 的SELECT * EXCEPT陳述式,從目的地資料表中排除row_number資料欄。#standardSQL前置字元會為這項查詢啟用 GoogleSQL。此外,您也可以選取特定的資料欄名稱來略過此資料欄。 - 如要在移除重複項目後查詢即時資料,您也可以使用重複項目移除查詢來對資料表建立資料檢視。請注意,檢視表的查詢費用是根據檢視表中選取的資料欄計算,因此掃描的位元組大小可能會很大。
串流至時間分區資料表
將資料串流至時間分區資料表時,每個分區都有串流緩衝區。執行載入、查詢或複製工作,並將 writeDisposition 屬性設為 WRITE_TRUNCATE 來覆寫分區時,系統會保留串流緩衝區。如要移除串流緩衝區,請在分區上呼叫 tables.get,確認串流緩衝區為空白。
擷取時間分區
串流至擷取時間分區資料表時,BigQuery 會根據目前的世界標準時間推論目的地分區。
新資料在串流緩衝區時,會暫時存放在 __UNPARTITIONED__ 分區。當未分區資料量足夠時,BigQuery 會將資料分區至正確的分區。不過,資料移出 __UNPARTITIONED__ 分區所需的時間並無服務水準協議。查詢可以透過使用其中一個虛擬資料欄 (_PARTITIONTIME 或 _PARTITIONDATE,視您偏好的資料類型而定),從 __UNPARTITIONED__ 分區中篩選出 NULL 值,從而排除串流緩衝區中的資料。
如果您將資料串流至每日分區資料表,可以提供分區修飾符做為 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 指令列工具,請在 insert 指令中加入 template_suffix 旗標。如果 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 的處理量較高、價格較低,且提供許多實用功能。