Kusto 查询语言 (KQL) 图形语义的常见使用场景有哪些?

通过 Kusto 查询语言 (KQL) 中的图形语义,可以为数据建模并查询数据(采用图形形式)。 在许多场景中,图形可用于表示涉及多对多、分层或联网的关系(例如社交网络、建议系统、联网资产或知识图形)的复杂动态数据。

在本文中,你将了解 KQL 图形语义的以下常见使用场景:

朋友的朋友

图形的一个常见用例是对社交网络进行建模和查询,其中节点是用户,边缘是朋友关系或互动。 例如,假设我们有一个名为“Users”的表,其中包含用户的相关数据(例如其姓名和组织),还有一个名为“Knows”的表,其中包含用户之间的朋友关系数据,如下图所示

显示好友的好友图表的关系图。

如果不使用 KQL 中的图形语义,则可以创建一个图形,通过多个联接来查找朋友的朋友,如下所示:

let Users = datatable (UserId: string, name: string, org: string)[]; // nodes
let Knows = datatable (FirstUser: string, SecondUser: string)[]; // edges
Users
| where org == "Contoso"
| join kind=inner (Knows) on $left.UserId == $right.FirstUser
| join kind=innerunique(Users) on $left.SecondUser == $right.UserId
| join kind=inner (Knows) on $left.SecondUser == $right.FirstUser
| join kind=innerunique(Users) on $left.SecondUser1 == $right.UserId
| where UserId != UserId1
| project name, name1, name2

可以使用 KQL 中的图形语义以更直观、更高效的方式执行相同的查询。 以下查询使用 make-graph 运算符创建一个从 FirstUser 到 SecondUser 的有向图,并使用 Users 表提供的列扩充节点上的属性。 对图形进行实例化后,graph-match 运算符会提供朋友的朋友模式,包括筛选器和生成表格输出的投影。

let Users = datatable (UserId:string , name:string , org:string)[]; // nodes
let Knows = datatable (FirstUser:string , SecondUser:string)[]; // edges
Knows
| make-graph FirstUser --> SecondUser with Users on UserId
| graph-match (user)-->(middle_man)-->(friendOfAFriend)
    where user.org == "Contoso" and user.UserId != friendOfAFriend.UserId
    project contoso_person = user.name, middle_man = middle_man.name, kusto_friend_of_friend = friendOfAFriend.name

日志数据中的见解

在某些用例中,需要从包含时序信息(例如日志数据)的简单展平表中获取见解。 每行中的数据是包含原始数据的字符串。 若要根据此数据创建图形,必须先标识与图形分析相关的实体和关系。 例如,假设你有一个来自 Web 服务器的 rawLogs 表,其中包含请求的相关信息,例如时间戳、源 IP 地址、目标资源等等

下表所示为原始数据的示例:

let rawLogs = datatable (rawLog: string) [
    "31.56.96.51 - - [2019-01-22 03:54:16 +0330] \"GET /product/27 HTTP/1.1\" 200 5379 \"https://www.contoso.com/m/filter/b113\" \"some client\" \"-\"",
    "31.56.96.51 - - [2019-01-22 03:55:17 +0330] \"GET /product/42 HTTP/1.1\" 200 5667 \"https://www.contoso.com/m/filter/b113\" \"some client\" \"-\"",
    "54.36.149.41 - - [2019-01-22 03:56:14 +0330] \"GET /product/27 HTTP/1.1\" 200 30577 \"-\" \"some client\" \"-\""
];

若要根据此表对图形进行建模,一种可行的方法是将源 IP 地址视为节点,将对资源发出的 Web 请求视为边缘。 可以使用 parse 运算符提取图形所需的列,然后可以创建一个图形,用来表示不同源和目标之间的网络流量和交互。 若要创建图形,可以使用 make-graph 运算符将源和目标列指定为边缘终结点,还可以选择性地将其他列作为边缘或节点属性提供。

以下查询根据原始日志创建图形:

let parsedLogs = rawLogs
    | parse rawLog with ipAddress: string " - - [" timestamp: datetime "] \"" httpVerb: string " " resource: string " " *
    | project-away rawLog;
let edges = parsedLogs;
let nodes =
    union
        (parsedLogs
        | distinct ipAddress
        | project nodeId = ipAddress, label = "IP address"),
        (parsedLogs | distinct resource | project nodeId = resource, label = "resource");
let graph = edges
    | make-graph ipAddress --> resource with nodes on nodeId;

此查询分析原始日志并创建一个有向图,其中节点是 IP 地址或资源,每个边缘是源到目标的请求,时间戳和 HTTP 谓词是边缘属性。

显示已分析的日志数据的图表的关系图。

创建图形后,可以使用 graph-match 运算符通过模式、筛选器和投影查询图形数据。 例如,可以创建这样一种模式,即根据其他 IP 地址在过去五分钟内请求的资源提出简单的建议,如下所示:

graph
| graph-match (startIp)-[request]->(resource)<--(otherIP)-[otherRequest]->(otherResource)
    where startIp.label == "IP address" and //start with an IP address
    resource.nodeId != otherResource.nodeId and //recommending a different resource
    startIp.nodeId != otherIP.nodeId and //only other IP addresses are interesting
    (request.timestamp - otherRequest.timestamp < 5m) //filter on recommendations based on the last 5 minutes
    project Recommendation=otherResource.nodeId

输出

建议
/product/42

查询根据基于原始文本的日志返回“/product/42”作为建议。