1. Przegląd
Większość błędów SQL, które przechodzą weryfikację kodu, to błędy agregacji. Liczba jest prawidłowa w tabeli, w której się znajduje, złączenie ją kopiuje, a suma jest nieprawidłowa.
BigQuery Graph umożliwia jednokrotne opisanie połączeń między tabelami w postaci wykresu właściwości, a następnie wysyłanie zapytań dotyczących tych połączeń. Pomiary wykresu dodają do tego opisu jeszcze jedną rzecz: samą agregację. Deklarujesz MEASURE(SUM(streams)) w węźle, który jest właścicielem liczby, a każde zapytanie odczytujące wykres otrzymuje prawidłową sumę na odpowiednim poziomie szczegółowości – bez sztuczki GROUP BY i bez wyrażenia CTE, o którym ktoś musi pamiętać.
W tym laboratorium zbudujesz katalog muzyczny składający się z 5 tabel, umieścisz w nim 1 miarę i zobaczysz, jak to samo pytanie zwraca 2 różne odpowiedzi: 12,6 miliarda w przypadku SUM i 5,1 miliarda w przypadku AGG. Luka to kształt katalogu – utwór, który znajduje się na 4 playlistach, po spłaszczeniu wykresu zajmuje 4 wiersze, a SUM dodaje wszystkie 4. Następnie poznajesz reguły, które sprawiają, że drugie zdanie jest poprawne.

Miejsce, w którym będziesz pisać
W tym module używane są dokładnie 2 miejsca w tej kolejności:
gdzie | co tam robisz, | |
1 | Terminal Cloud Shell | kilka poleceń, ale tylko na etapie Konfiguracja. |
2 | konsola BigQuery, | wszystkie inne działania: wklejanie zapytań do edytora zapytań, klikanie w modelu wykresu, czatowanie z agentem. |
Każda instrukcja jest oznaczona tagiem, dzięki czemu zawsze wiesz, o którą chodzi:
- 👉💻 Cloud Shell – wpisz to w terminalu Cloud Shell.
- 👉📋 Edytor zapytań – wklej to do edytora zapytań BigQuery i kliknij Uruchom.
- 👉🌐 Konsola – klikaj różne elementy w konsoli BigQuery. Nie wpisuj niczego, chyba że w instrukcji jest to wyraźnie zaznaczone.
- 👀 – sprawdź wynik.
Czego się nauczysz
- Jak zadeklarować miarę w tabeli węzłów – w wizualnym modelowaniu grafu lub w SQL
- Jak
GRAPH_EXPANDspłaszcza wykres do jednej szerokiej tabeli - Dlaczego tylko funkcja
AGGmoże odczytać miarę i co zwraca każda inna próba - 6 rodzajów agregacji, które obsługuje miara, oraz sposób wykonywania na nich działań arytmetycznych
- Jak jedna miara odpowiada na pytanie z innym grupowaniem bez zmian
- Opcjonalnie: jak GQL i karta Wykres odpowiadają na pytanie, na które nie można uzyskać odpowiedzi za pomocą sumy, oraz jak agent danych BigQuery korzysta z Twoich pomiarów bez informowania o nich
Czego potrzebujesz
- Konto Google z dostępną opcją rozliczeń i przeglądarka. Nie musisz mieć projektu w chmurze Google Cloud na początku – konfiguracja utworzy go za Ciebie.
- Tylko w przypadku opcjonalnego kroku czatu: włączony interfejs Gemini Data Analytics API i rola Twórca agentów danych Gemini Data Analytics.
Nie musisz niczego instalować na swoim urządzeniu. Wszystko działa w Cloud Shell i konsoli BigQuery.
Stan i koszt produktu
Graf BigQuery jest ogólnodostępny. Pomiary grafu, wizualny modeler grafu, wizualizacja grafu i używanie grafu jako źródła wiedzy agenta danych są w wersji testowej i podlegają Warunkom ofert przed GA.
GRAPH_EXPAND i AGG są rozliczane według cen na żądanie. Zapytania GQL (opcjonalny krok ścieżki) wymagają rezerwacji korzystającej z wersji Enterprise lub Enterprise Plus zgodnie z dokumentacją, dlatego ten krok jest opcjonalny.
Zbiór danych ma rozmiar kilku kilobajtów. W przypadku cen na żądanie każde zapytanie jest rozliczane według minimalnej stawki za 10 MB, więc cały kurs kosztuje ułamek centa.
2. Konfiguracja
To jedyny krok, w którym używana jest usługa Cloud Shell. Spowoduje to utworzenie projektu, włączenie w nim płatności i utworzenie tabel pierwotnych. Wykres, miara i każde zapytanie możesz później uruchomić w konsoli BigQuery.
Jednego nie możemy Ci zapewnić: projektu Google Cloud z włączonymi płatnościami. W kroku 1 uzyskasz konto, z którego można dokonywać płatności, a w kroku 4 przekształcisz to konto w projekt. Wykonaj je w tej kolejności – każdy krok po kroku 4 odczytuje projekt utworzony w kroku 4.
1. Uzyskaj konto z płatnościami (~1 min)
👉🌐 Zrób to w pierwszej kolejności. Zaloguj się na konto Google z włączonymi płatnościami. Każde takie konto będzie działać. Jeśli nie masz takiego konta, rozpocznij bezpłatny okres próbny. Dzięki temu uzyskasz konto rozliczeniowe, które jest potrzebne w kroku 4.
2. Otwórz Cloud Shell (~1 min)
👉🌐 Konsola – kliknij Aktywuj Cloud Shell u góry konsoli Google Cloud. Jest to ikona w kształcie terminala w nagłówku. U dołu strony otworzy się terminal.

