1. 總覽
通過程式碼審查的 SQL 錯誤大多是彙整錯誤。表格中的數字正確無誤,但聯結會複製該數字,導致總數有誤。
BigQuery Graph 可讓您以屬性圖譜的形式,描述資料表之間的連結,然後查詢這些連結。圖表指標會在說明中加入另一個項目:匯總本身。您可以在擁有該數字的節點上宣告 MEASURE(SUM(streams)),而讀取圖表的每個查詢都會在正確的粒度取得正確的總計,不需要 GROUP BY 技巧,也不需要有人記得 CTE。
在本程式碼研究室中,您將建構五個資料表的音樂目錄,並在目錄中加入一個指標,然後觀察同一個問題傳回的兩個不同答案:126 億 (使用 SUM) 和 51 億 (使用 AGG)。這個間隙就是目錄的形狀,如果歌曲出現在四個播放清單中,圖表就會有四列,而 SUM 會新增所有四列。然後瞭解第二個句子正確的原因。

輸入內容的位置
本實驗室會使用兩個地點,順序如下:
媒介 | 你在那裡做什麼 | |
1 | Cloud Shell 終端機 | 少數指令,僅限「設定」步驟 |
2 | BigQuery 控制台 | 其他所有操作:將查詢貼到查詢編輯器、點按圖表建模工具、與代理交談 |
每項指令都會加上標記,方便你辨識指令的意義:
- 👉💻 Cloud Shell:在 Cloud Shell 終端機中輸入這個指令。
- 👉📋 查詢編輯器:將這段程式碼貼到 BigQuery 查詢編輯器,然後按一下「執行」。
- 👉🌐 控制台 - 在 BigQuery 控制台中隨意點選,除非步驟中另有說明,否則不需要輸入任何內容。
- 👀 - 查看結果。
課程內容
- 如何在節點資料表上宣告指標 - 在視覺化圖表模型工具或 SQL 中
GRAPH_EXPAND如何將圖譜攤平為一個寬資料表- 為什麼
AGG是唯一可以讀取指標的函式,以及其他嘗試會傳回的內容 - 指標支援的六個匯總,以及如何對這些匯總執行算術運算
- 某項指標如何回答分組方式不同的問題,且沒有任何變更
- 選用:瞭解 GQL 和「圖表」分頁如何回答總計無法回答的問題,以及 BigQuery 資料代理程式如何使用您的指標,而不需事先得知這些指標
軟硬體需求
- 具備可啟用帳單的 Google 帳戶和瀏覽器。您不需要預先建立 Google Cloud 專案,設定程序會為您建立專案。
- 僅限選用的對話步驟:啟用 Gemini Data Analytics API,並具備 Gemini Data Analytics 資料代理建立者角色。
你不需要在電腦上安裝任何軟體。所有作業都會在 Cloud Shell 和 BigQuery 控制台中執行。
產品狀態和費用
BigQuery Graph 現已正式發布。圖表指標、視覺化圖表模型工具、圖表視覺化,以及將圖表做為資料代理程式知識來源的功能,目前處於預先發布版,並受到《正式發布前產品條款》規範。
GRAPH_EXPAND 和 AGG 均採用以量計價模式。根據文件,GQL 查詢 (選用路徑步驟) 需要使用 Enterprise 或 Enterprise Plus 版本的預留項目,因此這個步驟是選用步驟。
資料集大小為幾 KB。以量計價的最低費用為 10 MB,因此整個程式碼研究室的費用不到一美分。
2. 設定
這是唯一需要使用 Cloud Shell 的步驟。這個指令會建立專案、啟用帳單功能,並建構原始資料表。之後您可以在 BigQuery 控制台中執行圖表、指標和所有查詢。
本實驗室無法提供已啟用計費功能的 Google Cloud 專案。步驟 1 會提供可支付費用的帳戶,步驟 4 則會將該帳戶轉換為專案。請按照這個順序操作,因為步驟 4 之後的每個步驟都會讀取步驟 4 建立的專案。
1. 取得含帳單的帳戶 (約 1 分鐘)
👉🌐 請務必先完成這項操作。使用已啟用帳單功能的 Google 帳戶登入。任何這類帳戶都可以。如果沒有,請開始免費試用,這樣您就會有帳單帳戶,這也是步驟 4 的必要條件。
2 · 開啟 Cloud Shell (約 1 分鐘)
👉🌐 控制台:點選 Google Cloud 控制台頂端的「啟用 Cloud Shell」,即標題中的終端機形狀圖示。頁面底部會開啟終端機。

