Skip to main content

bigquery-graph-query

Provides guidelines and best practices for querying BigQuery property graphs and semantic graphs: native GQL (Graph Query Language) pattern matching, multi-hop and variable-length paths, aggregation, top-N, path extraction, output formatting (graph visualization with TO_JSON vs tabular), GRAPH_TABLE relational SQL integration, and semantic graph querying via the GRAPH_EXPAND TVF with starting-node view selection and AGG() measures. Also covers hybrid semantic search, combining `VECTOR_SEARCH` candidate generation with graph traversal when a node carries an embedding-backed property. Use when querying graph topology, node/edge connections, paths, or semantic measures over an existing BigQuery graph. Don't use for Cypher or non-BigQuery graph databases, or for creating/modifying a graph schema.

Source facts

Repository
GoogleCloudPlatform/data-agent-kit-plugin
Last source activity
September 29, 2026 at 04:01
Detected SKILL.md language
English
Stars
240
Forks
69

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
5 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
bigquery-graph-query
license
Apache-2.0
metadata
{"version":"v2","publisher":"google"}
description
Provides guidelines and best practices for querying BigQuery property graphs and semantic graphs: native GQL (Graph Query Language) pattern matching, multi-hop and variable-length paths, aggregation, top-N, path extraction, output formatting (graph visualization with TO_JSON vs tabular), GRAPH_TABLE relational SQL integration, and semantic graph querying via the GRAPH_EXPAND TVF with starting-node view selection and AGG() measures. Also covers hybrid semantic search, combining `VECTOR_SEARCH` candidate generation with graph traversal when a node carries an embedding-backed property. Use when querying graph topology, node/edge connections, paths, or semantic measures over an existing BigQuery graph. Don't use for Cypher or non-BigQuery graph databases, or for creating/modifying a graph schema.
# BigQuery Graph Query Guidelines You are querying a BigQuery property graph or semantic graph. You **MUST exclusively use the BigQuery GoogleSQL GQL and SQL standards**. **NEVER, under any circumstances, generate or consider Cypher queries.** Follow the instructions below exactly rather than relying on general graph-query knowledge. ## Query Paradigm Decision Guide Before writing any query, determine whether you are querying a **Property Graph** or a **Semantic Graph**: - **Property Graph (topology, paths, connections)**: - **Schema in Context**: `<property_graph>` DDL / node & edge tables. - **Target Query Engine / Mechanism**: **Native GQL** (`GRAPH ... MATCH ... RETURN`) by default; `GRAPH_TABLE` if joining relational tables. - **Semantic Graph (business metrics, dimensions, measures)**: - **Schema in Context**: `<semantic_graph start_node="X">` flattened views. - **Target Query Engine / Mechanism**: **`GRAPH_EXPAND` TVF** with `start_node => "X"` and `AGG()` measures. - **Semantic Graph Fallback (unqueryable entity / cyclic path)**: - **Schema in Context**: Node has no `<semantic_graph start_node="X">` view. - **Target Query Engine / Mechanism**: **Native GQL fallback** via `GRAPH_TABLE` over the `<property_graph>` with manual SQL aggregations. -------------------------------------------------------------------------------- ## Reference Files (rarely needed — do NOT load for standard queries) **This document is self-sufficient for the vast majority of questions**, including matching, multi-hop and variable-length paths, filtering, **aggregation / grouping / top-N**, existence checks, output formatting, and `GRAPH_EXPAND` queries. For these, generate the query directly from the rules below — do **not** open the companion files. Only read a companion file when the query genuinely needs one of these **uncommon** capabilities: - **Joining graph results with a separate relational (non-graph) table**, or passing values from an outer SQL table into the graph scope (parameterized `GRAPH_TABLE`): [graph-table-and-sql-integration.md](references/graph-table-and-sql-integration.md) - **Advanced element-identity functions** (`SOURCE_NODE_ID`, `DESTINATION_NODE_ID`, `ELEMENT_ID`, `LABELS`), or deep **performance tuning** of a slow/large traversal beyond the optimization rules in this core: [gql-advanced-functions-and-perf.md](references/gql-advanced-functions-and-perf.md) - **Correlated-subquery edge cases** beyond the WHERE-vs-FILTER rule below (e.g. `VALUE`/`ARRAY` subquery correlation limits): [gql-subqueries.md](references/gql-subqueries.md) - **Hybrid semantic + graph search**, when the question is conceptual rather than key-based **and** a node has an embedding-backed property, so candidates must come from `VECTOR_SEARCH` before traversal (embedding calls bill per invocation — do not open this otherwise): [hybrid-vector-graph-search.md](references/hybrid-vector-graph-search.md) If none of the above clearly applies, this core document is sufficient. -------------------------------------------------------------------------------- ## PART 1: Property Graph Querying (Native GQL) ### Pre-generation Checklist Before generating any GQL, you MUST: 1. **Identify Output Intent**: Determine if the user intends to **visualize a graph network** (requires `TO_JSON()`) or **view tabular data** (requires specific properties). 2. **Verify Language Standard**: Confirm the query will use **BigQuery GoogleSQL GQL**. NEVER use Cypher. ### Core Directives 1. **Default Query Construction (Standalone GQL)**: Write standalone GQL queries using the `RETURN` statement natively (`GRAPH ... MATCH ... RETURN`). This natively supports aggregation, grouping, and top-N (see below). **Only** use the `GRAPH_TABLE` table-valued function when you must join graph results with a separate relational table (see the SQL-integration reference). 2. **Keyword Escaping**: You **MUST** enforce backticks around any reserved SQL and GQL keywords used as identifiers (e.g., `order`, `begin`, `path` used as column, label, or variable names). 3. **Strictly Follow Graph Schema**: All labels (e.g., `:Person`, `:Account`) and properties (e.g., `n.id`, `e.amount`) used in the query MUST match the provided graph schema. Do NOT guess or hallucinate schema elements. 4. **Result Uniqueness**: Use `DISTINCT` in your `RETURN`/`COLUMNS` clause when the user prompt implies they want unique results. 5. **Graph Path Variables**: When a query involves "paths", "path traversal", "path finding", or finding relationships between nodes, you **MUST** assign the matched pattern to a path variable (e.g., `MATCH p = ...`). ### Basic Query Construction A GQL query names the graph, then chains clauses that pipe a "working table" from one to the next: `MATCH`, `LET` (define a variable/alias), `FILTER` (filter intermediate results — this is the GQL clause, used between clauses instead of a trailing `WHERE`), `WITH` (project/sort/group into the next scope), `ORDER BY` / `LIMIT` / `OFFSET`, and `RETURN` (project the final output). ```sql GRAPH <project>.<dataset>.<graph> MATCH (src:Account)-[t:Transfers]->(dst:Account) LET transfer_amount = t.amount FILTER transfer_amount > 1000 WITH src, dst, transfer_amount ORDER BY transfer_amount DESC LIMIT 50 RETURN src.id AS source, dst.id AS destination, transfer_amount ``` **Chaining with `NEXT`:** Compose multiple linear statements into one compound query with the `NEXT` keyword — the results of the statement before `NEXT` pipe into the statement after it. ### Aggregation, Grouping, and Top-N (native standalone GQL) **You do NOT need `GRAPH_TABLE` for aggregation, grouping, counts, sums, averages, "how many", "most/least", or "top N".** Standalone GQL handles these natively — this covers the majority of analytical questions: - **Aggregate functions** go directly in `RETURN` (or `WITH`): `COUNT(*)`, `COUNT(DISTINCT x)`, `SUM(e.amount)`, `AVG(...)`, `MIN`/`MAX`. - **Implicit GROUP BY**: any non-aggregated expressions in `RETURN`/`WITH` become the grouping keys automatically (like standard GQL grouping). There is no separate `GROUP BY` clause in standalone GQL — group by listing the key columns alongside the aggregate. - **Top-N / ranking**: add `ORDER BY <agg> DESC` then `LIMIT <n>`. ```sql -- "Which 3 entities filed the most filings?" (grouping + top-N, no GRAPH_TABLE) GRAPH <project>.<dataset>.<graph> MATCH (e:Entity)-[:Filed]->(f:Filing) RETURN e.name AS entity, COUNT(f) AS filing_count ORDER BY filing_count DESC LIMIT 3 ``` ```sql -- "Total transferred out per account" (grouped aggregate) GRAPH <project>.<dataset>.<graph> MATCH (src:Account)-[t:Transfers]->(:Account) RETURN src.id AS account, SUM(t.amount) AS total_out ORDER BY total_out DESC ``` Use `GRAPH_TABLE` (load the SQL-integration reference) **only** when you must `JOIN` graph output with a separate relational table or feed outer-table values into the graph scope. ### Existence Checks and Subqueries (essentials) For "entities that have / do not have a relationship", "at least one", "where there exists ..." questions, use a subquery. Two rules prevent the common errors (load the subqueries reference only for `VALUE`/`ARRAY` correlation edge cases): 1. **Use `FILTER`, not `WHERE`, for `EXISTS` / `IN` / `LIKE` subqueries.** These throw errors inside a `WHERE` clause. 2. **Re-declare the graph name inside the subquery block.** A subquery `{ ... }` must repeat `GRAPH <project>.<dataset>.<graph>` even though the outer query already declared it. ```sql GRAPH <project>.<dataset>.<graph> MATCH (p:Person) FILTER EXISTS { GRAPH <project>.<dataset>.<graph> MATCH (p)-[:Owns]->(:Account) } RETURN p.name ``` ### Graph Pattern Matching Node patterns use parentheses `()`; edge patterns use square brackets `[]` connected with arrows for direction. The BigQuery-specific rules: #### Node Patterns - `MATCH (p:Person|Account)`: the `|` label expression matches nodes that have **either** label (OR). You **cannot** use `&` in a label expression. - `MATCH (p:Person {id: 1})`: property-filter shorthand. - `MATCH (p:Person WHERE p.age > 18)`: inline `WHERE` condition on properties. #### Edge Patterns - `MATCH (a)-[e:Transfers]->(b)`: directed edge (preferred). - `MATCH (a)-[e:Transfers {amount: 50}]->(b)`: edge with a property filter. - `MATCH (a)-[e:Transfers]-(b)`: undirected (any direction) — **avoid**; specify explicit direction for better performance. #### Pattern Joins A complex pattern is one or more path patterns separated by commas `,`. If two comma-separated patterns **share a variable**, BigQuery performs an **equijoin** on it; if they share none, the result is a **cross join**. ```sql GRAPH <project>.<dataset>.<graph> MATCH (src:Account)-[t1:Transfers]->(interm:Account), (interm)<-[:Owns]-(p:Person) RETURN src.id AS account_id, p.name AS owner_name ``` #### Variable-Length Paths and Quantifiers Find multi-hop connections by appending a quantifier to an edge pattern. **This syntax differs from Cypher — use the BigQuery form:** - `{m, n}`: repeat the edge pattern between `m` and `n` times, e.g. `-[e:Transfers]->{1,3}`. - **Group Variables**: when an edge variable is quantified (e.g., `e` in `-[e:Transfers]->{1,3}`), `e` becomes a **group variable** — an array of the matched edges in the path. Interact with it using array functions (`ARRAY_LENGTH(e)`) or horizontal aggregation (`SUM(e.amount)`). #### Path Search Prefixes Variable-length paths can produce exponential combinations and repeating paths. Constrain the search between each source/destination pair with a prefix placed immediately before the path pattern: - `ANY`: exactly one arbitrary matching path per unique source/destination pair. - `ANY SHORTEST`: a single path with the minimum number of edges (hops). - `ANY CHEAPEST`: a single path with the minimum total cost, aggregating `COST` expressions defined on the edges. ```sql GRAPH <project>.<dataset>.<graph> MATCH ANY SHORTEST (a:Account {id: 123})-[e:Transferred]->{1,3}(b:Account {id: 456}) RETURN e ``` ### Path Extraction Functions When an entire path is bound to a variable (`MATCH p = (...)`), extract metadata and elements from it: - `PATH_FIRST(p)` / `PATH_LAST(p)`: the starting / terminal node of path `p`. - `PATH_LENGTH(p)`: an `INT64` count of the edge hops in path `p`. - `NODES(p)` / `EDGES(p)`: an array of the node / edge elements, ordered by their sequence in the path. ```sql GRAPH <project>.<dataset>.<graph> MATCH p = (a:Account)-[t:Transfers]->{1,3}(b:Account) RETURN PATH_LENGTH(p) AS hops, TO_JSON(NODES(p)) AS path_nodes ``` For `SOURCE_NODE_ID`, `DESTINATION_NODE_ID`, `ELEMENT_ID`, and `LABELS`, load the advanced-functions reference. ### Output Formatting: Visualization vs. Tabular Strictly distinguish **graph visualization** intent from **tabular data** intent when constructing the `RETURN`/`COLUMNS` clause. #### 1. Graph Visualization Intent Use when the user wants to see relationships, paths, topology, networks, connectivity, or entire entities (nodes/edges) as a whole. **Triggers**: "visualize", "show the graph", "network", "connections", "find the path", "relationship between X and Y". - **Default to `TO_JSON()`**: unless specific properties (e.g., `n.name`) or path metrics (e.g., `PATH_LENGTH(p)`) are explicitly requested, you **MUST** wrap all graph topology outputs (nodes, edges, and path variables) in `TO_JSON()` so the graphing UI receives full JSON objects. - **Limit**: always append `LIMIT 500` unless the user requests a different number, to avoid overwhelming the UI. ```sql GRAPH <project>.<dataset>.<graph> MATCH p = (:Person)-[:Knows]->(:Person)
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub