1. Visão geral
A maioria dos bugs de SQL que sobrevivem à revisão de código são bugs de agregação. Um número está correto na tabela em que está, uma junção o copia e o total está errado.
Com o BigQuery Graph, você descreve como as tabelas se conectam uma vez, como um gráfico de propriedades, e depois consulta as conexões. As medidas de gráfico adicionam mais uma coisa a essa descrição: a própria agregação. Você declara MEASURE(SUM(streams)) no nó que possui o número, e toda consulta que lê o gráfico recebe o total correto no nível certo. Não há truque de GROUP BY nem CTE que alguém precise lembrar.
Neste codelab, você vai criar um catálogo de músicas com cinco tabelas, adicionar uma métrica a ele e ver a mesma pergunta retornar duas respostas diferentes: 12,6 bilhões com SUM e 5,1 bilhões com AGG. A lacuna é o formato do catálogo: uma música que está em quatro playlists se torna quatro linhas quando o gráfico é achatado, e SUM adiciona todas as quatro. Em seguida, você aprende as regras que tornam a segunda opção correta.

Onde você vai digitar
Este laboratório usa exatamente dois lugares, nesta ordem:
onde | o que você faz lá | |
1 | Terminal do Cloud Shell | alguns comandos, apenas na etapa Configuração |
2 | Console do BigQuery | Todo o resto: colar consultas no editor de consultas, clicar no modelador de gráficos, conversar com um agente |
Cada instrução é marcada para que você sempre saiba o que ela significa:
- 👉💻 Cloud Shell: digite isso no terminal do Cloud Shell.
- 👉📋 Editor de consultas: cole isso no editor de consultas do BigQuery e clique em Executar.
- 👉🌐 Console: clique no console do BigQuery. Não digite nada, a menos que a etapa diga o contrário.
- 👀: confira o resultado.
O que você vai aprender
- Como declarar uma métrica em uma tabela de nós no modelador gráfico visual ou em SQL
- Como o
GRAPH_EXPANDnivela um gráfico em uma tabela ampla - Por que
AGGé a única função que pode ler uma métrica e o que todas as outras tentativas dizem - Os seis agregados que uma métrica aceita e como fazer cálculos aritméticos com eles
- Como uma medida responde a uma pergunta agrupada de forma diferente sem mudanças
- Opcional: como a GQL e a guia "Gráfico" respondem a uma pergunta que um total não consegue, e como um agente de dados do BigQuery usa suas métricas sem que você precise informá-las.
O que é necessário
- Uma Conta do Google com faturamento disponível e um navegador. Você não precisa de um projeto na nuvem do Google Cloud de imediato. A configuração cria um para você.
- Somente para a etapa de chat opcional: a API Gemini Data Analytics ativada e o papel Criador do agente de dados do Gemini Data Analytics.
Não é necessário instalar nada na sua máquina. Tudo é executado no Cloud Shell e no console do BigQuery.
Status e custo do produto
O BigQuery Graph está disponível para todos. As medidas de gráfico, o modelador de gráficos visuais, a visualização de gráficos e o uso de um gráfico como fonte de conhecimento de um agente de dados estão em prévia, cobertos pelos Termos de ofertas pré-GA.
GRAPH_EXPAND e AGG são executados com preços sob demanda. As consultas GQL (a etapa opcional de caminho) exigem uma reserva que use a edição Enterprise ou Enterprise Plus, de acordo com a documentação. Por isso, essa etapa é opcional.
O conjunto de dados tem alguns kilobytes. Com o sistema de preços sob demanda, cada consulta é faturada com o mínimo de 10 MB. Assim, todo o codelab custa uma fração de um centavo.
2. Configuração
Esta é a única etapa que usa o Cloud Shell. Ele cria um projeto, ativa o faturamento nele e cria as tabelas brutas. O gráfico, a métrica e todas as consultas podem ser executados depois no console do BigQuery.
Há uma coisa que este laboratório não pode oferecer: um projeto na nuvem do Google Cloud com faturamento ativado. A etapa 1 cria uma conta que pode pagar por ele, e a etapa 4 transforma essa conta em um projeto. Faça isso nessa ordem. Cada etapa depois da 4 lê o projeto que a etapa 4 cria.
1 · Receber uma conta com faturamento (~1 min)
👉🌐 Faça isso antes de qualquer outra coisa. Faça login com uma Conta do Google que tenha o faturamento ativado. Qualquer uma delas funciona. Se não tiver, inicie um teste sem custo financeiro. Ele oferece uma conta de faturamento, que é tudo o que a etapa 4 precisa.
2 · Abra o Cloud Shell (~1 min)
👉🌐 Console: clique em Ativar o Cloud Shell na parte de cima do console do Google Cloud. É o ícone em forma de terminal no cabeçalho. Um terminal é aberto na parte de baixo da página.