👉🌐 控制台:如果系統在今天任何時間提示您授權,請點選「授權」繼續操作。
👉💻 Cloud Shell - 檢查 Cloud Shell 登入的帳戶:
gcloud auth list
👀 預期自己的帳戶會標示 *,且必須與步驟 1 中登入的帳戶相同。如果不是,請執行 gcloud auth login 並選擇正確的項目。
3. 取得實驗室 (約 1 分鐘)
👉💻 Cloud Shell - 複製存放區:
cd ~
rm -rf ~/bq-graph-measures-lab
git clone https://github.com/cuppibla/bq-graph-measures-lab.git
cd ~/bq-graph-measures-lab
4 · 建立專案 (約 2 分鐘)
👉💻 Cloud Shell:一個指令碼會找出您的帳單帳戶、在該帳戶中建立專案,並將 Cloud Shell 指向該專案:
cd ~/bq-graph-measures-lab
./setup_project.sh
👀 系統會為所選帳單帳戶和建立的專案各產生一個 ✓✓,並在結尾加上:
Project ready: bq-graph-4271 Next: ./setup.sh
bq-graph-4271 是您的專案 ID,您的專案 ID 會有不同的數字。當中會發生四件事:
帳單 | 如果有的話,會採用最新的 | |
project | 建立 | |
選取 | 將 ID 寫入 | |
等待 | 輪詢,直到新專案實際獲准放送為止,最多兩分鐘 | |
🌐 控制台中現在有相同的專案,其 ID 位於資訊主頁的「專案資訊」資訊卡中:

5 · 建立資料集 (~3 分鐘)
👉💻 Cloud Shell - 另一個指令碼會建構表格:
cd ~/bq-graph-measures-lab
./setup.sh
指令碼執行時會列印每個步驟。這段程式碼會依序執行下列作業:
project | 從 | |
API | 啟用 | |
資料集 | 在美國多區域建立 | |
檢查 | 計算每個資料表中的資料列,如果任何計數有誤,就會停止 | |
👀 預期:
BigQuery Graph Measures · setup ✓ project: bq-graph-4271 ✓ BigQuery API enabled Creating dataset music (US) and five tables... ✓ music.Labels 2 rows ✓ music.Artists 3 rows ✓ music.Songs 5 rows ✓ music.Playlists 4 rows ✓ music.PlaylistEntries 10 rows 🎉 ready — open BigQuery Studio: https://console.cloud.google.com/bigquery?project=bq-graph-4271
您已完成 Cloud Shell 的操作。你可以關閉這個視窗。
6 · 開啟 BigQuery 和查詢編輯器
👉🌐 控制台:按一下輸出內容結尾的連結,或從導覽選單開啟 BigQuery。在左側的「Explorer」窗格中展開專案:一個包含五個資料表的 music 資料集。

👉🌐 控制台:在 BigQuery Studio 頂端的「新建」列中,按一下「SQL 查詢」。系統會開啟空白的編輯器分頁。

請保留這個分頁。這個實驗室中的每個 👉📋 區塊都會顯示在這裡:選取編輯器中的內容,將新區塊貼到該處,然後按一下「執行」。結果會顯示在下方的面板中。
認識資料表
稍後會用到這兩張表格。每個資料表都會將主鍵宣告為 NOT ENFORCED:BigQuery 不會檢查主鍵,但您即將建構的屬性圖需要明確的鍵,才能瞭解識別資料列的依據。最後一個資料表 PlaylistEntries 是接合資料表:如果歌曲位於四個播放清單中,這個資料表就會有四列。整個故事的來龍去脈都在這個表格中。
這些表格會像這樣串連在一起:唱片公司簽約藝人、藝人發行歌曲,以及透過 PlaylistEntries 將歌曲加入播放清單。Cymbal Records 擁有 Ava Sterling 和 Mina Okafor,以及她們的四首歌曲。Northwind Audio 擁有 Kai Nakamura 和一首歌曲「Midnight Drive」。
桌子 | 列 | 金鑰 | 所持內容 |
標籤 | 2 |
| 名稱、行銷預算 |
演出者 | 3 |
| 名稱,哪個標籤 |
歌曲 | 5 |
| 歌曲名稱、藝人、串流次數 |
播放清單 | 4 |
| 名稱、追蹤者 |
PlaylistEntries | 10 |
| 哪些歌曲位於哪些播放清單中 |
✅ 檢查點: 🎉 ready 在 Cloud Shell 中,檔案總管的 music 下方有五個表格,並開啟空白的查詢編輯器分頁。
3. 建立圖表 - 選項 A:視覺化建模工具
屬性圖形說明資料表的連結方式。您可以在視覺化圖形建模工具中一起點選 (這個步驟需要點選所有項目),也可以編寫 SQL (下一個步驟只需貼上)。兩者都會產生相同的物件,因此請擇一使用,不要同時使用。
1. 建立圖形殼層
👉🌐 控制台:在 BigQuery Studio 的「建立新項目」列中,開啟「AI 和知識」選單,然後點選「圖表」。
👉🌐 控制台:輸入 MusicGraph 做為「圖表名稱」,並輸入 music 做為「資料集內的圖表目的地」。系統會從資料集 (美國) 填入區域。
👉🌐 控制台:在「資料來源」下方,選取五個表格 (藝人、唱片公司、播放清單項目、播放清單、歌曲),然後按一下「建立」。

👀 畫布隨即開啟,顯示五個彩色節點,節點之間沒有任何線條。右側的「詳細資料」面板會列出「節點 (5)」和「邊緣 (0)」。每個節點都已將資料表的主鍵和所有資料欄做為屬性,按一下任一節點即可查看。