👉🌐 Konsola – jeśli w dowolnym momencie pojawi się prośba o autoryzację, kliknij Autoryzuj, aby kontynuować.
👉💻 Cloud Shell – sprawdź, na jakie konto jest zalogowany Cloud Shell:
gcloud auth list
👀 Spodziewaj się, że Twoje konto będzie oznaczone symbolem *. Musi to być to samo konto, na które zalogowano się w kroku 1. Jeśli nie, uruchom gcloud auth login i wybierz odpowiednią.
3. Uzyskaj dostęp do laboratorium (ok. 1 min)
👉💻 Cloud Shell – sklonuj repozytorium:
cd ~
rm -rf ~/bq-graph-measures-lab
git clone https://github.com/cuppibla/bq-graph-measures-lab.git
cd ~/bq-graph-measures-lab
4. Utwórz projekt (ok. 2 min)
👉💻 Cloud Shell – jeden skrypt znajduje Twoje konto rozliczeniowe, tworzy na nim projekt i kieruje Cloud Shell na ten projekt:
cd ~/bq-graph-measures-lab
./setup_project.sh
👀 Oczekuj ✓ w przypadku wybranego konta rozliczeniowego, ✓ w przypadku utworzonego projektu i zakończenia w tym stylu:
Project ready: bq-graph-4271 Next: ./setup.sh
bq-graph-4271 to identyfikator Twojego projektu – będzie on zawierać inne cyfry. W tym czasie dzieją się 4 rzeczy:
płatności, | wybiera najnowsze konto | |
projekt | utworzy konto | |
wybiera | zapisuje identyfikator w | |
waits | sprawdza, czy nowy projekt może wyświetlać reklamy, przez maksymalnie 2 minuty. | |
🌐 Ten sam projekt jest teraz w konsoli – jego identyfikator znajduje się na karcie Informacje o projekcie w panelu:

5. Utwórz zbiór danych (ok. 3 min)
👉💻 Cloud Shell – kolejny skrypt tworzy tabele:
cd ~/bq-graph-measures-lab
./setup.sh
Skrypt wyświetla każdy krok podczas jego wykonywania. Działanie w kolejności:
projekt | odczytuje projekt z | |
API | umożliwia | |
zbiór danych | tworzy zbiór danych | |
sprawdź | zlicza wiersze w każdej tabeli i przerywa działanie, jeśli któraś z liczb jest nieprawidłowa; | |
👀 Spodziewaj się:
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
Praca z Cloud Shell została zakończona. Możesz go zamknąć.
6. Otwórz BigQuery i edytor zapytań
👉🌐 Konsola – kliknij link na końcu danych wyjściowych lub otwórz BigQuery w menu nawigacyjnym. W panelu Eksplorator po lewej stronie rozwiń projekt: zbiór danych music z 5 tabelami.

👉🌐 Konsola – u góry BigQuery Studio w wierszu Utwórz nowe kliknij Zapytanie SQL. Otworzy się pusta karta edytora.