👉🌐 Console: se for necessário autorizar em algum momento hoje, clique em Autorizar para continuar.
👉💻 Cloud Shell: verifique com qual conta o Cloud Shell está conectado:
gcloud auth list
👀 Espere que sua conta seja marcada com um * e que seja a mesma conta em que você fez login na etapa 1. Caso contrário, execute gcloud auth login e escolha a opção correta.
3 · Faça o laboratório (~1 min)
👉💻 Cloud Shell: clone o repositório:
cd ~
rm -rf ~/bq-graph-measures-lab
git clone https://github.com/cuppibla/bq-graph-measures-lab.git
cd ~/bq-graph-measures-lab
4 · Crie seu projeto (~2 min)
👉💻 Cloud Shell: um script encontra sua conta de faturamento, cria um projeto nela e aponta o Cloud Shell para esse projeto:
cd ~/bq-graph-measures-lab
./setup_project.sh
👀 Espere um ✓ para a conta de faturamento escolhida, um ✓ para o projeto criado e uma finalização como:
Project ready: bq-graph-4271 Next: ./setup.sh
bq-graph-4271 é o ID do projeto, que terá dígitos diferentes. Quatro coisas acontecem lá:
faturamento | usa a conta | |
project | cria o | |
seleciona | grava o ID em | |
waits | faz pesquisas até que o novo projeto seja autorizado a veicular, por até dois minutos | |
🌐 O mesmo projeto agora está no console. O ID dele fica no card Informações do projeto no painel:

5 · Criar o conjunto de dados (~3 min)
👉💻 Cloud Shell: mais um script cria as tabelas:
cd ~/bq-graph-measures-lab
./setup.sh
O script imprime cada etapa à medida que é executado. O que ele faz, em ordem:
project | lê o projeto de | |
API | ativa o | |
dataset | cria o conjunto de dados | |
check | conta as linhas em todas as tabelas e para se alguma contagem estiver errada | |
👀 Expect:
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
Você terminou de usar o Cloud Shell. Você pode fechar.
6 · Abrir o BigQuery e um editor de consultas
👉🌐 Console: clique no link no final da saída ou abra o BigQuery no menu de navegação. No painel Explorer à esquerda, expanda seu projeto: um conjunto de dados music com cinco tabelas.

👉🌐 Console: na parte de cima do BigQuery Studio, na linha Criar novo, clique em Consulta SQL. Uma guia vazia do editor será aberta.