2. 繪製四個邊緣
邊緣是外鍵,每個參照都從保存鍵的資料表,指向該鍵所指的資料表。
👉🌐「控制台」- 按一下「新邊緣」。在「選取表格」對話方塊中,選擇 PlaylistEntries 並點按「新增」。在「新增邊緣」面板中:
- 將「Name」(名稱) 設定為
EntryToSong。 - 按一下「新增主鍵」,然後接受
entry_id。 - 在「來源」下方,將「來源節點」設為 PlaylistEntries,然後使用「在節點上新增參照的資料欄」和「在邊緣上新增參照的資料欄」,為兩者選取
entry_id。 - 在「目標」下方,將「目標節點」設為「歌曲」,然後為「節點的參照欄」和「邊緣的參照欄」選取
song_id。 - 按一下「完成」。

👉🌐 Console - 再重複三次:
邊緣名稱 | 桌子 | 來源節點 → 目標節點 | 兩側要挑選的資料欄 |
| PlaylistEntries | PlaylistEntries → Playlists | 來源 |
| 歌曲 | 歌曲 → 藝人 | 來源 |
| 演出者 | 藝人 → 唱片公司 | 來源 |
每個邊緣都不要有額外屬性。
👀「詳細資料」面板現在會顯示「邊緣 (4)」,畫布則會顯示鏈結:標籤 ← 藝人 ← 歌曲 ← PlaylistEntries → 播放清單。

3. 新增度量
👉🌐 控制台:按一下「歌曲」節點,然後點選「詳細資料」面板頂端的「編輯」 (鉛筆) 圖示。在標籤的「屬性」下方,依序點選「新增屬性」和「新增欄位」。
👉🌐 控制台:輸入 total_streams 做為「欄位名稱」,然後在「運算式」方塊中輸入以下內容:
MEASURE(SUM(streams))
👉🌐 主控台:依序點按「新增」和「完成」。

4. 閱讀系統編寫的程式碼,然後發布
👉🌐 控制台:開啟右側面板中的「程式碼」分頁。建模者已為您撰寫 CREATE PROPERTY GRAPH 陳述。捲動至「Songs」節點:其屬性清單現在會以
MEASURE(SUM(streams)) AS `total_streams`
這就是這項功能的全部內容,一行就說完了。這個步驟之後的所有內容,都是關於該行的作用。

👉🌐 控制台 - 點選「發布」。
✅ 檢查點:在 Explorer 中,music 現在有一個包含 MusicGraph 的「圖表」資料夾。點選:五個節點、四條邊緣,以及「程式碼」分頁中的 MEASURE(SUM(streams)) 行。略過下一個步驟,直接前往「SUM 和 AGG 並列」。
4. 建立圖表 - 選項 B:SQL
如果您在模型器中建構圖表,請略過這個步驟。
👉📋 查詢編輯器 - 貼上,然後點選「執行」:
CREATE OR REPLACE PROPERTY GRAPH music.MusicGraph
NODE TABLES (
music.Labels KEY (label_id)
PROPERTIES (label_id, label_name, marketing_budget,
MEASURE(SUM(marketing_budget)) AS total_budget),
music.Artists KEY (artist_id)
PROPERTIES (artist_id, artist_name, label_id,
MEASURE(COUNT(artist_id)) AS artist_count),
music.Songs KEY (song_id)
PROPERTIES (song_id, title, artist_id, streams,
MEASURE(SUM(streams)) AS total_streams,
MEASURE(COUNT(song_id)) AS song_count),
music.Playlists KEY (playlist_id)
PROPERTIES (playlist_id, playlist_name, followers,
MEASURE(SUM(followers)) AS total_followers),
music.PlaylistEntries KEY (entry_id)
PROPERTIES (entry_id, playlist_id, song_id,
MEASURE(COUNT(entry_id)) AS placement_count)
)
EDGE TABLES (
music.PlaylistEntries AS EntryToSong
SOURCE KEY (entry_id) REFERENCES PlaylistEntries(entry_id)
DESTINATION KEY (song_id) REFERENCES Songs(song_id) NO PROPERTIES,
music.PlaylistEntries AS EntryToPlaylist
SOURCE KEY (entry_id) REFERENCES PlaylistEntries(entry_id)
DESTINATION KEY (playlist_id) REFERENCES Playlists(playlist_id) NO PROPERTIES,
music.Songs AS SongToArtist
SOURCE KEY (song_id) REFERENCES Songs(song_id)
DESTINATION KEY (artist_id) REFERENCES Artists(artist_id) NO PROPERTIES,
music.Artists AS ArtistToLabel
SOURCE KEY (artist_id) REFERENCES Artists(artist_id)
DESTINATION KEY (label_id) REFERENCES Labels(label_id) NO PROPERTIES
)
👀 結果面板會顯示屬性圖已建立。

