Microsoft Sentinel 中的 Kusto 查詢語言
Kusto 查詢語言是您將用來處理及操作 Microsoft Sentinel 中資料的語言。 如果您無法分析饋送到工作區的記錄,並取得那其中所有資料中隱藏的重要資訊,則這些記錄就沒什麼價值。 Kusto 查詢語言不僅具備取得該資訊的能力和彈性,而且還具備協助您快速開始使用的簡單性。 如果您具備指令碼處理或使用資料庫的背景,則您將覺得此文章的許多內容非常熟悉。 如果沒有,別擔心,因為語言的直覺本質可讓您快速開始撰寫自己的查詢,並為組織創造價值。
此文章介紹 Kusto 查詢語言的基本概念,其中涵蓋一些最常使用的函式和運算子,其應該能夠處理您每天將撰寫的 75% 到 80% 的查詢數目。 當您需要更深入或執行更進階的查詢時,可以利用新的適用於 Microsoft Sentinel 的進階 KQL 活頁簿 (請參閱這篇簡介部落格文章 \(英文\))。 另請參閱官方 Kusto 查詢語言文件以及各種線上課程 (例如 Pluralsight 的課程)。
背景 - 為何是 Kusto 查詢語言?
Microsoft Sentinel 建置於 Azure 監視器服務之上,並使用 Azure 監視器的 Log Analytics 工作區來儲存其所有資料。 此資料包括下列任一項:
- 使用 Microsoft Sentinel 資料連接器,從外部來源擷取到預先定義資料表的資料。
- 使用自訂建立的資料連接器以及某些類型的現成連接器,從外部來源擷取到使用者定義自訂資料表的資料。
- 由 Microsoft Sentinel 本身建立的資料 (產生自其建立並執行的分析),例如,警示、事件及 UEBA 相關資訊。
- 上傳至 Microsoft Sentinel 以協助偵測和分析的資料,例如,威脅情報摘要和關注清單。
Kusto 查詢語言是作為 Azure 資料總管服務的一部分來開發,因此,會針對在雲端環境中搜尋巨量資料存放區進行最佳化。 受到著名海底探險家 Jacques Cousteau (相應發音為 "koo-STOH") 所啟發,此語言的設計目的是協助您深入探索資料海洋,並探索隱藏其中的寶藏。
Kusto 查詢語言也能用於 Azure 監視器 (因此也可用於 Microsoft Sentinel),包括一些額外的 Azure 監視器功能,可讓您擷取、視覺化、分析及剖析 Log Analytics 資料存放區中的資料。 在 Microsoft Sentinel 中,不論是在現有的規則和活頁簿中,還是在建置您自己的規則中,每當您將資料視覺化且進行分析並搜捕威脅時,都會使用以 Kusto 查詢語言為基礎的工具。
由於 Kusto 查詢語言幾乎是您在 Microsoft Sentinel 中執行所有作業的一部分,因此,清楚了解其運作方式有助於讓您從 SIEM 中獲得更多。
什麼是查詢?
Kusto 查詢語言的查詢是處理資料並傳回結果的唯讀要求,它不會寫入任何資料。 查詢會針對組織為資料庫、資料表及資料行階層的資料進行操作,類似於 SQL。
要求均會明文陳述,並使用設計來讓語法易於讀取、撰寫及自動執行的資料流程模型。 我們將詳細了解這一點。
Kusto 查詢語言的查詢由以分號分隔的「陳述式」所組成。 有許多種類的陳述式,但這裡只討論兩種廣泛使用的類型:
表格式運算式陳述式是我們一般在討論查詢時所代表的意義,這些是查詢的實際主體。 有個關於表格式運算式陳述式需了解的重要事項是,它們接受表格式輸入 (資料表或其他表格式運算式),並產生表格式輸出。 至少需要有這其中一個。 此文章其餘部分的大多數內容都將討論這種陳述式。
let 陳述式可讓您在查詢主體之外建立並定義變數與常數,以便更容易閱讀且具多樣性。 這些是選擇性,可根據您的特殊需求而定。 我們將在此文章結尾處理這種陳述式。
示範環境
您可以在 Azure 入口網站的 Log Analytics 示範環境中練習 Kusto 查詢語言陳述式,包括此文章中的陳述式。 使用此練習環境不需付費,但您需要 Azure 帳戶才能存取它。
探索示範環境。 就像實際執行環境中的 Log Analytics 一樣,有數種方式可以使用它:
選擇要在其中建置查詢的資料表。 從預設的 [資料表] 索引標籤 (顯示於左上方的紅色矩形中),從依主題群組的資料表清單中選取資料表 (顯示於左下方)。 展開主題以查看個別資料表,您可以進一步展開每個資料表來查看其所有欄位 (資料行)。 按兩下資料表或欄位名稱,會將它放在查詢視窗中的游標所在位置。 在資料表名稱之後輸入查詢的其餘部分,如下所示。
尋找要研究或修改的現有查詢。 選取 [查詢] 索引標籤 (顯示於左上方的紅色矩形中),以查看現成可用的查詢清單。 或者,從右上方的按鈕列中選取 [查詢]。 您可以探索隨附於 Microsoft Sentinel 的現成查詢。 按兩下查詢,即會將整個查詢放在查詢視窗中的游標所在位置。
如同在此示範環境中,您可以在 Microsoft Sentinel 的 [記錄] 頁面中查詢和篩選資料。 您可以選取資料表並向下切入,以查看資料行。 您可以使用 [欄位選擇器] 來修改顯示的預設資料行,也可以為查詢設定預設時間範圍。 如果在查詢中明確定義時間範圍,時間篩選將無法使用 (呈現灰色)。
查詢結構
學習 Kusto 查詢語言時,了解整體查詢結構是個不錯的起點。 查看 Kusto 查詢時,您將注意到的第一件事是使用管道符號 (|
)。 Kusto 查詢的結構首先會從資料來源取得資料,然後在「管線」中傳遞資料,而每個步驟都會提供某種程度的處理,接著將資料傳遞到下一個步驟。 在管線結束時,您將取得最終結果。 實際上,這是我們的管線:
Get Data | Filter | Summarize | Sort | Select
這個沿著管線傳遞資料的概念形成了一個非常直覺的結構,因為很容易就能在每個步驟中建立資料的意向圖。
為了說明這一點,讓我們看看下列查詢,其會查看 Microsoft Entra 登入記錄。 當您逐行閱讀時,可以看到指出資料發生狀況的關鍵字。 我們已在每一行,以註解形式包含管線中的相關階段。
注意
您可以透過在註解前面加上雙斜線 (//
),將註解新增到查詢中的任一行。
SigninLogs // Get data
| evaluate bag_unpack(LocationDetails) // Ignore this line for now; we'll come back to it at the end.
| where RiskLevelDuringSignIn == 'none' // Filter
and TimeGenerated >= ago(7d) // Filter
| summarize Count = count() by city // Summarize
| sort by Count desc // Sort
| take 5 // Select
由於每個步驟的輸出都會作為下一個步驟的輸入,因此,步驟的順序可以判斷查詢的結果並影響其效能。 請務必根據您希望從查詢中取得的內容來排序步驟。
提示
- 有個良好的經驗法則是提早篩選資料,因此,您只需沿著管線傳遞相關資料。 這將大幅提升效能,並確保您不會意外在摘要步驟中包含不相關的資料。
- 此文章將指出一些要記住的其他最佳做法。 如需更完整的清單,請參閱查詢最佳做法。
希望您現在已對 Kusto 查詢語言中查詢的整體結構有所了解。 現在,讓我們看看實際查詢運算子本身,其可用來建立查詢。
資料類型
進入查詢運算子之前,讓我們先快速查看資料類型。 如同大多數語言,資料類型會決定可以針對值執行哪些計算和操作。 例如,如果您有 string 類型的值,將無法對其執行算術計算。
在 Kusto 查詢語言中,大多數資料類型都遵循標準慣例,並具有您先前可能已看過的名稱。 下表顯示完整清單:
資料類型表格
類型 | 其他名稱 | 對等的 .NET 類型 |
---|---|---|
bool |
Boolean |
System.Boolean |
datetime |
Date |
System.DateTime |
dynamic |
System.Object |
|
guid |
% | System.Guid |
int |
System.Int32 |
|
long |
System.Int64 |
|
real |
Double |
System.Double |
string |
System.String |
|
timespan |
Time |
System.TimeSpan |
decimal |
System.Data.SqlTypes.SqlDecimal |
儘管大多數資料類型均為標準,但您可能不熟悉 dynamic、timespan 和 guid 等類型。
Dynamic 的結構與 JSON 非常類似,但有一個主要差異:它可以儲存 Kusto 查詢語言特定的資料類型 (傳統 JSON 則不行),例如,巢狀的 dynamic 值或 timespan。 以下為 dynamic 類型的範例:
{
"countryOrRegion":"US",
"geoCoordinates": {
"longitude":-122.12094116210936,
"latitude":47.68050003051758
},
"state":"Washington",
"city":"Redmond"
}
Timespan 是一種資料類型,可參考時間量值,例如小時、天或秒。 請勿將 timespan 與 datetime 混淆,其會評估為實際日期和時間,而不是時間量值。 下表顯示 timespan 尾碼的清單。
Timespan 尾碼
函式 | 描述 |
---|---|
D |
days |
H |
hours |
M |
分鐘 |
S |
seconds |
Ms |
milliseconds |
Microsecond |
微秒 |
Tick |
奈秒 |
GUID 是代表 128 位元全域唯一識別碼的資料類型,其遵循標準格式 [8]-[4]-[4]-[4]-[12],其中每個 [number] 均代表字元數目,而且每個字元的範圍可以是 0-9 或 a-f。
注意
Kusto 查詢語言同時具有表格式和純量運算子。 在此文章的其餘部分,如果您只看到「運算子」一詞,除非另有說明,否則,可假設其表示表格式運算子。
取得、限制、排序及篩選資料
Kusto 查詢語言的核心詞彙 (可讓您完成絕大多數工作的基礎) 是篩選、排序及選取資料的運算子集合。 您需要執行的其餘工作將要求您延續對該語言的知識,以符合更進階的需求。 讓我們稍微闡述上述範例中使用的一些命令,並查看 take
、sort
及 where
。
針對這其中每一個運算子,我們將檢查其在先前 SigninLogs 範例中的用法,並了解有用的提示或最佳做法。
取得資料
所有基本查詢的第一行均會指定您要使用的資料表。 在 Microsoft Sentinel 的案例中,這可能是工作區中記錄類型的名稱,例如 SigninLogs、SecurityAlert 或 CommonSecurityLog。 例如:
SigninLogs
請注意,在 Kusto 查詢語言中,記錄名稱會區分大小寫,因此 SigninLogs
和 signinLogs
會以不同的方式來解譯。 謹慎選擇自訂記錄的名稱,使它們易於識別且不會與其他記錄過於類似。
限制資料:take / limit
take 運算子 (以及相同的 limit 運算子) 可用於透過只傳回指定的資料列數目來限制結果。 後面接著一個整數,指定要傳回的資料列數目。 一般而言,它會在您決定排序順序之後用於查詢結尾,在這種情況下,它將在排序順序頂端傳回指定的資料列數目。
當您不想傳回大型資料集時,在查詢早期使用 take
,對測試查詢很有用。 不過,如果您在任何 take
作業之前放置 sort
作業,take
將隨機傳回已選取的資料列,而且每次執行查詢時,可能會傳回一組不同的資料列。 以下是使用 take 的範例:
SigninLogs
| take 5
提示
處理您可能不知道查詢看起來如何的全新查詢時,將 take
陳述式放在開頭,透過人為方式限制資料集,以加快處理和實驗速度,可能很實用。 當您滿意整個查詢之後,即可移除初始的 take
步驟。
排序資料:sort / order
sort 運算子 (以及相同的 order 運算子) 可用來依指定的資料行排序資料。 在下列範例中,我們依 TimeGenerated 排序結果,並使用 desc 參數來將排序方向設為遞減,即先放置最高值;針對遞增順序,我們使用 asc。
注意
排序的預設方向是遞減,因此,技術上,您只需指定是否要以遞增順序排序。 不過,在任何情況下指定排序方向,將能讓您的查詢更容易閱讀。
SigninLogs
| sort by TimeGenerated desc
| take 5
如前所述,我們將 sort
運算子放在 take
運算子之前。 我們需要先排序,以確保會取得五個適當的記錄。
前幾個
top 運算子可讓我們將 sort
和 take
運算合併為單一運算子:
SigninLogs
| top 5 by TimeGenerated desc
如果有兩個或多個記錄在您作為排序依據的資料行中具有相同值,則您可以新增更多資料行作為排序依據。 在逗號分隔清單中新增額外的排序資料行,位於第一個排序資料行之後,但在排序順序關鍵字之前。 例如:
SigninLogs
| sort by TimeGenerated, Identity desc
| take 5
現在,如果 TimeGenerated 在多個記錄之間均相同,則將嘗試依 Identity 資料行中的值排序。
注意
何時使用 sort
和 take
,以及何時使用 top
如果您只排序一個欄位,請使用
top
,因為它提供比sort
和take
的組合更好的效能。如果您需要排序多個欄位 (例如,上述最後一個範例),
top
無法執行此動作,因此,您必須使用sort
和take
。
篩選資料:where
where 運算子可說是最重要的運算子,因為它是確定您只需處理與您案例相關之資料子集的關鍵。 您應該盡可能及早在查詢中篩選資料,因為這麼做將透過減少後續步驟中需要處理的資料量,來改善查詢效能;它也可確保您只要對所需資料執行計算。 請參閱此範例:
SigninLogs
| where TimeGenerated >= ago(7d)
| sort by TimeGenerated, Identity desc
| take 5
where
運算子會指定變數、比較 (「純量」) 運算子和值。 在我們的案例中,使用了 >=
來表示 TimeGenerated 資料行中的值必須大於 (也就是晚於) 或等於七天前。
Kusto 查詢語言中有兩種類型的比較運算子:字串和數值。 下表顯示數值運算子的完整清單:
數值運算子
Operator | 描述 |
---|---|
+ |
加法 |
- |
減 |
* |
乘法 |
/ |
除法 |
% |
模數 |
< |
小於 |
> |
大於 |
== |
等於 |
!= |
不等於 |
<= |
小於或等於 |
>= |
大於或等於 |
in |
等於其中一個元素 |
!in |
不等於任何元素 |
字串運算子清單是一個較長的清單,因為它可以根據字母大小寫、子字串位置、首碼、尾碼等等來排列。 ==
運算子既是數值運算子,同時也是字串運算子,這表示它可以同時用於數字和文字。 例如,下列兩個陳述式都是有效的 Where 陳述式:
| where ResultType == 0
| where Category == 'SignInLogs'
提示
最佳做法:在大多數情況下,您可能想要依多個資料行篩選資料,或以多種方式篩選相同資料行。 在這些情況下,您應該記住兩種最佳做法。
您可以使用 and 關鍵字,將多個 where
陳述式合併為單一步驟。 例如:
SigninLogs
| where Resource == ResourceGroup
and TimeGenerated >= ago(7d)
當您使用 and 關鍵字來將多個篩選聯結至單一 where
陳述式時,您可以透過放置只會先參考單一資料行的篩選來取得更好效能。 因此,撰寫上述查詢的較好方式是:
SigninLogs
| where TimeGenerated >= ago(7d)
and Resource == ResourceGroup
在此範例中,第一個篩選提及單一資料行 (TimeGenerated),第二個篩選則參考兩個資料行 (Resource 和 ResourceGroup)。
摘要資料
Summarize 是 Kusto 查詢語言中最重要的表格式運算子之一,但它也是更複雜的運算子之一,可了解您是否為一般查詢語言的新手。 summarize
的作業是取得一個資料資料表,並輸出由一或多個資料行彙總的「新資料表」。
Summarize 陳述式的結構
summarize
陳述式的基本結構如下:
| summarize <aggregation> by <column>
例如,以下傳回 Perf 資料表中,每個 CounterName 值的記錄計數:
Perf
| summarize count() by CounterName
因為 summarize
的輸出是新資料表,所以,summarize
陳述式中未明確指定的任何資料行都不會沿著管線傳遞。 為了說明此概念,請考量下列範例:
Perf
| project ObjectName, CounterValue, CounterName
| summarize count() by CounterName
| sort by ObjectName asc
在第二行,指出我們只關心 ObjectName、CounterValue 和 CounterName 資料行。 然後摘要說明依 CounterName 取得記錄計數,最後,嘗試根據 ObjectName 資料行以遞增順序來排序資料。 可惜的是,此查詢將失敗並出現錯誤 (指出 ObjectName 為未知),因為,當我們摘要說明時,只會在新資料表中包含 Count 和 CounterName 資料行。 若要避免此錯誤,可以直接將 ObjectName 新增至 summarize
步驟結尾,如下所示:
Perf
| project ObjectName, CounterValue , CounterName
| summarize count() by CounterName, ObjectName
| sort by ObjectName asc
讀取標頭中 summarize
行的方式如下:「依 CounterName 摘要記錄計數,並依 ObjectName 分組」。 您可以繼續將資料行 (以逗號分隔) 新增到 summarize
陳述式結尾。
以上述範例為基礎,如果我們想要同時彙總多個資料行,可透過將彙總新增到 summarize
運算子 (以逗號分隔) 來達成此目的。 在下列範例中,不僅會取得所有記錄的計數,也會取得所有記錄 (符合查詢中的任何篩選) 中 CounterValue 資料行的值總和:
Perf
| project ObjectName, CounterValue , CounterName
| summarize count(), sum(CounterValue) by CounterName, ObjectName
| sort by ObjectName asc
重新命名彙總資料行
此時似乎是討論這些彙總資料行的資料行名稱的好時機。 在此節開頭,我們說過 summarize
運算子會取得資料資料表並產生新資料表,而且只有您在 summarize
陳述式中指定的資料行將沿著管線繼續。 因此,如果您要執行上述範例,彙總的結果資料行會是 count_ 和 sum_CounterValue。
Kusto 引擎將自動建立資料行名稱,而不需我們明確建立,但通常您會發現,您偏好讓新資料行具有更易記的名稱。 您可以透過指定新名稱,後面接著 summarize
和彙總,輕鬆地在 =
陳述式中將資料行重新命名,如下所示:
Perf
| project ObjectName, CounterValue , CounterName
| summarize Count = count(), CounterSum = sum(CounterValue) by CounterName, ObjectName
| sort by ObjectName asc
現在,我們的摘要資料行將命名為 Count 和 CounterSum。
summarize
運算子的功能遠比我們在此處所說明的還多,但您應該投入時間來了解它,因為它是您計畫對 Microsoft Sentinel 資料執行之任何資料分析的重要元件。
彙總參考
有許多彙總函式,但其中一些最常使用的函式是 sum()
、count()
和 avg()
。 以下是部分清單 (請參閱完整清單):
彙總函數
函式 | 描述 |
---|---|
arg_max() |
當引數最大化時,傳回一或多個運算式 |
arg_min() |
當引數最小化時,傳回一或多個運算式 |
avg() |
傳回整個群組的平均值 |
buildschema() |
傳回容許動態輸入的所有值的最小結構描述 |
count() |
傳回群組的計數 |
countif() |
傳回包含群組述詞的計數 |
dcount() |
傳回群組元素的近似相異計數 |
make_bag() |
傳回群組內動態值的屬性包。 |
make_list() |
傳回群組內所有值的清單 |
make_set() |
傳回群組內的一組相異值 |
max() |
傳回整個群組的最大值 |
min() |
傳回整個群組的最小值 |
percentiles() |
傳回群組的百分位數近似值 |
stdev() |
傳回整個群組的標準差 |
sum() |
傳回群組內元素的總和 |
take_any() |
傳回群組的隨機非空白值 |
variance() |
傳回整個群組的變異數 |
選取:新增和移除資料行
隨著您開始更常使用查詢,可能會發現您擁有關於主體的資訊比您需要的還要多 (也就是,資料表中有太多資料行)。 或者,您需要的資訊比您擁有的還要多 (也就是,您必須新增資料行,其中將包含其他資料行分析的結果)。 讓我們看看一些用於進行資料行操作的關鍵運算子。
Project 和 project-away
Project 大致上相當於許多語言的 select 陳述式。 其允許您選擇要保留的資料行。 傳回的資料行順序將符合您在 project
陳述式中列出的資料行順序,如下列範例所示:
Perf
| project ObjectName, CounterValue, CounterName
想像一下,當您使用範圍非常廣泛的資料集時,可能會有許多想要保留的資料行,而且依名稱指定它們全部,將需要大量輸入。 針對那些情況,您可以使用 project-away,讓您能夠指定要移除的資料行,而非要保留的資料行,如下所示:
Perf
| project-away MG, _ResourceId, Type
提示
在查詢內的兩個位置中使用 project
(開頭一次且結尾再一次),這非常有用。 在查詢早期使用 project
,可透過移除您不需沿著管線傳遞的大型資料區塊,來協助改善效能。 在結尾再次使用它,可讓您移除可能已在先前步驟中建立,但最終輸出中不需要的任何資料行。
擴充
Extend 可用來建立新的導出資料行。 當您想要對現有資料行執行計算,並查看每個資料列的輸出時,這非常有用。 讓我們看一個簡單範例,我們在其中計算名為 Kbytes 的新資料行,並將 MB 值 (在現有 Quantity 資料行中) 乘以 1,024 來計算。
Usage
| where QuantityUnit == 'MBytes'
| extend KBytes = Quantity * 1024
| project ResourceUri, MBytes=Quantity, KBytes
在 project
陳述式的最後一行,將 Quantity 資料行重新命名為 Mbytes,因此,可輕鬆地分辨與每個資料行相關的量值單位。
值得注意的是,extend
也適用於已經導出的資料行。 例如,我們可以多新增一個名為 Bytes 的資料行 (從 Kbytes 導出):
Usage
| where QuantityUnit == 'MBytes'
| extend KBytes = Quantity * 1024
| extend Bytes = KBytes * 1024
| project ResourceUri, MBytes=Quantity, KBytes, Bytes
聯結資料表
您在 Microsoft Sentinel 中的大部分工作均可使用單一記錄類型來執行,但有時您想要將資料相互關聯在一起,或對另一組資料執行查閱。 就像大多數查詢語言一樣,Kusto 查詢語言提供一些用來執行各種聯結類型的運算子。 在此節中,我們將探討最常使用的運算子 union
和 join
。
Union
Union 只會取得兩個或以上的資料表並傳回所有資料列。 例如:
OfficeActivity
| union SecurityEvent
這會從 OfficeActivity 和 SecurityEvent 資料表傳回所有資料列。 Union
提供一些參數,以用來調整集合聯集的行為。 其中兩個最實用的是 withsource 和 kind:
OfficeActivity
| union withsource = SourceTable kind = inner SecurityEvent
withsource 參數可讓您指定新資料行的名稱,其在指定資料列中的值將是資料列來源資料表的名稱。 在上述範例中,將資料行命名為 SourceTable,並根據資料列而定,此值將是 OfficeActivity 或 SecurityEvent。
我們指定的另一個參數是 kind,其有兩個選項:inner 或 outer。 在上述範例中,指定了 inner,這表示在集合聯集期間將保留的唯一資料行是存在於這兩個資料表中的資料行。 或者,如果指定了 outer (這是預設值),則會傳回這兩個資料表的所有資料行。
聯結
Join 的運作方式類似於 union
,但除了聯結資料表來建立新資料表之外,我們還要聯結 rows 來建立新資料表。 就像大多數資料庫語言一樣,您可以執行的聯結類型有很多種。 join
的一般語法如下:
T1
| join kind = <join type>
(
T2
) on $left.<T1Column> == $right.<T2Column>
在 join
運算子之後,我們指定了想要執行的聯結 kind,後面接著左括弧。 您可以在括弧內指定要聯結的資料表,以及有關您想要新增的「那個」資料表的任何其他查詢陳述式。 在右括弧後面,我們使用 on 關鍵字,後面接著左側 ($left.<columnName> 關鍵字) 和右側 ($right.<columnName>) 資料行 (以 == 運算子分隔)。 以下為 inner join 的範例:
OfficeActivity
| where TimeGenerated >= ago(1d)
and LogonUserSid != ''
| join kind = inner (
SecurityEvent
| where TimeGenerated >= ago(1d)
and SubjectUserSid != ''
) on $left.LogonUserSid == $right.SubjectUserSid
注意
如果這兩個資料表對於您執行聯結所在的資料行具有相同名稱,則不需使用 $left 和 $right;您可以改為只指定資料行名稱。 不過,使用 $left 和 $right 更為明確,且通常會視為良好的做法。
如需參考,下表顯示可用的聯結類型清單。
聯結類型
加入類型 | 描述 |
---|---|
inner |
針對這兩個資料表中相符資料列的每個組合,各傳回一個。 |
innerunique |
從左側資料表傳回的資料列,在右側資料表中具有相符項的連結欄位中具有相異值。 這是預設未指定的聯結類型。 |
leftsemi |
從左側資料表中傳回在右側資料表中具有相符項的所有記錄。 只會傳回左側資料表的資料行。 |
rightsemi |
從右側資料表中傳回在左側資料表中具有相符項的所有記錄。 只會傳回右側資料表的資料行。 |
leftanti /leftantisemi |
從左側資料表中傳回在右側資料表中不具相符項的所有記錄。 只會傳回左側資料表的資料行。 |
rightanti /rightantisemi |
從右側資料表中傳回在左側資料表中不具相符項的所有記錄。 只會傳回右側資料表的資料行。 |
leftouter |
傳回左側資料表的所有記錄。 對於在右側資料表中沒有相符項的記錄,資料格值將是 Null。 |
rightouter |
傳回右側資料表的所有記錄。 對於在左側資料表中沒有相符項的記錄,資料格值將是 Null。 |
fullouter |
傳回左側和右側資料表的所有記錄,而不論是否相符。 不相符的值將是 Null。 |
提示
最佳做法是讓最小的資料表位於左側。 在某些情況下,根據您執行的聯結類型及資料表大小而定,遵循此規則可為您帶來巨大的效能優勢。
評估
回到第一個範例,您可能記得,我們在其中一行看到了 evaluate 運算子。 比起我們先前接觸的運算子,evaluate
運算子較不常使用。 不過,evaluate
運算子的運作方式很值得您花時間來了解。 再次於此處顯示第一個查詢,您將在第二行看到 evaluate
。
SigninLogs
| evaluate bag_unpack(LocationDetails)
| where RiskLevelDuringSignIn == 'none'
and TimeGenerated >= ago(7d)
| summarize Count = count() by city
| sort by Count desc
| take 5
此運算子允許您叫用可用的外掛程式 (基本上是內建函式)。 這其中許多外掛程式均著重於資料科學,例如 autocluster、diffpatterns 及 sequence_detect,可讓您執行進階分析,並探索統計異常和極端值。
上述範例中使用的外掛程式稱為 bag_unpack,可讓您非常輕鬆地取得動態資料的區塊,並將其轉換成資料行。 請記住, 動態資料是看起來非常類似 JSON 的資料類型,如下列範例所示:
{
"countryOrRegion":"US",
"geoCoordinates": {
"longitude":-122.12094116210936,
"latitude":47.68050003051758
},
"state":"Washington",
"city":"Redmond"
}
在此案例中,我們想要依 city 摘要資料,但 city 會包含在 LocationDetails 資料行內作為屬性。 若要在查詢中使用 city 屬性,必須先使用 bag_unpack 來將其轉換成資料行。
回到原始管線步驟,我們看到了下列內容:
Get Data | Filter | Summarize | Sort | Select
既然我們已考慮 evaluate
運算子,我們可以看到它代表管線中的新階段,現在看起來像這樣:
Get Data |
Parse
| Filter | Summarize | Sort | Select
還有許多其他運算子和函式範例可用來將資料來源剖析為更容易閱讀且可操作的格式。 您可以在完整文件和活頁簿中了解他們以及 Kusto 查詢語言的其餘部分。
let 陳述式
既然我們介紹了許多主要運算子和資料類型,讓我們以 let 陳述式來總結,這是讓您的查詢更容易讀取、編輯及維護的絕佳方式。
Let 可讓您建立並設定變數,或將名稱指派給運算式。 此運算式可以是單一值,但也可能是整個查詢。 以下是簡單的範例:
let aWeekAgo = ago(7d);
SigninLogs
| where TimeGenerated >= aWeekAgo
在這裡,我們指定了 aWeekAgo 的名稱,並將它設定為等於 timespan 函式的輸出,這會傳回 datetime 值。 然後,以分號終止 let 陳述式。 現在,有一個名為 aWeekAgo 的新變數,可在查詢中的任何位置使用。
如前所述,您可以使用 let 陳述式來取得整個查詢,並為結果提供名稱。 由於查詢結果 (是表格式運算式) 可用來作為查詢的輸入,因此,您可以將此具名結果視為資料表,以便在其上執行另一個查詢。 以下是稍微修改過先前範例的內容:
let aWeekAgo = ago(7d);
let getSignins = SigninLogs
| where TimeGenerated >= aWeekAgo;
getSignins
在此案例中,我們建立了第二個 let 陳述式,並將整個查詢包裝成名為 getSignins 的新變數。 就像之前一樣,我們會以分號終止第二個 let 陳述式。 然後,在最後一行呼叫該變數來執行查詢。 請注意,我們能夠在第二個 let 陳述式中使用 aWeekAgo。 這是因為我們在上一行指定了它;如果要交換 let 陳述式,以便讓 getSignins 先出現,就會收到錯誤。
現在,可以使用 getSignins 作為另一個查詢的基礎 (在相同視窗中):
let aWeekAgo = ago(7d);
let getSignins = SigninLogs
| where TimeGenerated >= aWeekAgo;
getSignins
| where level >= 3
| project IPAddress, UserDisplayName, Level
Let 陳述式可讓您以更強大且具彈性的方式協助組織查詢。 Let 可以定義純量和表格式值,以及建立使用者定義的函式。 當您組織可能執行多個聯結的更複雜查詢時,它們確實可派上用場。
下一步
儘管此文章僅觸及表面,但您現在已獲得必要的基礎,而且我們已說明您最常用來在 Microsoft Sentinel 中完成工作的部分。
適用於 Microsoft Sentinel 的進階 KQL 活頁簿
利用 Microsoft Sentinel 本身的 Kusto 查詢語言活頁簿:適用於 Microsoft Sentinel 的進階 KQL 活頁簿。 它為您提供在日常安全性作業期間可能遇到之許多情況的逐步說明和範例,同時也指出許多現成可用之分析規則、活頁簿、搜捕規則的範例,以及使用 Kusto 查詢的更多元素。 從 Microsoft Sentinel 中的 [活頁簿] 刀鋒視窗啟動此活頁簿。
進階 KQL Framework 活頁簿 - 讓您成為精通 KQL 的人 \(英文\) 是一篇出色的部落格文章,可為您說明如何使用此活頁簿。
更多資源
請參閱這個學習、定型及技能資源的集合,以擴大並強化您對 Kusto 查詢語言的知識。