Mantenha esta guia. Todos os blocos 👉📋 deste laboratório vão aqui:selecione o que estiver no editor, cole o novo bloco por cima e clique em Executar. O resultado aparece no painel abaixo.
Conheça as tabelas
Duas coisas sobre essas tabelas são importantes mais tarde. Cada tabela declara sua chave primária como NOT ENFORCED. O BigQuery não verifica isso, mas o gráfico de propriedades que você vai criar precisa de uma chave explícita para saber o que identifica uma linha. A última tabela, PlaylistEntries, é uma tabela de junção: uma música que está em quatro playlists tem quatro linhas nela. É nessa tabela que toda a história acontece.
As tabelas são encadeadas assim: uma gravadora assina com artistas, um artista lança músicas, uma música é colocada em playlists usando PlaylistEntries. A Cymbal Records é proprietária de Ava Sterling e Mina Okafor, e, por isso, de quatro músicas. A Northwind Audio é proprietária de Kai Nakamura e de uma música, "Midnight Drive".
tabela | linhas | chave | o que ele contém |
Rótulos | 2 |
| name, marketing budget |
Artistas | 3 |
| nome, qual rótulo |
Músicas | 5 |
| título, artista, streams |
Playlists | 4 |
| name, followers |
PlaylistEntries | 10 |
| qual música está em qual playlist |
✅ Checkpoint : 🎉 ready no Cloud Shell, cinco tabelas em music no Explorer e uma guia vazia do editor de consultas aberta.
3. Criar o gráfico: opção A (modelador visual)
Um gráfico de propriedades é uma descrição de como as tabelas se conectam. Você pode clicar nele no modelador de gráficos visuais (esta etapa, todos os cliques) ou escrever como SQL (a próxima etapa, uma colagem). Ambos produzem o mesmo objeto. Faça um ou outro, não os dois.
1. Criar o shell do gráfico
👉🌐 Console: no BigQuery Studio, na linha Criar novo, abra o menu IA e conhecimento e clique em Gráfico.
👉🌐 Console: insira MusicGraph como o Nome do gráfico e music como o Destino do gráfico no conjunto de dados. A região é preenchida com base no conjunto de dados (EUA).
👉🌐 Console: em Fontes de dados, selecione as cinco tabelas (Artists, Labels, PlaylistEntries, Playlists, Songs) e clique em Criar.

👀 A tela abre com cinco nós coloridos e sem linhas entre eles. O painel Detalhes à direita lista Nós (5) e Arestas (0). Cada nó já tem a chave primária da tabela e todas as colunas como propriedades. Clique em qualquer nó para conferir.

2. Desenhe as quatro bordas
Uma aresta é uma chave estrangeira desenhada. Cada uma vai da tabela que contém a chave para a tabela a que ela aponta.
👉🌐 Console: clique em Nova borda. Na caixa de diálogo Selecionar tabela, escolha PlaylistEntries e clique em Adicionar. No painel Adicionar aresta:
- Defina o Nome como
EntryToSong. - Clique em Adicionar chave primária e aceite
entry_id. - Em Origem, defina Nó de origem como PlaylistEntries. Em seguida, use Adicionar colunas referenciadas ao nó e Adicionar colunas referenciadas na aresta para escolher
entry_idem ambos. - Em Destino, defina Nó de destino como "Músicas" e escolha
song_idpara Colunas referenciadas no nó e Colunas referenciadas na aresta. - Clique em Concluído.

👉🌐 Console: repita mais três vezes:
nome da borda | tabela | nó de origem → nó de destino | a coluna para escolher nos dois lados |
| PlaylistEntries | PlaylistEntries → Playlists | origem |
| Músicas | Músicas → Artistas | origem |
| Artistas | Artistas → Gravadoras | origem |
Deixe todas as arestas sem propriedades extras.
👀 O painel "Detalhes" agora mostra Arestas (4), e a tela mostra a cadeia: Labels ← Artists ← Songs ← PlaylistEntries → Playlists.

3. Adicionar a medida
👉🌐 Console: clique no nó Músicas e depois no ícone Editar (lápis) na parte de cima do painel "Detalhes". Em Propriedades do rótulo, clique em Adicionar propriedade e depois em Adicionar campo.
👉🌐 Console: insira total_streams como o Nome do campo e digite isso na caixa Expressão:
MEASURE(SUM(streams))
👉🌐 Console: clique em Adicionar e em Concluído.

4. Leia o código que ele escreveu e publique
👉🌐 Console: abra a guia Código no painel à direita. O modelador escreveu a instrução CREATE PROPERTY GRAPH para você. Role até o nó "Músicas": a lista de propriedades agora termina com
MEASURE(SUM(streams)) AS `total_streams`
Esse é o recurso completo, em uma linha. Tudo depois dessa etapa é sobre o que essa linha faz.

👉🌐 Console: clique em Publicar.
✅ Checkpoint:no Explorer, music agora tem uma pasta Gráficos que contém MusicGraph. Clique nele: cinco nós, quatro arestas e a linha MEASURE(SUM(streams)) na guia "Código". Pule a próxima etapa e acesse SOMA e AGG, lado a lado.
4. Criar o gráfico — Opção B: SQL
Pule esta etapa se você criou o gráfico no modelador.
👉📋 Editor de consultas: cole e clique em Executar:
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
)
👀 O painel de resultados informa que o gráfico de propriedades foi criado.