朗讀一次
這個圖表有五個節點資料表和四個邊緣資料表。每個節點表格都會命名 KEY 並列出 PROPERTIES。以 MEASURE 開頭的行是新部分:每一行都會將其中一個支援的聚合體包裝在屬性周圍,並為其提供別名 (這是必要做法)。
每個邊緣資料表都是外鍵,拼寫方式如下:SOURCE KEY 在保存鍵的資料表上,DESTINATION KEY 在指向的資料表上。NO PROPERTIES 表示邊緣本身沒有任何內容。
請注意,PlaylistEntries 出現了三次:一次是節點資料表,另外兩次是 EntryToSong 和 EntryToPlaylist 邊緣後方的實體資料表。這是刻意設計,稍後我們會說明原因。
看看你製作的內容
👉🌐 控制台:在「Explorer」窗格中,依序展開 music、「Graphs」和「MusicGraph」。圖表頁面會在畫布上開啟,其中包含五個節點和四條邊緣。按一下節點即可查看屬性,當中會列出指標及其匯總。開啟「程式碼」分頁,即可查看圖片背後的陳述內容。

✅ 檢查點:music 具有包含 MusicGraph 的「Graphs」資料夾,且「程式碼」分頁會顯示 MEASURE(SUM(streams)) AS total_streams。
5. SUM 和 AGG 並列
這項查詢包含整個程式碼研究室的內容。這兩欄都嘗試從同一個資料表回答相同問題,也就是每個唱片的總串流次數。
該資料表就是 GRAPH_EXPAND 產生的資料表。這個函式會「扁平化」圖表:從一個資料表開始,沿著每個邊緣向外移動,直到所有連線的資料表都並排顯示在單一寬廣的結果中。LEFT JOIN每刊登位置一列,而非每首歌曲一列,且每個資料欄都命名為 TableLabel_property。請先查看該項目,再查詢。
👉📋 查詢編輯器 - 貼上,然後點選「執行」:
SELECT Labels_label_name, Songs_title, Songs_streams, Playlists_playlist_name
FROM GRAPH_EXPAND("music.MusicGraph")
ORDER BY Songs_title, Playlists_playlist_name
👀 預期會有 10 個資料列,PlaylistEntries 中的每個刊登位置各有一個資料列,這正是設定載入的內容。「Neon Summer」佔了其中四個位置 (每個播放清單各一個),且每個播放清單的Songs_streams讀取次數都達到 2,000,000,000 次。這些資料列沒有問題,播放清單確實是四個。但屬於歌曲的資料欄現在會在屬於刊登位置的資料列中重複出現,這就是下一個查詢要評估的整個問題。
現在來比較一下。
👉📋 查詢編輯器 - 貼上,然後點選「執行」:
SELECT
Labels_label_name,
SUM(Songs_streams) AS with_sum,
AGG(Songs_total_streams) AS with_agg
FROM GRAPH_EXPAND("music.MusicGraph")
GROUP BY 1 ORDER BY 1
👀 結果:
Labels_label_name | with_sum | with_agg |
Cymbal Records | 12,600,000,000 | 5,100,000,000 |
Northwind Audio | 9,000,000,000 | 4,500,000,000 |

請手動檢查。Cymbal 的四首歌曲分別有 20 億、15 億、12 億和 4 億次串流。也就是 51 億。AGG 是正確的。SUM 的大小是原本的 2.5 倍,而 Northwind 的單一歌曲大小則是原本的 2 倍。
三種新語法
GRAPH_EXPAND("music.MusicGraph")是資料表值函式,會將圖表轉換為一個寬資料表,並將每個邊緣視為LEFT JOIN。每個資料欄都命名為TableLabel_property,因此Songs_streams是 Songs 資料表中的原始資料欄,而Songs_total_streams是您宣告的指標。SUM(Songs_streams)是針對該寬資料表的普通 SQL,並會繼承扁平化產生的每個重複項目。AGG(Songs_total_streams)會以宣告的方式評估指標:每song_id一次,無論歌曲在寬資料表中佔據多少列。SUM(streams)
✅ 檢查點:兩個標籤、兩欄,且 with_agg 數字與手部數量相符。
6. 為什麼 SUM 會多算
選取一首歌曲,然後看看這些接合點對歌曲有什麼影響。
👉📋 查詢編輯器 - 貼上,然後點選「執行」:
SELECT 'BEFORE - the Songs table' AS step, title, streams, CAST(NULL AS STRING) AS playlist
FROM music.Songs WHERE title = 'Neon Summer'
UNION ALL
SELECT 'AFTER - joined to playlists', s.title, s.streams, pl.playlist_name
FROM music.Songs s
LEFT JOIN music.PlaylistEntries e ON e.song_id = s.song_id
LEFT JOIN music.Playlists pl ON pl.playlist_id = e.playlist_id
WHERE s.title = 'Neon Summer'
ORDER BY step DESC, playlist
👀 結果:
點選 [下一步] | title | 小溪 | 播放清單 |
更新前 - Songs 資料表 | 霓虹夏日 | 2,000,000,000 | null |
AFTER - joined to playlists | 霓虹夏日 | 2,000,000,000 | 健身房 |
AFTER - joined to playlists | 霓虹夏日 | 2,000,000,000 | 目前熱門 |
AFTER - joined to playlists | 霓虹夏日 | 2,000,000,000 | 竄紅流行樂 |
AFTER - joined to playlists | 霓虹夏日 | 2,000,000,000 | Road Trip |

一列變成四列。串流數量不會變更,而是複製。將副本的播放次數加總:Cymbal Records 的 Neon Summer 在四個播放清單中獲得 20 億次播放,總共是 80 億次;Paper Crown 在兩個播放清單中獲得 15 億次播放,總共是 30 億次;Double Shot 在一個播放清單中獲得 12 億次播放;Slow Arrow 在一個播放清單中獲得 4 億次播放。也就是 126 億,這是 SUM 傳回的數字。Northwind 的 Midnight Drive 位於兩個播放清單中,因此 45 億次播放次數會變成 90 億次。
這是「扇出」,並非聯結中的錯誤。播放清單列是真的。錯誤是將屬於刊登位置的資料列中,屬於歌曲的數字加總。
由於該指標是在「歌曲」節點上與 KEY (song_id) 一起宣告,因此可修正這個問題。關鍵在於紋理。AGG 評估 total_streams 時,系統會針對每個歌曲調性匯總一次,然後再匯總至您分組的任何項目。
異動內容
你以前寫的內容 | 有測量指標 |
|
|
|
|
三 |
|
在聯結前彙整的 CTE | 完全沒影響。 |
✅ 檢查點:五列資料 (一列是 BEFORE,四列是 AFTER),您可從中重建 126 億筆資料。
7. 規則:只有 AGG 會讀取測量指標
測量指標有自己的類型 MEASURE,且只有一個函式會接受該類型。下列四項查詢會刻意失敗,請逐一執行並閱讀紅色錯誤訊息。這四種說法是大家最常嘗試的,瞭解這些說法可節省後續時間。
👉📋 查詢編輯器 - AGG 位於純文字欄:
SELECT AGG(Songs_streams) FROM GRAPH_EXPAND("music.MusicGraph")
👀 No matching signature for aggregate function AGG ... Argument 1: expected MEASURE

👉📋 查詢編輯器 - 沒有 AGG 的指標資料欄:
SELECT Songs_total_streams FROM GRAPH_EXPAND("music.MusicGraph") LIMIT 1
👀 Returning expressions of type MEASURE is not allowed

👉📋 查詢編輯器:GQL 中參照的指標,但從未顯示任何指標 (這是 GQL 查詢,請參閱總覽中的版本附註):
GRAPH music.MusicGraph
MATCH (s:Songs)
RETURN s.total_streams
LIMIT 1
👀 total_streams is not exposed by element type GRAPH_NODE(...)

👉📋 查詢編輯器 - SUM 將滑鼠游標懸停在評估資料欄上,也就是您想使用的資料欄:
SELECT Labels_label_name, SUM(Songs_total_streams)
FROM GRAPH_EXPAND("music.MusicGraph")
GROUP BY 1
👀 MEASURE-typed arguments are only permitted in the AGG function

因此型別系統會為您強制執行規則。測量指標只能透過 GRAPH_EXPAND 顯示,且只能透過 AGG 讀取。先前多算的 126 億次只能來自於加總原始資料欄,絕不會是誤用指標所致。
✅ 檢查點:四個紅色錯誤,且您能指出每個錯誤強制執行的規則。
8. 每個匯總值,以及該指標支援的匯總值
MEASURE() 會包裝六個匯總之一:SUM、AVG、MIN、MAX、COUNT 和 COUNT(DISTINCT)。在「Songs」節點上重新建立圖表,邊緣會保持 NO PROPERTIES,這是邊緣與節點共用實體資料表時,記錄在文件中的最佳做法。
👉📋 查詢編輯器 - 貼上,然後點選「執行」:
CREATE OR REPLACE PROPERTY GRAPH music.MusicGraph
NODE TABLES (
music.Labels KEY (label_id)
PROPERTIES (label_id, label_name, marketing_budget,
MEASURE(SUM(marketing_budget)) AS total_budget),
music.Artists KEY (artist_id)
PROPERTIES (artist_id, artist_name, label_id,
MEASURE(COUNT(artist_id)) AS artist_count),
music.Songs KEY (song_id)
PROPERTIES (song_id, title, artist_id, streams,
MEASURE(SUM(streams)) AS total_streams,
MEASURE(AVG(streams)) AS avg_streams,
MEASURE(MIN(streams)) AS min_streams,
MEASURE(MAX(streams)) AS max_streams,
MEASURE(COUNT(song_id)) AS song_count,
MEASURE(COUNT(DISTINCT artist_id)) AS distinct_artists),
music.Playlists KEY (playlist_id)
PROPERTIES (playlist_id, playlist_name, followers,
MEASURE(SUM(followers)) AS total_followers),
music.PlaylistEntries KEY (entry_id)
PROPERTIES (entry_id, playlist_id, song_id,
MEASURE(COUNT(entry_id)) AS placement_count)
)
EDGE TABLES (
music.PlaylistEntries AS EntryToSong
SOURCE KEY (entry_id) REFERENCES PlaylistEntries(entry_id)
DESTINATION KEY (song_id) REFERENCES Songs(song_id) NO PROPERTIES,
music.PlaylistEntries AS EntryToPlaylist
SOURCE KEY (entry_id) REFERENCES PlaylistEntries(entry_id)
DESTINATION KEY (playlist_id) REFERENCES Playlists(playlist_id) NO PROPERTIES,
music.Songs AS SongToArtist
SOURCE KEY (song_id) REFERENCES Songs(song_id)
DESTINATION KEY (artist_id) REFERENCES Artists(artist_id) NO PROPERTIES,
music.Artists AS ArtistToLabel
SOURCE KEY (artist_id) REFERENCES Artists(artist_id)
DESTINATION KEY (label_id) REFERENCES Labels(label_id) NO PROPERTIES
)