Nie zamykaj tej karty. Każdy 👉📋 blok w tym module umieść tutaj: zaznacz wszystko w edytorze, wklej nowy blok, a potem kliknij Uruchom. Wynik pojawi się w panelu poniżej.
Poznaj tabele
Później ważne będą 2 rzeczy dotyczące tych tabel. Każda tabela deklaruje swój klucz podstawowy jako NOT ENFORCED: BigQuery go nie sprawdza, ale wykres właściwości, który zamierzasz utworzyć, potrzebuje jawnego klucza, aby wiedzieć, co identyfikuje wiersz. Ostatnia tabela, PlaylistEntries, to tabela łącząca: utwór, który znajduje się na 4 playlistach, ma w niej 4 wiersze. Przy tym stole rozgrywa się cała historia.
Tabele są połączone w ten sposób: wytwórnia podpisuje umowy z wykonawcami, wykonawca wydaje utwory, a utwór jest umieszczany na playlistach za pomocą tabeli PlaylistEntries. Cymbal Records jest właścicielem Ava Sterling i Miny Okafor, a za ich pośrednictwem 4 utworów. Firma Northwind Audio jest właścicielem Kai Nakamura i jednego utworu, Midnight Drive.
stół | wiersze | klucz | co zawiera, |
Etykiety | 2 |
| nazwa, budżet marketingowy |
Wykonawcy | 3 |
| nazwa, która etykieta |
Utwory | 5 |
| tytuł, wykonawca, strumienie |
Playlisty | 4 |
| nazwa, obserwujący |
PlaylistEntries | 10 |
| który utwór znajduje się na której playliście, |
✅ Punkt kontrolny: w Cloud Shell otwarty jest plik 🎉 ready, w Eksploratorze w sekcji music znajduje się 5 tabel, a karta edytora zapytań jest pusta.
3. Tworzenie grafu – opcja A: modelowanie wizualne
Graf właściwości to opis połączeń między tabelami. Możesz kliknąć go w modelu graficznym (ten krok, wszystkie kliknięcia) lub napisać go w SQL-u (następny krok, jedno wklejenie). Obie metody tworzą ten sam obiekt – użyj jednej z nich, ale nie obu.
1. Utwórz szkielet wykresu
👉🌐 Konsola – w BigQuery Studio w wierszu Utwórz nowe otwórz menu AI i wiedza i kliknij Wykres.
👉🌐 Konsola – wpisz MusicGraph jako nazwę grafu i music jako miejsce docelowe grafu w zbiorze danych. Region jest wypełniany na podstawie zbioru danych (Stany Zjednoczone).
👉🌐 Konsola – w sekcji Źródła danych wybierz 5 tabel: Artists, Labels, PlaylistEntries, Playlists, Songs (Wykonawcy, Wytwórnie, Pozycje na playlistach, Playlisty, Utwory) i kliknij Utwórz.

👀 Na kanwie pojawia się 5 kolorowych węzłów bez linii między nimi. W panelu Szczegóły po prawej stronie wyświetlają się Węzły (5) i Krawędzie (0). Każdy węzeł zawiera już klucz podstawowy tabeli i wszystkie jej kolumny jako właściwości – kliknij dowolny węzeł, aby je wyświetlić.

2. Narysuj 4 krawędzie
Krawędź to klucz obcy, narysowany. Każda z nich prowadzi od tabeli zawierającej klucz do tabeli, na którą wskazuje.
👉🌐 Konsola – kliknij Nowa krawędź. W oknie Wybierz tabelę wybierz PlaylistEntries i kliknij Dodaj. W panelu Dodaj krawędź:
- Ustaw Name (Nazwa) na
EntryToSong. - Kliknij Dodaj klucz podstawowy i zaakceptuj
entry_id. - W sekcji Źródło ustaw Węzeł źródłowy na PlaylistEntries, a następnie użyj opcji Dodaj kolumny, do których odwołuje się węzeł i Dodaj kolumny, do których odwołuje się krawędź, aby wybrać
entry_idw obu przypadkach. - W sekcji Wartość docelowa ustaw Węzeł docelowy na Utwory, a następnie wybierz
song_idw przypadku opcji Kolumny, do których odwołuje się węzeł i Kolumny, do których odwołuje się krawędź. - Kliknij Gotowe.

👉🌐 Konsola – powtórz jeszcze 3 razy:
nazwa krawędzi | stół | węzeł źródłowy → węzeł docelowy | kolumnę, którą chcesz wybrać po obu stronach; |
| PlaylistEntries | PlaylistEntries → Playlists | źródło |
| Utwory | Utwory → Wykonawcy | źródło |
| Wykonawcy | Wykonawcy → Wytwórnie | źródło |
Pozostaw wszystkie krawędzie bez dodatkowych właściwości.
👀 W panelu Szczegóły widnieje teraz napis Krawędzie (4), a na obszarze roboczym widać łańcuch: Etykiety ← Wykonawcy ← Utwory ← Elementy playlisty → Playlista.

3. Dodawanie pomiaru
👉🌐 Konsola – kliknij węzeł Utwory, a potem ikonę edytowania (ołówka) u góry panelu Szczegóły. W sekcji Właściwości etykiety kliknij Dodaj właściwość, a następnie Dodaj pole.
👉🌐 Konsola – w polu Nazwa pola wpisz total_streams, a w polu Wyrażenie wpisz:
MEASURE(SUM(streams))
👉🌐 Konsola – kliknij Dodaj, a potem Gotowe.

4. Odczytaj napisany kod, a następnie go opublikuj
👉🌐 Konsola – otwórz kartę Kod w panelu po prawej stronie. Modeler napisał za Ciebie instrukcję CREATE PROPERTY GRAPH. Przewiń do węzła Utwory: lista jego właściwości kończy się teraz na
MEASURE(SUM(streams)) AS `total_streams`
To cała funkcja w jednym zdaniu. Wszystko, co następuje po tym kroku, dotyczy działania tego wiersza.

👉🌐 Konsola – kliknij Opublikuj.
✅ Punkt kontrolny: w Eksploratorze music ma teraz folder Wykresy zawierający MusicGraph. Kliknij go: 5 węzłów, 4 krawędzie i linia MEASURE(SUM(streams)) na karcie Kod. Pomiń następny krok i przejdź do sekcji SUM i AGG obok siebie.
4. Tworzenie grafu – opcja B: SQL
Pomiń ten krok, jeśli wykres został utworzony w modelu.
👉📋 Edytor zapytań – wklej zapytanie, a następnie kliknij Uruchom:
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
)
👀 W panelu wyników wyświetla się informacja, że wykres właściwości został utworzony.

