次の方法で共有


make-graph 演算子

適用対象: ✅Microsoft FabricAzure データ エクスプローラーAzure MonitorMicrosoft 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 の列。
Nodes1Nodes2 string グラフ内のノードのプロパティを含む表形式の式。
NodesId1NodesId2 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 つが任意に選択されます。

ユーザーは、次の方法でノード情報を処理できます。

  1. ノード情報は必要ありません:make-graph ソースとターゲットで完了します。
  2. 明示的なノード プロパティ: "withNodes1onNodeId1 [,Nodes2onNodeId2 ]" を使用して、最大 2 つの表形式式を使用します。
  3. 既定のノード識別子: は "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)、グラフ演算子を各パーティションに個別に適用し、結果を結合します。

3 つの異なるパーティションを表す 3 つの異なる会社を示す図。

// 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)