現在請將所有內容讀回。每個測量值都會經過 AGG,最後一欄顯示的 AGG 結果是可進行算術運算的普通值。圖表剛變更,請先清除「使用快取結果」(「更多」→「查詢設定」)。
👉📋 查詢編輯器 - 貼上,然後點選「執行」:
SELECT
Labels_label_name,
AGG(Songs_total_streams) AS total_streams,
AGG(Songs_avg_streams) AS avg_streams,
AGG(Songs_min_streams) AS min_streams,
AGG(Songs_max_streams) AS max_streams,
AGG(Songs_song_count) AS songs,
AGG(Songs_distinct_artists) AS artists,
AGG(Songs_total_streams) / AGG(Songs_song_count) AS streams_per_song
FROM GRAPH_EXPAND("music.MusicGraph")
GROUP BY 1
ORDER BY 1
👀 結果:
Labels_label_name | total_streams | avg_streams | min_streams | max_streams | 歌曲 | 藝人 | streams_per_song |
Cymbal Records | 5,100,000,000 | 1,275,000,000 | 400,000,000 | 2,000,000,000 | 4 | 2 | 1,275,000,000 |
Northwind Audio | 4,500,000,000 | 4,500,000,000 | 4,500,000,000 | 4,500,000,000 | 1 | 1 | 4,500,000,000 |

每個數字都是根據 Cymbal 的四首歌曲和 Northwind 的一首歌曲計算,而不是根據十個刊登位置列。AVG 尤其會出現錯誤,因為如果將原始資料欄的資料平均分配到每個刊登位置列,Cymbal 的值會變成 15.75 億,這是因為 Neon Summer 的 20 億會計算四次。
因此「將 SUM 換成 AGG」實際上是兩項決策。宣告指標時,您仍可選擇六個匯總函式中的其中一個。讀取指標時,函式一律為 AGG。
✅ 檢查點:每個標籤各一列,每列七個數字,且 streams_per_song 等於 avg_streams。
9. 變更分組,而非指標
同一項指標回答了不同的問題。改為依播放清單分組,而非依標籤分組。
👉📋 查詢編輯器 - 貼上,然後點選「執行」:
SELECT
Playlists_playlist_name,
AGG(Songs_total_streams) AS streams,
AGG(Songs_song_count) AS songs
FROM GRAPH_EXPAND("music.MusicGraph")
GROUP BY 1
ORDER BY 2 DESC
👀 結果:
Playlists_playlist_name | 小溪 | 歌曲 |
Road Trip | 6,900,000,000 | 3 |
健身房 | 6,500,000,000 | 2 |
目前熱門 | 4,700,000,000 | 3 |
竄紅流行樂 | 3,500,000,000 | 2 |

這兩條 AGG 線條與 SUM 和 AGG 的線條完全相同,只是並排顯示。只有 GROUP BY 會轉移。「Road Trip」播放清單收錄了「Neon Summer」、「Midnight Drive」和「Slow Arrow」,每首歌在播放清單中都算一次,這就是「播放清單的串流次數」的意義。
撰寫該措施的人員已決定一次細節。之後任何人提出的查詢都會沿用這項設定。
✅ 查核點:「哈啦上路」以 69 億次觀看次數位居榜首。
10. 查看 GRAPH_EXPAND 的輸出結果
您不必執行 GRAPH_EXPAND 即可瞭解形狀。BQ.SHOW_GRAPH_EXPAND_SCHEMA 系統程序會將資料欄清單寫入變數。
👉📋 查詢編輯器 - 貼上所有三行,然後按一下「執行」:
DECLARE schema STRING DEFAULT '';
CALL BQ.SHOW_GRAPH_EXPAND_SCHEMA('music.MusicGraph', schema);
SELECT schema;
👀 結果是 JSON 字串。每個欄位都有名稱、類型和模式,且每個指標資料欄都會帶有 "is_measure": true。您剛建構的圖表會提供下列資訊:
名稱 | 類型 | is_measure | |
Songs_title | STRING | ||
Songs_streams | INTEGER | ||
Songs_total_streams | INTEGER | true | |
Songs_avg_streams | FLOAT | true | |
Songs_distinct_artists | INTEGER | true | |
PlaylistEntries_placement_count | INTEGER | true | |