Przeczytaj go raz
Graf ma 5 tabel węzłów i 4 tabele krawędzi. Każda tabela węzła zawiera nazwę KEY i listę PROPERTIES. Wiersze zaczynające się od znaku MEASURE to nowa część: każdy z nich zawiera jeden z obsługiwanych agregatów wokół właściwości i nadaje mu alias, który jest wymagany.
Każda tabela krawędzi jest kluczem obcym, co oznacza, że SOURCE KEY w tabeli, która zawiera klucz, a DESTINATION KEY w tabeli, na którą wskazuje. NO PROPERTIES oznacza, że krawędź nie przenosi niczego własnego.
Zwróć uwagę, że pole PlaylistEntries występuje 3 razy: raz jako tabela węzłów i 2 razy jako tabela fizyczna, która jest podstawą krawędzi EntryToSong i EntryToPlaylist. Jest to celowe, a później wyjaśnimy, dlaczego.
Sprawdź, co udało Ci się stworzyć
👉🌐 Konsola – w panelu Eksplorator rozwiń kolejno music, Wykresy i MusicGraph. Strona wykresu otworzy się na obszarze roboczym z 5 węzłami i 4 krawędziami. Kliknij węzeł, aby wyświetlić jego właściwości – miary są wymienione wraz z wartością zagregowaną. Otwórz kartę Kod, aby zobaczyć instrukcję stojącą za obrazem.

✅ Punkt kontrolny: music ma folder Graphs zawierający MusicGraph, a na karcie Kod widać MEASURE(SUM(streams)) AS total_streams.
5. SUM i AGG obok siebie
To cały codelab w jednym zapytaniu. Obie kolumny próbują odpowiedzieć na to samo pytanie – łączna liczba odtworzeń w przypadku wytwórni – na podstawie tej samej tabeli.
Tę tabelę generuje GRAPH_EXPAND. Spłaszcza wykres: zaczyna od jednej tabeli i podąża wzdłuż każdej krawędzi na zewnątrz jako LEFT JOIN, aż wszystkie połączone tabele znajdą się obok siebie w jednym szerokim wyniku. Jeden wiersz na miejsce docelowe, a nie na utwór, a każda kolumna ma nazwę TableLabel_property. Sprawdź go, zanim go wyślesz.
👉📋 Edytor zapytań – wklej zapytanie, a następnie kliknij Uruchom:
SELECT Labels_label_name, Songs_title, Songs_streams, Playlists_playlist_name
FROM GRAPH_EXPAND("music.MusicGraph")
ORDER BY Songs_title, Playlists_playlist_name
👀 Oczekuj 10 wierszy – po jednym na każde miejsce docelowe w pliku PlaylistEntries, czyli dokładnie tyle, ile wczytał moduł konfiguracji. Neon Summer zajmuje 4 z nich, po jednym na każdą playlistę, na której się znajduje, a w każdym z nich liczba odtworzeń wynosi Songs_streams2 000 000 000. Z tymi wierszami nie ma nic złego. Playlisty rzeczywiście mają po 4 filmy. Kolumna należąca do utworu jest teraz powtarzana w wierszach należących do miejsc docelowych. To jest właśnie problem, który mierzy następne zapytanie.
Teraz porównanie.
👉📋 Edytor zapytań – wklej zapytanie, a następnie kliknij Uruchom:
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
👀 Wynik:
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 |

Sprawdź to ręcznie. Cztery utwory Cymbala mają odpowiednio 2,0 miliarda, 1,5 miliarda, 1,2 miliarda i 0,4 miliarda odtworzeń. To 5,1 miliarda. AGG jest prawidłowa. SUM jest 2,5 raza za duży, a pojedynczy utwór Northwind podwoił swoją wielkość.
3 nowe elementy składni
GRAPH_EXPAND("music.MusicGraph")to funkcja zwracająca wartości o typie tabeli, która przekształca wykres w jedną szeroką tabelę, traktując każdą krawędź jakoLEFT JOIN. Każda kolumna ma nazwęTableLabel_property, więcSongs_streamsto kolumna surowa z tabeli Songs, aSongs_total_streamsto zadeklarowana miara.SUM(Songs_streams)to zwykłe zapytanie SQL dotyczące tej szerokiej tabeli, które dziedziczy wszystkie duplikaty powstałe w wyniku spłaszczenia.- Funkcja
AGG(Songs_total_streams)ocenia miarę w sposób, w jaki została zadeklarowana:SUM(streams)raz nasong_id, niezależnie od tego, ile wierszy zajmuje utwór w szerokiej tabeli.
✅ Punkt kontrolny: 2 etykiety, 2 kolumny i liczby with_agg odpowiadające liczbie palców.
6. Dlaczego funkcja SUM zawyża wyniki
Weź jeden utwór i zobacz, jak wpłyną na niego te połączenia.
👉📋 Edytor zapytań – wklej zapytanie, a następnie kliknij Uruchom:
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
👀 Wynik:
kroku | tytuł | odtworzenia | playlista |
PRZED – tabela Utwory | Neonowe lato | 2 000 000 000 | null |
PO – dodano do playlist | Neonowe lato | 2 000 000 000 | Gym Pump |
PO – dodano do playlist | Neonowe lato | 2 000 000 000 | Hot Right Now |
PO – dodano do playlist | Neonowe lato | 2 000 000 000 | Rising Pop |
PO – dodano do playlist | Neonowe lato | 2 000 000 000 | W drogę |

Jeden wiersz został podzielony na cztery. Liczba strumieni nie uległa zmianie – została skopiowana. Dodaj, co kopie robią z Cymbal Records: Neon Summer 2,0 mld na 4 playlistach to 8,0, Paper Crown 1,5 mld na 2 playlistach to 3,0, Double Shot 1,2 na 1 playliście, Slow Arrow 0,4 na 1 playliście. Jest to 12,6 miliarda, czyli liczba SUM. Utwór Northwind's Midnight Drive znajduje się na 2 playlistach, więc 4,5 mld stało się 9,0 mld.
Jest to zwielokrotnienie wyjściowe, a nie błąd w złączeniu. Wiersze playlist są prawdziwe. Błąd polega na zsumowaniu liczby, która należy do utworu, w wierszach należących do miejsc docelowych.
Miara rozwiązuje ten problem, ponieważ została zadeklarowana w węźle Songs razem z KEY (song_id). Kluczem jest ziarno. Gdy funkcja AGG ocenia total_streams, agreguje dane raz na klucz utworu, a dopiero potem sumuje je według wybranego przez Ciebie grupowania.
Co się zmieniło?
Kiedyś pisałeś | Z wskaźnikiem |
|
|
|
|
3 |
|
CTE, która agreguje dane przed złączeniem | Nic. |
✅ Punkt kontrolny: 5 wierszy – 1 PRZED i 4 PO – i możesz z nich odtworzyć 12, 6 miliarda.
7. Reguła: tylko funkcja AGG odczytuje miarę
Miary mają swój własny typ, MEASURE, i tylko jedna funkcja go akceptuje. Poniższe 4 zapytania celowo nie działają – uruchom każde z nich i przeczytaj czerwony komunikat o błędzie. To 4 sposoby, które wszyscy wypróbowują w pierwszej kolejności. Znajomość tych komunikatów pozwoli Ci zaoszczędzić czas.
👉📋 Edytor zapytań – AGG w zwykłej kolumnie:
SELECT AGG(Songs_streams) FROM GRAPH_EXPAND("music.MusicGraph")
👀 No matching signature for aggregate function AGG ... Argument 1: expected MEASURE

👉📋 Edytor zapytań – kolumna miary bez AGG:
SELECT Songs_total_streams FROM GRAPH_EXPAND("music.MusicGraph") LIMIT 1
👀 Returning expressions of type MEASURE is not allowed

👉📋 Edytor zapytań – miara, do której odwołuje się GQL, która nigdy nie widzi miar (jest to zapytanie GQL – zobacz notatkę w wersji w omówieniu):
GRAPH music.MusicGraph
MATCH (s:Songs)
RETURN s.total_streams
LIMIT 1
👀 total_streams is not exposed by element type GRAPH_NODE(...)

👉📋 Edytor zapytań – SUM nad kolumną liczbową, tą kuszącą:
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

System typów wymusza więc przestrzeganie tej reguły. Wskaźnik jest widoczny tylko w usłudze GRAPH_EXPAND i można go odczytać tylko w usłudze AGG. Nadmiarowe 12,6 miliarda z poprzedniego przykładu może pochodzić tylko z sumowania kolumny z danymi pierwotnymi, a nie z nieprawidłowego użycia miary.
✅ Punkt kontrolny: 4 czerwone błędy, z których każdy jest związany z inną regułą.
8. Każda funkcja agregacji obsługiwana przez miarę
MEASURE() obejmuje jedną z 6 wartości zagregowanych: SUM, AVG, MIN, MAX, COUNT i COUNT(DISTINCT). Odtwórz wykres z wszystkimi 6 węzłami w węźle Utwory. Krawędzie pozostają NO PROPERTIES, co jest zalecaną metodą, gdy krawędź współdzieli tabelę fizyczną z węzłem.
👉📋 Edytor zapytań – wklej zapytanie, a następnie kliknij Uruchom:
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
)

