make-graph operator
Applies to: ✅ Microsoft Fabric ✅ Azure Data Explorer ✅ Azure Monitor ✅ Microsoft Sentinel
The make-graph
operator builds a graph structure from tabular inputs of edges and nodes.
Syntax
Edges |
make-graph
SourceNodeId -->
TargetNodeId [ with
Nodes1 on
NodeId1 [,
Nodes2 on
NodeId2 ]]
Edges |
make-graph
SourceNodeId -->
TargetNodeId [ with_node_id=
DefaultNodeId ]
Parameters
Name | Type | Required | Description |
---|---|---|---|
Edges | string |
✔️ | The tabular source containing the edges of the graph, each row represents an edge in the graph. |
SourceNodeId | string |
✔️ | The column in Edges with the source node IDs of the edges. |
TargetNodeId | string |
✔️ | The column in Edges with the target node IDs of the edges. |
Nodes | string |
The tabular expressions containing the properties of the nodes in the graph. | |
NodesId | string |
The columns with the node IDs in Nodes. | |
DefaultNodeId | string |
The name of the column for the default node ID. |
Returns
The make-graph
operator returns a graph expression and must be followed by a graph operator. Each row in the source Edges expression becomes an edge in the graph with properties that are the column values of the row. Each row in the Nodes tabular expression becomes a node in the graph with properties that are the column values of the row. Nodes that appear in the Edges table but don't have a corresponding row in the Nodes table are created as nodes with the corresponding node ID and empty properties.
Note
Each node has a unique identifier. If the same node ID appears in both the Nodes1 and Nodes2 tables, a single node is created by merging their properties. If there are conflicting property values for the same node, one of the values is arbitrarily chosen.
Users can handle node information in the following ways:
- No node information required:
make-graph
completes with source and target. - Explicit node properties: use up to two tabular expressions using "
with
Nodes1on
NodeId1 [,
Nodes2on
NodeId2 ]." - Default node identifier: use "
with_node_id=
DefaultNodeId."
Example
Edges and nodes graph
The following example builds a graph from edges and nodes tables. The nodes represent people and systems, and the edges represent different relationships between nodes. The make-graph
operator builds the graph. Then, the graph-match
operator is used with a graph pattern to search for attack paths leading to the "Trent"
system node.
let nodes = datatable(name:string, type:string, age:int)
[
"Alice", "Person", 23,
"Bob", "Person", 31,
"Eve", "Person", 17,
"Mallory", "Person", 29,
"Trent", "System", 99
];
let edges = datatable(source:string, destination:string, edge_type:string)
[
"Alice", "Bob", "communicatesWith",
"Alice", "Trent", "trusts",
"Bob", "Trent", "hasPermission",
"Eve", "Alice", "attacks",
"Mallory", "Alice", "attacks",
"Mallory", "Bob", "attacks"
];
edges
| make-graph source --> destination with nodes on name
| graph-match (mallory)-[attacks]->(compromised)-[hasPermission]->(trent)
where mallory.name == "Mallory" and trent.name == "Trent" and attacks.edge_type == "attacks" and hasPermission.edge_type == "hasPermission"
project Attacker = mallory.name, Compromised = compromised.name, System = trent.name
Output
Attacker | Compromised | System |
---|---|---|
Mallory | Bob | Trent |
Default node identifier
The following example builds a graph using only edges, with the name
property as the default node identifier. This approach is useful when creating a graph from a tabular expression of edges, ensuring that the node identifier is available for the constraints section of the subsequent graph-match
operator.
let edges = datatable(source:string, destination:string, edge_type:string)
[
"Alice", "Bob", "communicatesWith",
"Alice", "Trent", "trusts",
"Bob", "Trent", "hasPermission",
"Eve", "Alice", "attacks",
"Mallory", "Alice", "attacks",
"Mallory", "Bob", "attacks"
];
edges
| make-graph source --> destination with_node_id=name
| graph-match (mallory)-[attacks]->(compromised)-[hasPermission]->(trent)
where mallory.name == "Mallory" and trent.name == "Trent" and attacks.edge_type == "attacks" and hasPermission.edge_type == "hasPermission"
project Attacker = mallory.name, Compromised = compromised.name, System = trent.name
Output
Attacker | Compromised | System |
---|---|---|
Mallory | Bob | Trent |