您在屬性中設定的任何說明或同義字也會顯示在這裡。選用的即時通訊步驟會顯示誰讀取這些內容。
✅ 檢查點:JSON 字串,其中每個以 MEASURE 宣告的資料欄都有 is_measure。
11. GRAPH_EXPAND 需要圖譜形狀的哪些資訊
這個步驟沒有要執行的內容,只要閱讀即可。GRAPH_EXPAND 會從一個資料表開始,沿著邊緣向外擴展,以 LEFT JOIN 鏈結建構寬資料表。這三項規則是從該原則衍生而來,而 MusicGraph 符合所有規則。

只能有一個根節點資料表。根是節點資料表,其鍵不會出現在任何其他資料表中,也就是沒有任何邊指向的節點。在 MusicGraph 中,PlaylistEntries 是兩條邊的來源,但不是任何邊的目的地。寬表格有 10 列,每列代表一個刊登位置。
每個邊緣都是多對一,從來源到目的地。每個項目都有一首歌曲和一個播放清單,每首歌曲有一位藝人,每位藝人有一個唱片公司。因此,寬表格絕不會超出根目錄本身的列。根目錄無法存取的資料不會顯示:如果歌曲沒有刊登位置,就不會出現在廣泛資料表中。
多對多關係會成為節點。歌曲和播放清單之間是多對多關係。如果您將接合資料表宣告為從歌曲到播放清單的單一邊緣,GRAPH_EXPAND 會忽略該資料表,因為這類邊緣不明確。由於沒有可用的邊緣,GRAPH_EXPAND 會失敗。將 PlaylistEntries 升格為節點資料表,並從中建立兩個多對一邊緣,是記錄在案的模式,也是您建構圖表時採用的做法。
12. (選用) 使用 GQL 查詢路徑
目前為止,每個問題都有一個答案編號。這個則不會。「Cymbal 的串流在何處觸及聽眾?」是關於圖表中路徑的問題,總和無法回答這個問題,因為在您加總時,路徑就消失了。
1. 詢問串流的播放位置
👉📋 查詢編輯器 - 貼上,然後點選「執行」:
GRAPH music.MusicGraph
MATCH (l:Labels)<-[:ArtistToLabel]-(a:Artists)<-[:SongToArtist]-(s:Songs)
<-[:EntryToSong]-(e:PlaylistEntries)-[:EntryToPlaylist]->(pl:Playlists)
WHERE l.label_name = 'Cymbal Records'
RETURN pl.playlist_name, pl.followers,
SUM(s.streams) AS streams_reaching_this_playlist,
STRING_AGG(s.title, ', ') AS songs
GROUP BY pl.playlist_name, pl.followers
ORDER BY streams_reaching_this_playlist DESC
👀 預計會有四個播放清單:
pl.playlist_name | pl.followers | streams_reaching_this_playlist | 歌曲 |
目前熱門 | 35,000,000 | 4,700,000,000 | Double Shot、Neon Summer、Paper Crown |
竄紅流行樂 | 2,000,000 | 3,500,000,000 | Neon Summer、Paper Crown |
Road Trip | 5,000,000 | 2,400,000,000 | 霓虹夏日、慢速箭頭 |
健身房 | 3,000,000 | 2,000,000,000 | 霓虹夏日 |

請將 MATCH 行視為一個句子:從唱片公司開始,往回走到藝人,再往回走到藝人的歌曲,然後往回走到這些歌曲所在的播放清單項目,最後往前走到播放清單。箭頭指向邊緣的宣告方式;<- 則會向後走一步。
現在請加總第三欄的數字。126 億:這是步驟四中 SUM 給你的數字,也就是錯誤的數字。
這就是正確的。當時的問題是 Cymbal 的串流次數,無論歌曲出現在多少播放清單中,都只會計算一次。這個問題就是這些串流的觸及範圍,而一首歌曲在四個播放清單上,確實觸及了四個目標對象。GRAPH_EXPAND 產生的重複內容,其中一個是問題,另一個是答案。AGG 從來不是要避免重複,而是要讓算術與問題相符。
2. 傳回路徑本身
取消匯總,然後要求路線。
👉📋 查詢編輯器 - 貼上,然後點選「執行」:
GRAPH music.MusicGraph
MATCH p = (l:Labels)<-[:ArtistToLabel]-(a:Artists)<-[:SongToArtist]-(s:Songs)
<-[:EntryToSong]-(e:PlaylistEntries)-[:EntryToPlaylist]->(pl:Playlists)
WHERE l.label_name = 'Cymbal Records'
RETURN TO_JSON(p) AS path
p = 會命名整個相符項目,而 TO_JSON 會算繪該項目。
👀 預期會有 8 列,以及一個 path 欄。每個儲存格都是節點和邊緣的 JSON 陣列,沿著一條路線,每個節點都攜帶 labels 和 properties。

四首歌曲共八列,因為每個刊登位置都有路徑,而非每首歌曲都有。
3. 開啟「圖表」分頁
👉🌐 主控台:在結果上方點選「圖表」。
只有在結果包含圖表元素時,系統才會顯示這個分頁。先前的查詢傳回數字,因此沒有「圖表」分頁;這次的查詢傳回路徑,因此有「圖表」分頁。