Teraz przeczytaj je wszystkie. Każda miara przechodzi przez AGG, a ostatnia kolumna pokazuje, że AGG to zwykłe wartości, z którymi można wykonywać działania arytmetyczne. Wykres właśnie się zmienił, więc najpierw wyczyść opcję Użyj wyników z pamięci podręcznej (Więcej → Ustawienia zapytania).
👉📋 Edytor zapytań – wklej zapytanie, a następnie kliknij Uruchom:
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
👀 Wynik:
Labels_label_name | total_streams | avg_streams | min_streams | max_streams | utwory | wykonawcy | 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 |

Każda liczba jest obliczana na podstawie 4 utworów w przypadku Cymbal i 1 utworu w przypadku Northwind, a nie na podstawie 10 wierszy miejsc docelowych. AVG w szczególności byłoby nieprawidłowe w drugą stronę: uśrednienie surowej kolumny w wierszach miejsc docelowych daje 1,575 mld w przypadku Cymbal, ponieważ 2 mld w przypadku Neon Summer jest liczone 4 razy.
„Zamień SUM na AGG” to w zasadzie 2 decyzje. Gdy deklarujesz miarę, nadal wybierasz, do którego z 6 rodzajów agregacji należy. Gdy odczytujesz miarę, funkcja zawsze ma wartość AGG.
✅ Punkt kontrolny: po jednym wierszu na etykietę, po 7 liczb w każdym wierszu i streams_per_song = avg_streams.
9. Zmień grupowanie, a nie miarę
Ten sam pomiar odpowiada na inne pytanie. Grupuj według playlisty zamiast etykiety.
👉📋 Edytor zapytań – wklej zapytanie, a następnie kliknij Uruchom:
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
👀 Wynik:
Playlists_playlist_name | odtworzenia | utwory |
W drogę | 6 900 000 000 | 3 |
Gym Pump | 6 500 000 000 | 2 |
Hot Right Now | 4 700 000 000 | 3 |
Rising Pop | 3 500 000 000 | 2 |

Dwa wiersze AGG są identyczne z wierszami z sekcji SUM i AGG, obok siebie. Przeniesiono tylko element GROUP BY. Road Trip zawiera utwory Neon Summer, Midnight Drive i Slow Arrow, a każdy z nich jest liczony raz na tej playliście – co dokładnie oznacza „liczba odtworzeń na tej playliście”.
Osoba, która napisała miarę, ustaliła ziarno tylko raz. Każde kolejne zapytanie, niezależnie od tego, kto je wyśle, będzie dziedziczyć tę wartość.
✅ Punkt kontrolny: Road Trip na pierwszym miejscu z 6,9 mld wyświetleń.
10. Zobacz, co daje funkcja GRAPH_EXPAND
Nie musisz uruchamiać GRAPH_EXPAND, aby poznać jego kształt. Procedura systemowa BQ.SHOW_GRAPH_EXPAND_SCHEMA zapisuje listę kolumn w zmiennej.
👉📋 Edytor zapytań – wklej wszystkie 3 wiersze, a potem kliknij Uruchom:
DECLARE schema STRING DEFAULT '';
CALL BQ.SHOW_GRAPH_EXPAND_SCHEMA('music.MusicGraph', schema);
SELECT schema;
👀 Wynikiem jest jeden ciąg JSON. Każde pole ma nazwę, typ i tryb, a każda kolumna miary zawiera "is_measure": true. W przypadku utworzonego wykresu otrzymasz m.in.:
nazwa | typ | is_measure | |
Songs_title | CIĄG ZNAKÓW | ||
Songs_streams | LICZBA CAŁKOWITA | ||
Songs_total_streams | LICZBA CAŁKOWITA | prawda | |
Songs_avg_streams | LICZBA ZMIENNOPRZECINKOWA | prawda | |
Songs_distinct_artists | LICZBA CAŁKOWITA | prawda | |
PlaylistEntries_placement_count | LICZBA CAŁKOWITA | prawda | |

Tutaj będą też widoczne wszystkie opisy i synonimy ustawione w usłudze. Opcjonalny krok czatu pokazuje, kto je czyta.
✅ Punkt kontrolny: ciąg JSON z wartością is_measure w każdej kolumnie zadeklarowanej za pomocą MEASURE.
11. Czego funkcja GRAPH_EXPAND potrzebuje od kształtu grafu
W tym kroku nie ma nic do uruchomienia – wystarczy przeczytać. GRAPH_EXPAND tworzy szeroką tabelę za pomocą łańcucha LEFT JOIN, zaczynając od jednej tabeli i podążając krawędziami na zewnątrz. Wynikają z tego 3 zasady, a MusicGraph spełnia wszystkie z nich.