Ler uma vez
O gráfico tem cinco tabelas de nós e quatro tabelas de arestas. Cada tabela de nós nomeia o KEY e lista o PROPERTIES. As linhas que começam com MEASURE são a nova parte: cada uma envolve um dos agregados compatíveis em uma propriedade e atribui um alias a ela, o que é obrigatório.
Cada tabela de aresta é uma chave externa, explicada assim: SOURCE KEY na tabela que contém a chave e DESTINATION KEY na tabela para onde ela aponta. NO PROPERTIES significa que a aresta não carrega nada próprio.
Observe que PlaylistEntries aparece três vezes: uma como uma tabela de nós e mais duas como a tabela física por trás das arestas EntryToSong e EntryToPlaylist. Isso é proposital, e vamos explicar o motivo mais tarde.
Olha só o que você fez
👉🌐 Console: no painel Explorer, expanda music, depois Gráficos e clique em MusicGraph. A página de gráfico é aberta em uma tela com cinco nós e quatro arestas. Clique em um nó para conferir as propriedades dele. As medidas são listadas com o agregado. Abra a guia Código para ver a declaração por trás da imagem.

✅ Ponto de verificação: music tem uma pasta Gráficos que contém MusicGraph, e a guia "Código" mostra MEASURE(SUM(streams)) AS total_streams.
5. SUM e AGG lado a lado
Este é o codelab inteiro em uma consulta. As duas colunas tentam responder à mesma pergunta (total de transmissões por rótulo) da mesma tabela.
Essa é a tabela que o GRAPH_EXPAND gera. Ele achata o gráfico: começa em uma tabela e segue cada aresta para fora como um LEFT JOIN, até que todas as tabelas conectadas fiquem lado a lado em um único resultado amplo. Uma linha por posição, não uma por música, e todas as colunas nomeadas TableLabel_property. Analise antes de consultar.
👉📋 Editor de consultas: cole e clique em Executar:
SELECT Labels_label_name, Songs_title, Songs_streams, Playlists_playlist_name
FROM GRAPH_EXPAND("music.MusicGraph")
ORDER BY Songs_title, Playlists_playlist_name
👀 Espere 10 linhas, uma para cada posição em PlaylistEntries, que é exatamente o que a configuração carregou. O Neon Summer ocupa quatro delas, uma por playlist em que está, e Songs_streams tem 2.000.000.000 em cada uma. Não há nada de errado com essas linhas. As playlists são quatro mesmo. Mas uma coluna que pertence a uma música agora é repetida em linhas que pertencem a posições, e esse é o problema que a próxima consulta mede.
Agora a comparação.
👉📋 Editor de consultas: cole e clique em Executar:
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
👀 Resultado:
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 |

Verifique manualmente. As quatro músicas do Cymbal têm 2 bilhões, 1,5 bilhão, 1,2 bilhão e 0,4 bilhão de streams. Isso é 5,1 bilhões. AGG está correto. SUM é duas vezes e meia maior, e a única música da Northwind dobrou.
Três novas sintaxes
GRAPH_EXPAND("music.MusicGraph")é uma função com valor de tabela que transforma o gráfico em uma tabela ampla, seguindo cada aresta como umLEFT JOIN. Todas as colunas são chamadas deTableLabel_property. Portanto,Songs_streamsé a coluna bruta da tabela "Músicas", eSongs_total_streamsé a métrica que você declarou.SUM(Songs_streams)é um SQL comum nessa tabela ampla e herda todos os duplicados produzidos pelo nivelamento.- O
AGG(Songs_total_streams)avalia a métrica da maneira como ela foi declarada:SUM(streams)uma vez porsong_id, não importa quantas linhas uma música ocupe na tabela ampla.
✅ Ponto de verificação:dois rótulos, duas colunas e os números with_agg correspondem à contagem manual.
6. Por que a função SUM faz contagens excessivas
Pegue uma música e veja o que essas junções fazem com ela.
👉📋 Editor de consultas: cole e clique em Executar:
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
👀 Resultado:
etapa | título | de aplicativos. | playlist |
ANTES: a tabela "Songs" | Verão neon | 2.000.000.000 | null |
DEPOIS: adicionado às playlists | Neon Summer | 2.000.000.000 | Gym Pump |
DEPOIS: adicionado às playlists | Neon Summer | 2.000.000.000 | Em alta agora |
DEPOIS: adicionado às playlists | Neon Summer | 2.000.000.000 | Rising Pop |
DEPOIS: adicionado às playlists | Neon Summer | 2.000.000.000 | Na estrada |

Uma linha se tornou quatro. A contagem de transmissões não mudou, ela foi copiada. Some o que as cópias fazem pela Cymbal Records: Neon Summer 2.0 bilhões em quatro playlists é 8,0, Paper Crown 1,5 bilhão em duas é 3,0, Double Shot 1,2 em uma, Slow Arrow 0,4 em uma. Esse é o número 12,6 bilhões, o número SUM retornado. "Midnight Drive", da Northwind, está em duas playlists, então 4,5 bilhões se tornaram 9 bilhões.
Isso é distribuição de dados e não um bug na junção. As linhas da playlist são reais. O erro é somar um número que pertence a uma música em linhas que pertencem a posições.
A medida corrige isso porque foi declarada no nó "Songs" junto com KEY (song_id). A chave é a granularidade. Quando AGG avalia total_streams, ele agrega uma vez por chave de música e só então faz o resumo de acordo com o que você agrupou.
O que mudou
Você costumava escrever | Com uma medida |
|
|
|
|
Três |
|
Uma CTE que agrega antes de fazer a junção | Nada O |
✅ Checkpoint:cinco linhas (uma ANTES, quatro DEPOIS), e você pode reconstruir 12,6 bilhões com elas.
7. A regra: somente AGG lê uma métrica
As métricas têm um tipo próprio, MEASURE, e exatamente uma função as aceita. As quatro consultas abaixo falham de propósito. Execute cada uma delas e leia o erro em vermelho. Essas são as quatro maneiras que todo mundo tenta primeiro, e saber o que elas dizem economiza tempo depois.
👉📋 Editor de consultas — AGG em uma coluna simples:
SELECT AGG(Songs_streams) FROM GRAPH_EXPAND("music.MusicGraph")
👀 No matching signature for aggregate function AGG ... Argument 1: expected MEASURE

👉📋 Editor de consultas: uma coluna de métrica sem AGG:
SELECT Songs_total_streams FROM GRAPH_EXPAND("music.MusicGraph") LIMIT 1
👀 Returning expressions of type MEASURE is not allowed

👉📋 Editor de consultas: uma métrica referenciada em GQL, que nunca vê métricas (esta é uma consulta GQL. Consulte a nota de edição na visão geral):
GRAPH music.MusicGraph
MATCH (s:Songs)
RETURN s.total_streams
LIMIT 1
👀 total_streams is not exposed by element type GRAPH_NODE(...)

👉📋 Editor de consultas: SUM em uma coluna de métricas, a mais tentadora:
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

Assim, o sistema de tipos aplica a regra para você. Uma métrica só fica visível no GRAPH_EXPAND e pode ser lida no AGG. Os 12,6 bilhões superestimados de antes só podem vir da soma da coluna bruta, nunca do mau uso da métrica.
✅ Checkpoint:quatro erros vermelhos, e você pode dizer qual regra cada um está aplicando.
8. Cada agregação que uma métrica aceita
MEASURE() envolve um de seis agregados: SUM, AVG, MIN, MAX, COUNT e COUNT(DISTINCT). Recrie o gráfico com todos os seis no nó "Músicas". As arestas permanecem NO PROPERTIES, que é a prática recomendada documentada quando uma aresta compartilha a tabela física com um nó.
👉📋 Editor de consultas: cole e clique em Executar:
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
)

Agora, leia todas elas. Todas as medidas passam por AGG, e a última coluna mostra que os resultados de AGG são valores comuns com que você pode fazer cálculos aritméticos. O gráfico acabou de mudar. Portanto, primeiro desmarque Usar resultados em cache (Mais → Configurações de consulta).
👉📋 Editor de consultas: cole e clique em Executar:
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
👀 Resultado:
Labels_label_name | total_streams | avg_streams | min_streams | max_streams | músicas | artistas | 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 |

Cada número é calculado em quatro músicas para Cymbal e uma para Northwind, não nas dez linhas de posição. AVG, em particular, teria sido errado de outra forma: a média da coluna bruta nas linhas de posição dá 1,575 bilhão para Cymbal, porque os 2 bilhões de Neon Summer são contados quatro vezes.
Portanto, "trocar SUM por AGG" são duas decisões. Ao declarar a métrica, você ainda escolhe qual dos seis agregados ela é. Ao ler, a função é sempre AGG.
✅ Checkpoint:uma linha por marcador, sete números cada e streams_per_song igual a avg_streams.
9. Mude o agrupamento, não a métrica
A mesma métrica responde a uma pergunta diferente. Agrupe por playlist em vez de rótulo.
👉📋 Editor de consultas: cole e clique em Executar:
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
👀 Resultado:
Playlists_playlist_name | de aplicativos. | músicas |
Na estrada | 6.900.000.000 | 3 |
Gym Pump | 6.500.000.000 | 2 |
Em alta agora | 4.700.000.000 | 3 |
Rising Pop | 3.500.000.000 | 2 |

As duas linhas AGG são exatamente as mesmas de SUM e AGG, lado a lado. Somente o GROUP BY foi movido. A playlist Road Trip tem Neon Summer, Midnight Drive e Slow Arrow, e cada música conta uma vez dentro dela. É exatamente isso que "streams que chegam a esta playlist" significa.
A pessoa que escreveu a métrica decidiu o nível de detalhe uma vez. Todas as consultas posteriores, de qualquer pessoa, herdam essa configuração.
✅ Checkpoint:Road Trip no topo com 6,9 bilhões.
10. Confira o que a GRAPH_EXPAND oferece
Não é necessário executar GRAPH_EXPAND para aprender o formato dele. O procedimento do sistema BQ.SHOW_GRAPH_EXPAND_SCHEMA grava a lista de colunas em uma variável.
👉📋 Editor de consultas: cole as três linhas e clique em Executar:
DECLARE schema STRING DEFAULT '';
CALL BQ.SHOW_GRAPH_EXPAND_SCHEMA('music.MusicGraph', schema);
SELECT schema;
👀 O resultado é uma string JSON. Cada campo tem um nome, um tipo e um modo, e cada coluna de métrica carrega "is_measure": true. Para o gráfico que você acabou de criar, você recebe estes dados, entre outros:
nome | tipo | is_measure | |
Songs_title | STRING | ||
Songs_streams | INTEGER | ||
Songs_total_streams | INTEGER | verdadeiro | |
Songs_avg_streams | FLOAT | verdadeiro | |
Songs_distinct_artists | INTEGER | verdadeiro | |
PlaylistEntries_placement_count | INTEGER | verdadeiro | |

Qualquer descrição ou sinônimo definido em uma propriedade também aparece aqui. A etapa de chat opcional mostra quem lê essas informações.
✅ Checkpoint:uma string JSON com is_measure em todas as colunas declaradas com MEASURE.
11. O que o GRAPH_EXPAND precisa da forma de um gráfico
Não há nada para executar nesta etapa, apenas leia. O GRAPH_EXPAND cria a tabela ampla com uma cadeia de LEFT JOINs, começando em uma tabela e seguindo as bordas para fora. Três regras decorrem disso, e o MusicGraph atende a todas elas.

Exatamente uma tabela de nós raiz. A raiz é a tabela de nós cuja chave não aparece em nenhuma outra tabela, ou seja, aquela a que nenhuma aresta aponta. No MusicGraph, esse nó é PlaylistEntries: a origem de duas arestas e o destino de nenhuma. A tabela ampla tem 10 linhas, uma por posição.
Cada aresta é de muitos para um, da origem para o destino. Cada entrada tem uma música e uma playlist, cada música tem um artista, e cada artista tem uma gravadora. É por isso que a tabela ampla nunca se estende além das linhas da raiz. Os dados que a raiz não pode alcançar não aparecem: uma música sem canais não apareceria na tabela ampla.
As relações de muitos para muitos se tornam um nó. As músicas e playlists são de muitos para muitos. Se você declarou a tabela de junção como uma única aresta de "Músicas" para "Playlists", o GRAPH_EXPAND a ignoraria por ser ambígua. Sem arestas utilizáveis, ele falharia. Promover PlaylistEntries a uma tabela de nós com muitas arestas de muitos para um é o padrão documentado, e foi o que você fez ao criar o gráfico.
12. (OPCIONAL) Caminhos com GQL
Todas as perguntas até agora tiveram um número como resposta. Este não. Onde as transmissões do Cymbal alcançam os ouvintes? é uma pergunta sobre rotas no gráfico, e um total não pode responder a ela. Quando você soma, a rota desaparece.
1. Perguntar onde as transmissões são exibidas
👉📋 Editor de consultas: cole e clique em Executar:
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
👀 Você vai encontrar quatro playlists:
pl.playlist_name | pl.followers | streams_reaching_this_playlist | músicas |
Em alta agora | 35.000.000 | 4.700.000.000 | Double Shot, Neon Summer, Paper Crown |
Rising Pop | 2.000.000 | 3.500.000.000 | Neon Summer, Paper Crown |
Na estrada | 5.000.000 | 2.400.000.000 | Neon Summer, Slow Arrow |
Gym Pump | 3.000.000 | 2.000.000.000 | Neon Summer |

Leia a linha MATCH como uma frase: comece em um rótulo, volte para os artistas, para as músicas, para as entradas da playlist em que essas músicas estão e avance para as playlists. As setas apontam para a maneira como as bordas foram declaradas. <- anda para trás.
Agora some essa terceira coluna. 12,6 bilhões: o número que SUM informou na etapa quatro, que estava errado.
Aqui está a resposta certa. Naquela época, a questão era quanto a Cymbal transmitia, e uma música era contabilizada uma vez, não importa em quantas playlists ela estivesse. Essa pergunta é onde esses streams chegam, e uma música em quatro playlists realmente alcança quatro públicos-alvo. A duplicação GRAPH_EXPAND produz um erro para uma pergunta e a resposta para a outra. O AGG nunca foi sobre duplicatas serem ruins, mas sim sobre corresponder a aritmética à pergunta.
2. Retornar os próprios caminhos
Remova a agregação e peça as rotas.
👉📋 Editor de consultas: cole e clique em Executar:
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 = nomeia a correspondência inteira, e TO_JSON a renderiza.
👀 Expect 8 linhas, uma coluna path. Cada célula é uma matriz JSON dos nós e arestas ao longo de uma rota, e cada nó carrega seus labels e properties.

Oito linhas para quatro músicas, porque existe uma rota por posição, não por música.
3. Abra a guia "Gráfico".
👉🌐 Console: acima dos resultados, clique em Gráfico.
Essa guia só aparece quando um resultado contém elementos de gráfico. A consulta anterior retornou números, então não tinha uma guia "Gráfico". Esta retorna caminhos, então tem.

Você recebe o canto do gráfico do Cymbal desenhado como um layout de força, com uma contagem dos nós e bordas em exibição e um ícone por rótulo. Arraste um nó para separar o layout ou clique em um para ler as propriedades dele.
✅ Checkpoint:a terceira coluna da primeira consulta soma 12,6 bilhões, a segunda consulta retorna oito caminhos, e a guia "Gráfico" os mostra.
13. (OPCIONAL) Conversar com o gráfico
Não há SQL nesta etapa. Os agentes de dados do BigQuery podem usar um gráfico como fonte de conhecimento, e a documentação diz que eles usam medidas para agregação multinível. Vamos ver se isso é verdade.
1. Criar um agente
👉🌐 Console: no menu de navegação do BigQuery à esquerda, clique em Agentes, Catálogo de agentes e Criar agente.
👉🌐 Console: digite Music graph agent em Nome do agente e isto em Descrição do agente:
Ask questions about labels, artists, songs and playlists in the music property graph.
👉🌐 Console: em Fontes de conhecimento, clique em Adicionar fonte. Na caixa de diálogo Selecionar fontes, expanda seu projeto, music, Gráficos, marque MusicGraph e clique em Confirmar.
👀 O botão Adicionar fonte fica cinza. Um agente pode conter no máximo um gráfico e não pode misturar gráficos com tabelas.