您會看到以強制版面配置繪製的 Cymbal 圖表角落,以及每個標籤的節點和邊緣計數。拖曳節點即可拉開版面配置;按一下節點即可讀取其屬性。
✅ 檢查點:第一個查詢的第三欄總和為 126 億,第二個查詢會傳回 8 個路徑,「圖表」分頁會繪製這些路徑。
13. (選用) 與圖表對話
這個步驟不涉及 SQL。BigQuery 資料代理可將圖表做為知識來源,且文件指出這些代理會使用多層級匯總的指標。我們來看看是否真是如此。
1. 建立代理
👉🌐 控制台:在左側的 BigQuery 導覽選單中,依序點選「代理程式」、「代理程式目錄」和「建立代理程式」。
👉🌐 控制台:在「代理名稱」中輸入 Music graph agent,並在「代理說明」中輸入:
Ask questions about labels, artists, songs and playlists in the music property graph.
👉🌐 控制台:在「知識來源」下方,按一下「新增來源」。在「選取來源」對話方塊中,依序展開專案、music、「圖表」,勾選「MusicGraph」,然後按一下「確認」。
👀「新增來源」按鈕會變成灰色。代理最多可保留一個圖表,且無法混用圖表和表格。

👉🌐 管理中心 - 將「區域」保留為圖表位置設定的值。依序點選「儲存」和「發布」。在「發布管道」面板中,按一下「發布代理」並關閉確認視窗。
2. 提問
👉🌐 主控台:按一下「建立對話」。系統會開啟即時通訊頁面。在底部的「提出問題」方塊中輸入下列內容,然後按下 Enter 鍵:
For each label, show total streams and how many playlists their songs are on
👀 代理程式會傳回表格和一句摘要:
label_name | total_streams | playlist_placements |
Cymbal Records | 5,100,000,000 | 8 |
Northwind Audio | 4,500,000,000 | 2 |

51 億美元。沒有人告訴代理程式有關擴散傳遞功能,而且代理程式也沒有落入擴散傳遞功能。
3. 閱讀系統撰寫的查詢
👉🌐 控制台:在導覽選單中,依序點選「Jobs explorer」和最新工作。標籤包括 ca-bq-job: true 和 data-agent-id,其中包含代理程式的 ID,查詢內容如下:
SELECT
Labels_label_name AS label_name,
AGG(Songs_total_streams) AS total_streams,
AGG(PlaylistEntries_placement_count) AS playlist_placements
FROM GRAPH_EXPAND("music.MusicGraph")
GROUP BY label_name
ORDER BY total_streams DESC

因為讀取的結構定義中含有這些指標,因此會自行使用 GRAPH_EXPAND 和 AGG。代理的說明中未提及這些項目。
✅ 檢查點:聊天室回覆中為 51 億,且作業的 SQL 中為 AGG(...)。
14. 清理
👉💻 Cloud Shell - 捨棄資料集、資料表和屬性圖:
cd ~/bq-graph-measures-lab
./cleanup.sh
👀 預期 ✓ dropped YOUR_PROJECT_ID.music (tables and graph)。
如果您建立了選用資料代理,請在控制台的「Agents」→「Agent catalog」下方刪除。如果您./setup_project.sh是為了這個實驗室建立專案,最徹底的清除方式就是關閉整個專案,專案 ID 位於 ~/project_id.txt。
15. 恭喜
您宣告了一行 MEASURE(SUM(streams)),將 126 億改為 51 億,這項變更會影響您和之後對該圖表執行的所有查詢 (包括代理程式編寫的查詢)。
您學到的內容
- 測量值是在節點上宣告的匯總,位於設定其粒度的
KEY旁。 GRAPH_EXPAND會將圖表攤平為一個寬表格,其中包含TableLabel_property欄。AGG是唯一會讀取指標的函式,型別系統會以四種不同方式強制執行這項操作。- 共有六個匯總值,而
AGG結果是可除以的普通值。 - 變更
GROUP BY會重新詢問問題,但不會影響測量結果。 GRAPH_EXPAND想要一個根、多對一的邊緣,以及升級為節點的交接點。
決策表
問題 | 原因 | 修正 |
總金額過高 |
| 宣告測量值,並使用 |
「expected MEASURE, found INT64」(預期為 MEASURE,但找到 INT64) |
| 使用 |
「Returning expressions of type MEASURE is not allowed」(不允許傳回 MEASURE 類型的運算式) | 沒有 | 包裝: |
「not exposed by element type」(元素類型未公開) | GQL 參照的測量指標 | 僅測量落後 |
| 以邊緣形式模擬的交會點 | 將接合表升級為節點 |
變更圖表後的舊號碼 | 快取結果 | 取消勾選「使用快取結果」 |
我們刻意未涵蓋的主題
屬性的說明和同義詞、資料代理的已驗證查詢和詞彙表、超過一個 MATCH 的 GQL、多個圖譜的測量指標。每個都是獨立的實驗室。