Dokładnie 1 tabela węzła głównego. Węzeł główny to tabela węzłów, której klucz nie występuje w żadnej innej tabeli – nie wskazuje na niego żadna krawędź. W MusicGraph jest to węzeł PlaylistEntries: źródło 2 krawędzi i miejsce docelowe żadnej. Szeroka tabela ma 10 wierszy, po jednym na każdą lokalizację.
Każda krawędź jest relacją wiele-do-jednego, od źródła do miejsca docelowego. Każdy wpis zawiera 1 utwór i 1 playlistę, każdy utwór ma 1 wykonawcę, a każdy wykonawca ma 1 wytwórnię. Dlatego szeroka tabela nigdy nie rozszerza się poza wiersze węzła głównego. Dane, do których nie ma dostępu element główny, nie są wyświetlane: utwór bez miejsc docelowych nie będzie widoczny w tabeli szerokiej.
Relacje „wiele do wielu” stają się węzłem. Utwory i playlisty są powiązane relacją wiele do wielu. Jeśli zadeklarujesz tabelę złączeń jako pojedynczą krawędź od utworów do playlist, GRAPH_EXPAND zignoruje ją jako niejednoznaczną, a ponieważ nie będzie już żadnych użytecznych krawędzi, operacja się nie powiedzie. Promowanie PlaylistEntries do tabeli węzłów z 2 krawędziami typu „wiele do jednego” jest udokumentowanym wzorcem i właśnie to zrobiono podczas tworzenia wykresu.
12. (OPCJONALNIE) Ścieżki z użyciem GQL
Do tej pory na każde pytanie odpowiadaliśmy liczbą. Ten nie. Gdzie strumienie Cymbala docierają do słuchaczy? to pytanie o trasy w grafie, na które nie można odpowiedzieć za pomocą sumy – gdy ją obliczysz, trasa już nie istnieje.
1. Zapytaj, gdzie kończą się strumienie
👉📋 Edytor zapytań – wklej zapytanie, a następnie kliknij Uruchom:
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
👀 Spodziewaj się 4 playlist:
pl.playlist_name | pl.followers | streams_reaching_this_playlist | utwory |
Hot Right Now | 35 000 000 | 4 700 000 000 | Double Shot, Neon Summer, Paper Crown |
Rising Pop | 2 000 000 | 3 500 000 000 | Neonowe lato, papierowa korona |
W drogę | 5 000 000 | 2 400 000 000 | Neon Summer, Slow Arrow |
Gym Pump | 3 000 000 | 2 000 000 000 | Neonowe lato |

Przeczytaj MATCH jako zdanie: zacznij od wytwórni, przejdź do jej wykonawców, następnie do ich utworów, potem do pozycji na playlistach, na których znajdują się te utwory, a następnie do playlist. Strzałki wskazują kierunek deklarowania krawędzi. Symbol <- oznacza ruch do tyłu.
Teraz dodaj tę trzecią kolumnę. 12,6 mld – liczba SUM podana w kroku 4, czyli ta, która była nieprawidłowa.
Oto ona. Wtedy pytanie brzmiało, ile razy utwór został odtworzony w Cymbalu, i liczył się tylko raz, niezależnie od tego, na ilu playlistach się znajdował. W tym przypadku strumienie docierają do odbiorców, a utwór na 4 playlistach dociera do 4 grup odbiorców. Powielanie GRAPH_EXPAND powoduje błąd w przypadku jednego pytania i odpowiedź na drugie. AGG nigdy nie chodziło o to, że duplikaty są złe – chodziło o dopasowanie działań arytmetycznych do pytania.
2. Zwracanie samych ścieżek
Zrezygnuj z agregacji i poproś o trasy.
👉📋 Edytor zapytań – wklej zapytanie, a następnie kliknij Uruchom:
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 = określa całe dopasowanie, a TO_JSON je renderuje.
👀 Oczekuj 8 wierszy i 1 kolumny path. Każda komórka to tablica JSON zawierająca węzły i krawędzie na jednej trasie. Każdy węzeł zawiera swoje współrzędne labels i properties.

8 wierszy dla 4 utworów, ponieważ trasa istnieje dla każdego miejsca docelowego, a nie dla każdego utworu.
3. Otwórz kartę Wykres
👉🌐 Konsola – nad wynikami kliknij Wykres.
Ta karta pojawia się tylko wtedy, gdy wynik zawiera elementy wykresu. Poprzednie zapytanie zwróciło liczby, więc nie miało karty Wykres. To zapytanie zwraca ścieżki, więc ma tę kartę.

Róg wykresu Cymbal jest rysowany jako układ siłowy z liczbą widocznych węzłów i krawędzi oraz z etykietami. Przeciągnij węzeł, aby rozdzielić układ, lub kliknij go, aby wyświetlić jego właściwości.
✅ Punkt kontrolny: suma w trzeciej kolumnie pierwszego zapytania wynosi 12,6 mld, drugie zapytanie zwraca 8 ścieżek, a karta Wykres je rysuje.
13. (OPCJONALNIE) Czat z wykresem
Na tym etapie nie ma SQL. Agenci danych BigQuery mogą używać wykresu jako źródła wiedzy, a dokumentacja podaje, że do agregacji na wielu poziomach używają miar. Sprawdźmy, czy to prawda.
1. Tworzenie agenta
👉🌐 Konsola – w menu nawigacyjnym BigQuery po lewej stronie kliknij Agenci, a następnie Katalog agentów i Utwórz agenta.
👉🌐 Konsola – w polu Nazwa agenta wpisz Music graph agent, a w polu Opis agenta wpisz:
Ask questions about labels, artists, songs and playlists in the music property graph.
👉🌐 Konsola – w sekcji Źródła wiedzy kliknij Dodaj źródło. W oknie Wybierz źródła rozwiń projekt, a następnie kolejno music, Wykresy i MusicGraph. Zaznacz MusicGraph i kliknij Potwierdź.
👀 Przycisk Dodaj źródło jest wyszarzony. Agent może zawierać maksymalnie 1 wykres i nie może łączyć wykresów z tabelami.

👉🌐 Konsola – pozostaw Region bez zmian. Kliknij kolejno Zapisz i Opublikuj. W panelu Kanały publikacji kliknij Opublikuj agenta i zamknij potwierdzenie.
2. Zadaj pytanie
👉🌐 Konsola – kliknij Utwórz rozmowę. Otworzy się strona czatu. Wpisz to w polu Zadaj pytanie u dołu i naciśnij Enter:
For each label, show total streams and how many playlists their songs are on
👀 Agent zwraca tabelę i podsumowanie w jednym zdaniu:
label_name | total_streams | playlist_placements |
Cymbal Records | 5 100 000 000 | 8 |
Northwind Audio | 4 500 000 000 | 2 |

5,1 miliarda Nikt nie poinformował agenta o zwielokrotnieniu wyjściowym, więc nie zostało ono uwzględnione.
3. Przeczytaj zapytanie, które zostało utworzone
👉🌐 Konsola – w menu nawigacyjnym kliknij Eksplorator zadań i kliknij najnowsze zadanie. Etykiety obejmują ca-bq-job: true i data-agent-id z identyfikatorem agenta, a zapytanie to:
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

Użyła ona samodzielnie symboli GRAPH_EXPAND i AGG, ponieważ miary były w odczytanym przez nią schemacie. W opisie agenta nie ma o nich wzmianki.
✅ Punkt kontrolny: 5, 1 mld w odpowiedzi na czacie i AGG(...) w kodzie SQL zadania.
14. Czyszczenie danych
👉💻 Cloud Shell – usuń zbiór danych, jego tabele i wykres właściwości:
cd ~/bq-graph-measures-lab
./cleanup.sh
👀 Spodziewaj się ✓ dropped YOUR_PROJECT_ID.music (tables and graph).
Jeśli utworzono opcjonalnego agenta danych, usuń go w konsoli w sekcji Agenci → Katalog agentów. Jeśli ./setup_project.sh utworzono projekt specjalnie na potrzeby tego laboratorium, najprostszym sposobem na jego usunięcie jest wyłączenie całego projektu – identyfikator znajduje się w ~/project_id.txt.
15. Gratulacje
Zadeklarowano 1 wiersz, MEASURE(SUM(streams)), który zmienił wartość 12,6 mld na 5,1 mld – dla Ciebie i dla każdego zapytania, które ktoś później napisze w odniesieniu do tego wykresu, w tym dla zapytań napisanych przez agenta.
Czego się dowiedzieliśmy
- Miara to agregacja zadeklarowana w węźle obok symbolu
KEY, który określa jej ziarnistość. GRAPH_EXPANDspłaszcza wykres do jednej szerokiej tabeli zTableLabel_propertykolumnami.AGGto jedyna funkcja, która odczytuje miarę, a system typów wymusza to na 4 różne sposoby.- Dostępnych jest 6 rodzajów agregacji, a wyniki
AGGto zwykłe wartości, które można dzielić. - Zmiana
GROUP BYpowoduje ponowne zadanie pytania bez dotykania pomiaru. GRAPH_EXPANDchce, aby jeden węzeł główny, krawędzie typu „wiele do jednego” i skrzyżowania były promowane do węzłów.
Tabela decyzji
Krótki opis problemu | Przyczyna | Napraw |
zbyt duża suma, |
| zadeklarować miarę, odczytać ją za pomocą |
„oczekiwano MEASURE, znaleziono INT64” |
| użyj |
„Nie można zwracać wyrażeń typu MEASURE” | kolumna pomiaru bez | pakuj: |
„nie jest udostępniana przez typ elementu” | miara, do której odwołuje się GQL; | mierzy tylko czas spędzony na żywo za |
| skrzyżowanie modelowane jako krawędź, | promować tabelę złączeń do węzła, |
stary numer po zmianie wykresu; | wynik z pamięci podręcznej, | wyczyść opcję Użyj wyników z pamięci podręcznej. |
Czego nie omówiliśmy (celowo)
Opisy i synonimy w usługach, zweryfikowane zapytania i słowniczki dla agentów danych, GQL w więcej niż 1 MATCH, miary w więcej niż 1 wykresie. Każde z nich jest osobnym laboratorium.
Więcej informacji
- Praca z rodzajami danych
- Tworzenie wykresu właściwości i wysyłanie do niego zapytań
- Omówienie analityki konwersacyjnej
- Repozytorium laboratorium – wszystkie zapytania w tym ćwiczeniu, ponumerowane według kroków.