👉🌐 Console: deixe a Região como foi definida no local do gráfico. Clique em Salvar e em Publicar. No painel Canais de publicação, clique em Publicar agente e feche a confirmação.
2. Faça a pergunta
👉🌐 Console: clique em Criar conversa. Uma página de chat é aberta. Digite isso na caixa Fazer uma pergunta na parte de baixo e pressione Enter:
For each label, show total streams and how many playlists their songs are on
👀 O agente retorna uma tabela e um resumo de uma frase:
label_name | total_streams | playlist_placements |
Cymbal Records | 5.100.000.000 | 8 |
Northwind Audio | 4.500.000.000 | 2 |

5,1 bilhões. Ninguém falou sobre distribuição de dados para o agente, e ele não se enquadrou nisso.
3. Ler a consulta que ele escreveu
👉🌐 Console: no menu de navegação, clique em Explorador de jobs e no job mais recente. Os rótulos incluem ca-bq-job: true e data-agent-id com o ID do seu agente, e a consulta é:
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

Ele usou GRAPH_EXPAND e AGG por conta própria, porque as medidas estavam no esquema que ele leu. Nada na descrição do agente menciona você.
✅ Checkpoint:5, 1 bilhões na resposta do chat e AGG(...) no SQL do job.
14. Limpar
👉💻 Cloud Shell: solte o conjunto de dados, as tabelas e o gráfico de propriedades:
cd ~/bq-graph-measures-lab
./cleanup.sh
👀 Espere ✓ dropped YOUR_PROJECT_ID.music (tables and graph).
Se você criou o agente de dados opcional, exclua-o no console em Agentes → Catálogo de agentes. Se ./setup_project.sh criou um projeto apenas para este laboratório, a limpeza mais organizada de todas é encerrar todo o projeto. O ID está em ~/project_id.txt.
15. Parabéns
Você declarou uma linha, MEASURE(SUM(streams)), e ela mudou 12,6 bilhões para 5,1 bilhões, para você e para todas as consultas que alguém escrever nesse gráfico depois, incluindo as que um agente escrever.
O que você aprendeu
- Uma métrica é um agregado declarado em um nó, ao lado da
KEYque define o nível de detalhe dela. GRAPH_EXPANDnivela o gráfico em uma tabela ampla comTableLabel_propertycolunas.AGGé a única função que lê uma métrica, e o sistema de tipos a aplica de quatro maneiras diferentes.- Seis agregações estão disponíveis, e os resultados de
AGGsão valores comuns que podem ser divididos. - Mudar o
GROUP BYfaz com que a pergunta seja feita novamente sem afetar a métrica. GRAPH_EXPANDquer uma raiz, arestas de muitos para um e junções promovidas a nós.
A tabela de decisão
Sintoma | Causa | Correção |
Um total muito grande |
| declarar uma métrica e lê-la com |
"expected MEASURE, found INT64" |
| use |
"Não é permitido retornar expressões do tipo MEASURE" | coluna de medida sem | unir: |
"não exposto pelo tipo de elemento" | Métrica referenciada no GQL | mede o atraso em relação a |
| junção modelada como uma aresta | promover a tabela de junção a um nó |
Um número antigo depois de mudar o gráfico | resultado em cache | desmarque Usar resultados em cache |
O que não abordamos (de propósito)
Descrições e sinônimos em propriedades, consultas verificadas e glossários para agentes de dados, GQL além de um MATCH, medidas em mais de um gráfico. Cada um é um laboratório independente.
Saiba mais
- Trabalhar com medidas
- Criar e consultar um gráfico de propriedades
- Visão geral da análise conversacional
- O repositório do laboratório: todas as consultas deste codelab, numeradas por etapa