適用対象: ✅Microsoft Fabric✅Azure データ エクスプローラー✅Azure Monitor✅Microsoft Sentinel
make-graph演算子は、エッジとノードの表形式の入力からグラフ構造を構築します。
構文
|
make-graph
TargetNodeId [ -->Nodes1withNodeId1 [onNodes2,NodeId2 ]]
エッジ|make-graphSourceNodeId-->TargetNodeId [ with_node_id=NodeIdPropertyName ]
|
make-graph
TargetNodeId [ -->Nodes1withNodeId1 [onNodes2,NodeId2 ]] onPartitionColumnpartitioned-byGraphOperator(
パラメーター
| 件名 | タイプ | Required | 説明 |
|---|---|---|---|
| エッジ | string |
✔️ | グラフのエッジを含む表形式のソース。各行はグラフ内のエッジを表します。 |
| SourceNodeId | string |
✔️ | エッジのソース ノード ID をEdges 内の列。 |
| TargetNodeId | string |
✔️ | エッジのターゲット ノード ID を持つ Edges の列。 |
| Nodes1、Nodes2 | string |
グラフ内のノードのプロパティを含む表形式の式。 | |
| NodesId1、NodesId2 | string |
Nodes1内のノード ID を持つ対応する列 Nodes2。 | |
| NodeIdPropertyName | string |
グラフのノード上のノード ID のプロパティの名前。 | |
| PartitionColumn | string |
グラフをパーティション分割する列。 この列の一意の値ごとに個別のグラフを作成します。 | |
| GraphOperator | string |
パーティション分割された各グラフに適用するグラフ演算子。 |
返品
make-graph演算子はグラフ式を返し、その後にグラフ演算子が続く必要があります。 ソース Edges 式の各行は、行の列値であるプロパティを持つグラフのエッジになります。
Nodes表形式式の各行は、グラフ内のノードになり、その行の列値であるプロパティが含まれます。
Edges テーブルに表示されるが、Nodes テーブルに対応する行がないノードは、対応するノード ID と空のプロパティを持つノードとして作成されます。
partitioned-by句を使用すると、指定した PartitionColumn 内の一意の値ごとに個別のグラフが作成されます。 その後、指定した GraphOperator がパーティション分割された各グラフに個別に適用され、結果が 1 つの出力に結合されます。 これは、同じグラフ構造と分析ロジックを維持しながら、各テナントのデータを個別に分析するマルチテナント シナリオに特に役立ちます。
Important
partitioned-by句を使用する場合、Edges テーブルとすべての Nodes テーブルの両方にパーティション列が含まれている必要があります。
Note
各ノードには一意の識別子があります。 Nodes1 テーブルと Nodes2 テーブルの両方に同じノード ID が表示される場合は、プロパティをマージすることで 1 つのノードが作成されます。 同じノードに対して競合するプロパティ値がある場合、値の 1 つが任意に選択されます。
ユーザーは、次の方法でノード情報を処理できます。
-
ノード情報は必要ありません:
make-graphソースとターゲットで完了します。 -
明示的なノード プロパティ: "
withNodes1onNodeId1 [,Nodes2onNodeId2 ]" を使用して、最大 2 つの表形式式を使用します。 -
既定のノード識別子: は "
with_node_id=DefaultNodeId" を使用します。
例
エッジとノードグラフ
次の例では、エッジ テーブルとノード テーブルからグラフを作成します。 ノードは人とシステムを表し、エッジはノード間の異なる関係を表します。
make-graph演算子によってグラフが作成されます。 次に、 graph-match オペレーターをグラフ パターンと共に使用して、 "Trent" システム ノードにつながる攻撃パスを検索します。
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
出力
| 攻撃者 | セキュリティ侵害 | System |
|---|---|---|
| Mallory | Bob | Trent |
既定のノード識別子
次の例では、既定のノード識別子として name プロパティを使用して、エッジのみを使用してグラフを作成します。 この方法は、エッジの表形式の式からグラフを作成し、後続の graph-match 演算子の制約セクションでノード識別子を使用できるようにする場合に便利です。
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
出力
| 攻撃者 | セキュリティ侵害 | System |
|---|---|---|
| Mallory | Bob | Trent |
パーティション分割されたグラフ
この例では、 partitioned-by 句を使用してマルチテナント ソーシャル ネットワークを分析する方法を示します。
partitioned-by句は、パーティション列の一意の値ごとに個別のグラフを作成し (この場合はtenantId)、グラフ演算子を各パーティションに個別に適用し、結果を結合します。
// Nodes table representing users across multiple tenants (organizations)
let nodes = datatable(userId:string, tenantId:string, name:string, department:string, role:string, location:dynamic)
[
// Tenant: CompanyA - San Francisco Bay Area
"u001", "CompanyA", "Alice Johnson", "Engineering", "Senior Developer", dynamic({"type": "Point", "coordinates": [-122.4194, 37.7749]}),
"u002", "CompanyA", "Bob Smith", "Engineering", "Team Lead", dynamic({"type": "Point", "coordinates": [-122.4094, 37.7849]}),
"u003", "CompanyA", "Charlie Black", "Marketing", "Manager", dynamic({"type": "Point", "coordinates": [-122.4294, 37.7649]}),
"u004", "CompanyA", "Diana Finch", "HR", "Director", dynamic({"type": "Point", "coordinates": [-122.3994, 37.7949]}),
"u005", "CompanyA", "Eve Wilson", "Engineering", "Junior Developer", dynamic({"type": "Point", "coordinates": [-122.4394, 37.7549]}),
// Tenant: CompanyB - New York Area
"u006", "CompanyB", "Frank Miller", "Sales", "Account Manager", dynamic({"type": "Point", "coordinates": [-74.0060, 40.7128]}),
"u007", "CompanyB", "Grace Lee", "Engineering", "Senior Developer", dynamic({"type": "Point", "coordinates": [-74.0160, 40.7228]}),
"u008", "CompanyB", "Henry Davis", "Marketing", "Specialist", dynamic({"type": "Point", "coordinates": [-73.9960, 40.7028]}),
"u009", "CompanyB", "Ivy Chen", "Engineering", "Team Lead", dynamic({"type": "Point", "coordinates": [-74.0260, 40.7328]}),
"u010", "CompanyB", "Jack Thompson", "Operations", "Manager", dynamic({"type": "Point", "coordinates": [-73.9860, 40.6928]}),
// Tenant: CompanyC - Austin Area
"u011", "CompanyC", "Kate Anderson", "Finance", "Analyst", dynamic({"type": "Point", "coordinates": [-97.7431, 30.2672]}),
"u012", "CompanyC", "Liam Murphy", "Engineering", "Architect", dynamic({"type": "Point", "coordinates": [-97.7331, 30.2772]}),
"u013", "CompanyC", "Maya Patel", "Product", "Manager", dynamic({"type": "Point", "coordinates": [-97.7531, 30.2572]}),
"u014", "CompanyC", "Noah Garcia", "Engineering", "Developer", dynamic({"type": "Point", "coordinates": [-97.7631, 30.2472]}),
"u015", "CompanyC", "Olivia Rodriguez", "Marketing", "Director", dynamic({"type": "Point", "coordinates": [-97.7231, 30.2872]})
];
// Edges table representing relationships/interactions between users
let edges = datatable(sourceUserId:string, targetUserId:string, tenantId:string, relationshipType:string, strength:int)
[
// CompanyA relationships
"u001", "u002", "CompanyA", "reportsTo", 9,
"u005", "u002", "CompanyA", "reportsTo", 8,
"u002", "u003", "CompanyA", "collaborates", 6,
"u001", "u005", "CompanyA", "mentors", 7,
"u003", "u004", "CompanyA", "collaborates", 5,
"u001", "u003", "CompanyA", "communicates", 4,
// CompanyB relationships
"u007", "u009", "CompanyB", "reportsTo", 9,
"u006", "u010", "CompanyB", "reportsTo", 8,
"u008", "u006", "CompanyB", "collaborates", 6,
"u009", "u010", "CompanyB", "communicates", 5,
"u007", "u008", "CompanyB", "mentors", 7,
"u006", "u007", "CompanyB", "collaborates", 6,
// CompanyC relationships
"u014", "u012", "CompanyC", "reportsTo", 9,
"u012", "u013", "CompanyC", "collaborates", 7,
"u011", "u013", "CompanyC", "collaborates", 6,
"u013", "u015", "CompanyC", "reportsTo", 8,
"u012", "u015", "CompanyC", "communicates", 5,
"u011", "u014", "CompanyC", "mentors", 6
];
edges
| make-graph sourceUserId --> targetUserId with nodes on userId partitioned-by tenantId (
graph-match cycles=none (n1)-[e*2..4]->(n2)
where n1.userId != n2.userId and all(e, relationshipType == "collaborates") and
geo_distance_2points(todouble(n1.location.coordinates[0]), todouble(n1.location.coordinates[1]),
todouble(n2.location.coordinates[0]), todouble(n2.location.coordinates[1])) < 10000
project Start = strcat(n1.name, " (", n1.tenantId, ")"), Tenants = map(e, tenantId), End = strcat(n2.name, " (", n2.tenantId, ")")
)
| Start | テナント | End |
|---|---|---|
| Bob Smith (CompanyA) | [ "CompanyA", "CompanyA" ] |
ダイアナ フィンチ (CompanyA) |
| ヘンリー・デイビス (CompanyB) | [ "CompanyB", "CompanyB" ] |
Grace Lee (CompanyB) |