DataPrime 經營者

本指南提供 IBM® Cloud Logs DataPrime 運算符號的詞彙。

block

filter 的否定。 篩選出條件為真的所有事件。 使用 filter!(condition) 可以達到相同的效果。

block $d.status_code >= 200 && $d.status_code <= 299         # Leave all events which don't have a status code of 2xx

資料使用下列欄位顯示:

  • $m - 事件元資料

    • timestamp
    • severity- 可能的值為 Verbose, Debug, Info, Warning, ErrorCritical
    • priorityclass- 可能的值為 high, mediumlow
    • logid
  • $l - 事件標籤

    • applicationname
    • subsystemname
    • category
    • classname
    • computername
    • methodname
    • threadid
    • ipaddress
  • $d -使用者的資料

bottom

沒有分組變化:將傳回的行數限制為指定的數目,並根據一組表達式對結果排序。

order_direction := "descending"/"ascending" according to top/bottom
bottom <limit> <result_expression1> [as <alias>] [, <result_expression2> [as <alias2>], ...] by <orderby_expression> [as alias>]

例如,下列查詢:

bottom 5 $m.severity as $d.log_severity by $d.duration

將導致以下形式的日誌:

[
   { "log_severity": "Debug", "duration":  1000 }
   { "log_severity": "Warning", "duration": 2000 },
   ...
]

群組變化:將傳回的行數限制為指定的數目,並透過一組聚集表達式進行分組,並透過一組表達式進行排序。

order_direction := "descending"/"ascending" according to top/bottom

bottom <limit> <(groupby_expression1|aggregate_function1)> [as <alias>] [, <(groupby_expression2|aggregate_function2)> [as <alias2>], ...] by <(groupby_expression1|aggregate_function1)> [as <alias>]

例如,下列查詢:

bottom 10 $m.severity, count() as $d.number_of_severities by avg($d.duration) as $d.avg_duration

將導致以下形式的日誌:

[
   { "severity": "Warning", "number_of_severities": 50, avg_duration: 1000 },
   { "severity": "Debug", "number_of_severities":  10, avg_duration: 2000 }
   ...
]

支援的聚合功能列於「聚合功能」一節。

choose

只留下所提供的按鍵路徑,捨棄所有其他按鍵。 完全支援輸出中的巢狀關鍵路徑。

(choose|select) <keypath1> [as <new_keypath>],<keypath2> [as <new_keypath>],...

範例:

choose $d.mysuperkey.myfield
choose $d.my_superkey.mykey as $d.important_value, 10 as $d.the_value_ten

convert

轉換鍵的資料類型。

datatypes 關鍵字是可選的,可以用來提高可讀性。

(conv|convert) [datatypes] <keypath1>:<datatype1>,<keypath2>:<datatype2>,...

範例:

convert $d.level:number
conv datatypes $d.long:number,$d.lat:number
convert $d.data.color:number,$d.item:string

count

傳回包含前述運算符產生的行數的單一行。

count [into <keypath>]

可以提供別名來覆寫寫入結果的 keypath。

例如,查詢的以下部分:

count into $d.num_rows

將產生以下形式的單一行:

{ "num_rows": 7532 }

countby

回傳一列依表達式分組的所有行數。

countby <expression> [as <alias>] [into <keypath>]

可以提供別名來覆寫結果要寫入的 keypath。

例如,查詢的以下部分

countby $d.verb into $d.verb_count

將產生每組一行。

它在功能上與

groupby $data.verb calculate count() as $d.verb_count

create

建立新的鍵,並將其值設定為表達式的結果。 鍵的建立是粒狀的,這表示路徑中的父鍵不會被覆蓋。

  (a|add|c|create) <keypath> from <expression> [on keypath exists (fail|skip|overwrite)] [on keypath missing (fail|create|skip)] [on datatype change (skip|fail|overwrite)

可透過加入下列子句來控制建立:

  • 新增 keypath exists 允許選擇在關鍵路徑已經存在時該怎麼做。

    • overwrite- 覆寫舊值。 這是預設值

    • fail- 查詢失敗

    • skip- 跳過建立金鑰

  • 新增 keypath missing 選擇在新的關鍵路徑不存在時該怎麼做。

    • create- 建立金鑰。 這是預設值

    • fail- 查詢失敗

    • skip- 跳過新金鑰的建立

  • datatype changed 上新增選擇如果鍵已經存在,而新資料改變了值的資料類型時該怎麼做。

    • overwrite- 覆寫數值。 這是預設值。

    • fail- 查詢失敗

    • skip- 留下具有原始值(和類型)的鍵

範例:

create $d.radius from 100+23
c $d.log_data.truncated_message from $d.message.substring(1,50)
c $data.trimmed_name from $data.username.trim()

create $d.temperature from 100*23 on datatype changed skip

distinct

為提供的表達式的每個不同組合傳回一列。

distinct <expression> [as <alias>] [, <expression_2> [as <alias_2>], ...]

此運算符號的功能與 groupby 相同,但沒有任何聚合功能。

enrich

使用來自查詢表的額外上下文來豐富您的日誌。

使用資料上傳尋找表資料流圖標 > 資料豐富 > 自訂豐富。

enrich <value_to_lookup> into <enriched_key> using <lookup_table>
  • value_to_lookup- 將在查詢表中查詢的字串表達式。

  • enriched_key- 儲存增益結果的目的地鍵。

  • lookup_table- 要使用的自訂增益表名稱。

該表的欄位將作為子鍵加入到目的鍵中。 如果 value_to_lookup 未找到,目的鍵將為空。 然後,您可以使用 DataPrime 功能篩選結果,例如依據豐富欄位中的特定值來篩選記錄。

範例:

原始日誌:

{
    "userid": "111",
    ...
}

自訂豐富查詢表名為 my_users

樣本查詢表
ID 名稱 部門
111 John 金融
222 愛蜜莉 採用 AI

執行下列查詢:

enrich $d.userid into $d.user_enriched using my_users

將產生以下豐富的日誌:

{
    "userid": "111",
    "user_enriched": {
        "ID": "111",
        "Name": "John",
        "Department": "Finance"
    },
    ...
}

使用 enrich 時,請考慮下列事項:

  • 執行 DataPrime 查詢來源 lookup_table 以檢視豐富表。

  • 如果原始日誌已包含增強金鑰:

    • 如果 value_to_lookup 存在于 lookup_table 中,子键将用新值更新。 如果 value_to_lookup 不存在,則會保留其目前的值。

    • 任何其他不在 lookup_table 中列的子代鍵將保留其現有值。

  • lookup_table 中的所有值都被視為字串。 這表示:

    • value_to_lookup 必須是字串格式。

    • 所有值都以字串格式豐富。 然後您可以使用適當的函式,將它們轉換成您偏好的格式 (例如 JSON、時間戳記)。

extract

從某個字串值抽取資料到一個新的物件。 支援多種萃取方法。

(e|extract) <expression> into <keypath> using <extraction-type>(<extraction-params>) [datatypes keypath:datatype,keypath:datatype,...]

以下是支援的萃取方法及其參數:

  • regexp- 根據 regexp capture-groups 建立新物件

  • e- 名稱為 capture-groups 的正則表 達式。

範例:

extract $d.my_text into $d.my_data using regexp(e=/user (?<user>.*) has logged in/)
  • kv- 從包含 key=value key=value... 對的字串中抽取新物件

  • pair_delimiter- 資料對之間的分隔符。 預設為(空格)

  • key_delimiter- 分隔鍵和值的分隔符。 預設為 =。

範例:

extract $d.text into $d.my_kvs using kv()
e $d.text into $d.my_kvs using kv(pair_delimiter=' ',key_delimiter='=')
  • jsonobject- 從包含已編碼 json 物件的字串中抽取新物件,有可能嘗試在解碼成 json 之前先解讀字串

  • max_unescape_count- 解析 json 前要取消轉義的最大層數。 預設值為 1。 當設定為 1 或更多時,引擎會偵測值是否包含轉換的 JSON 字串,並解除轉換,直到超過其可解析次數或最大解除轉換次數。

範例:

e $d.json_message_as_str into $d.json_message using jsonobject(max_unescape_count=1)

透過使用 datatypes 子句,可以提供資料類型資訊作為抽取的一部分。 例如,將資料類型 my_field:number 加入抽取,會導致抽取 my_field keypath 成為數字而非字串。 例如:

extract $d.my_msg into $d.data using kv() datatypes my_field:number

擷取的資料總是以物件的形式進入新的 keypath,允許在該新物件中進一步處理新的鍵。 例如:

# Assuming a dataset which look like that:
{ "msg": "query_type=fetch query_id=100 query_results_duration_ms=232" }
{ "msg": "query_type=fetch query_id=200 query_results_duration_ms=1001" }

# And the following DataPrime query:
source logs
  | extract $d.msg into $d.query_data using kv() datatypes
query_results_duration_ms:number
  | filter $d.query_data.query_results_duration_ms > 500

# The results will contain only the second message, in which the duration is greater than 500 ms

filter

篩選事件,只留下條件求值為真的事件。

(f|filter|where) <condition-expression>

範例:

f $d.radius > 10
filter $m.severity.toUpperCase() == 'INFO'
filter $l.applicationname == 'myapp'
filter $l.applicationname == 'myapp' && $d.msg.contains('failure')

與 null 比較只適用於標量值,在 JSON 子樹上永遠會回傳 null。

當使用條件比較 keypath 與 null 時,這只會對標量值(字串、數字、時間戳記等)有效。 對於指定文件中的 JSON 物件,與 null 比較永遠會回傳 null。

使用功能篩選器來執行複雜的搜尋。

範例:

filter in($l.applicationname, 'ibm-audit-event', 'ibm-platform-logs') #
filter ipInSubnet(ip_address, '155.64.5.20/24')

e - 篩選指定範圍內的 IP 位址。 filter 可以與函式結合,以很少的語法執行複雜的搜尋,例如使用 ipInSubnet 函式:

篩選 ipInSubnet(ip_address, ' 154.67.8.20/24 ')

groupby

根據指定的分組表述將前面運算符的結果分組,並為每個建立的組計算集合函數。

groupby <grouping_expression> [as <alias>] [, <grouping_expression_2> [as <alias_2>], ...] [calculate]
  <aggregate_function> [as <result_keypath>]
  [, <aggregate_function_2> [as <result_keypath_2], ...]

例如,下列查詢:

groupby $m.severity calculate sum($d.duration)

將導致以下形式的日誌:

{ "severity": "Warning", "_sum": 17045 }

分組表達式的關鍵路徑總是在 $d 之下。 使用 as 關鍵字,我們可以重新命名分組表達式和聚集函數的關鍵路徑。 例如:

groupby $l.applicationname as $d.app calculate sum($d.duration) as $d.sum_duration

將導致以下形式的日誌:

{ "app": "web-api", "sum_duration": 17045 }

使用 groupby 運算符查詢時,可以對結果桶套用 聚集函數 (例如 avg, max, sum)。 此功能可讓您在表達式本身內部操作聚集表達式,讓您同時計算和操作資料。

join

Join 根據指定的條件,將目前 (左) 的查詢結果與第二個 (右) 的查詢結果合併。 它提供多種形式來控制資料的組合方式,並支援嵌套,讓正確的查詢包含自己的 join 指令。

Join 支援三種變化:

join left|join
對於左側查詢中的每個事件,指令會根據指定的條件從右側查詢中選取符合的事件。 如果找不到符合的資料,則會包含左側查詢中所有事件的資料。 來自右側查詢的不匹配資料會被設定為 null
join full
為每個事件傳回一列,包括那些在任一查詢(左或右)中可能沒有匹配的事件,用 null 填補缺失值。
join inner
只返回兩次查詢都有非空結果的資料列。
join cross
將左方查詢的每一行與右方查詢的每一行配對,產生完整的笛卡兒積。 與其他 join 類型不同,join cross 不支援 onusing conditions。 它的功能與 join inner 相似,但沒有任何篩選,只會回傳所有可能的行組合。

對於 left (預設)、innerfull,您可以使用 on 關鍵字指定 join 條件,或使用 keyword 指定關鍵路徑。 笛卡兒乘積會經過篩選,只保留條件為真或關鍵路徑值在兩側都符合的資料。

由於所有連接(不論修改器為何)都是基於笛卡兒乘積,因此如果 join 條件多次匹配,就可能出現重複結果。 為了防止意外重複,請考慮預先處理子查詢,例如使用區別。

語法:

<left_side_query> | join [left/inner/full] (<right_side_query>) on <condition> into <right_side_target>
<left_side_query> | join [left/inner/full] (<right_side_query>) using <join_keypath_1> [, <join_keypath_2>, ...] into <right_side_target>
<left_side_query> | join cross (<right_side_query>) into <right_side_target>

其中:

  • <right_side_query>- <right_side_query> 表示要加入的新查詢。

  • <left_side_query> - <left_side_query> 表示初始查詢,例如,在查詢 source logs | filter x != null | join ... 中,左側查詢為 source logs | filter x != null

  • <condition>- 如果兩個查詢的結果都應該連接的條件。

    在條件中,您可以使用 left=>right=> 前綴,分別指左側和右側查詢的事件。 但是,如果關鍵路徑只存在於其中一個查詢中,則不需要。

    在條件中使用 == (相等) 運算符時,必須比較左側查詢的關鍵路徑與右側查詢的關鍵路徑。 不過,由於 keypaths 必須是唯一的,或是以 left=>right=> 為前綴,因此操作項的順序並不重要。

  • <join_keypath_n>- <join_keypath_n> 作為連接鍵意指將左側查詢和右側查詢結果中給定鍵路徑相同的結果連接起來。

  • <right_side_target>- 關鍵路徑,加入的資料會被加入到目前的查詢中。

join 範例

您有一個名為 users自訂豐富 資料表,提供與名稱相關的 ID 資訊:

{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }

而這些資料提供登入事件和使用者 ID,但不提供與使用者 ID 相關聯的使用者名稱。

{ "userid": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "userid": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z" }

使用 join,您可以使用查詢來傳回資料,包括所需的資料。

source users | join (source logs | countby userid) on id == userid into logins

此查詢的處理方式如下:

  • source 是自訂豐富表 (users)。

  • join 中,由 userid 欄位產生計數。 這提供了我們的 count 統計資料。

  • 自訂增益表中的 id 欄位會與記錄中的 userid 欄位進行比較。

  • 結果會推入 logins 鍵。 如果 logins 鍵已存在於左側查詢中,則會被覆蓋。

例如:

{ "id": "111", "name": "John", "logins": { "userid": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "userid": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }

現在右側查詢的結果在 logins 欄位內。 請注意,使用者 ID 333 (Alice) 沒有登入,因此登入欄位為 null,因為 join 條件沒有匹配的結果。

join 使用 using 關鍵字的範例

請考慮我們的登入資料集是否:

{ "id": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }

在這種情況下,連接兩邊的資料都包含欄位 id。 在這種情況下,可以使用 using 關鍵字來利用共用資料:

source users | join (source logins | countby id) using id into logins

結果會類似,但傳回的欄位不是 userid,而是 id

{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }

如果您有兩個欄位名稱不同,但可以簡化您的 join 查詢,您可以使用 move 移動其中一個欄位,使兩邊的關鍵路徑相符。

join 使用 left=>right=> 關鍵字的範例

您可以使用 left=>right=> 前綴來指左側和右側查詢的事件。 但是,如果關鍵路徑只存在於其中一個查詢中,則不需要。

使用上一個範例中的資料,考慮查詢:

source users | join (source logins | countby id) on left=>id == right=>id into logins

這是必須的,因為兩個資料集都包含一個同名的欄位 (id)。為了讓 DataPrime 能夠唯一識別欄位,它必須知道我們所指的是查詢的哪一邊。 此查詢的結果與之前使用 using 關鍵字的結果相同。

在條件中使用 == (相等) 運算符時,必須比較左側查詢的關鍵路徑與右側查詢的關鍵路徑。 不過,由於 keypaths 必須是唯一的,或是以 left=>right=> 為前綴,因此操作項的順序並不重要。

join full 範例

您有一個名為 users自訂豐富 資料表,提供與名稱相關的 ID 資訊:

{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }

並考慮這個資料集:

{ "id": "001", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }

第二組文件 (右側查詢) 包含第一組文件 (左側查詢) 中不存在的記錄項目 "id": "001"。 如果您使用標準連接,右側查詢的此項目將會被忽略,並且不會出現在結果中。 為了確保每個 id 欄位都包含在輸出中,不論它是否出現在左側或右側查詢中,您可以使用 join full

source users | join full (source logins | countby id) using id into logins

此查詢結果:

{ "id": "001", "name": "null", "logins": { "id": "001", "_count": 1 } }
{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }

透過使用 join full,兩個資料集中的所有 id 欄位都會被保留,而任何缺失的值都會被設定為 null

join full 在兩個查詢的結果都包含時間桶時特別有用。 例如,如果左側查詢的結果缺少特定小時的時間桶 (例如 XX:XX:XX),則 join full 會包含此資料點。 這對於比較圖表上的兩個時間序列特別有用。

join inner 範例

如果要移除左側或右側查詢產生空值的列結果中的任何行,請使用 join inner

此查詢使用先前的資料,移除兩邊資料不匹配的資料列:

source users | join inner (source logins | countby id) using id into logins
  • 左側查詢 source users 擷取包含欄位 idname 的使用者資料集。

  • 右側查詢 (source logins | countby id) 擷取登入資料集,以 id 分組,並計算每個 id 的出現次數。

  • join inner 匹配兩個資料集中都存在 id 的記錄,並將資料合併為單一記錄。

  • 最終結果會剔除在兩個資料集中都不匹配的行。

在這種情況下,對於上述兩個文件集,結果如下:

{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }

join cross 範例

join cross 將左方查詢的每一行與右方查詢的每一行結合,產生兩個集合的笛卡兒積。

假設我們有以下來自名為 users 的自訂豐富表的文件。

{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }

現在,考慮這組名為 logs 的文件。

{ "id": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }

下面的查詢會產生 userslogs 資料集的笛卡兒積,因為 join cross 會將左側查詢的每一條記錄與右側查詢的每一條記錄配對,而不考慮任何匹配條件。

source users | join cross (source logs) into logins
{ "id": "111", "name": "John", "logins": { "id": "111", "timestamp": "2022-01-01T12:00:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "111", "timestamp": "2022-01-01T12:30:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "111", "timestamp": "2022-01-01T12:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "111", "timestamp": "2022-01-01T12:30:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "111", "timestamp": "2022-01-01T12:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "111", "timestamp": "2022-01-01T12:30:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }

查詢結果是每個使用者與每個記錄項目配對:來自 users 的 3 行乘以來自 logs 的 5 行,結果是 15 行。 每個使用者 (John, Emily, Alice) 與每個記錄項目配對。

當您有興趣看到資料的完整畫面時,使用 join cross 特別有用,然後在這些結果中加入 leftright join

限制與注意事項

在查詢中包含 join 時會有一些限制和注意事項:

  • join 條件僅支援關鍵路徑相等 (==)。如果需要多個相等條件,可以使用 && (邏輯和)結合。

  • 連接的一邊 (目前查詢或連接查詢) 必須很小 (< 200MB )。 您可以使用 filterremove 來縮小查詢的大小。

  • 左外連接要求條件中的所有欄位都是非空的。 任何空列都不會被連接。 若要包含右側查詢空列,請使用 join full。 若要排除左連結和右連結所產生的所有空列,請使用 join inner

limit

將輸出限制在第一個 event-count 事件。

limit <event-count>

範例:

limit 100

move

移動一個按鍵(包括其子按鍵,如果有)到新的位置。

(m|move) <source-keypath> to <target-keypath>

範例:

move $d.my_data.hostname to $d.my_new_data.host
m $d.kubernetes.labels to $d.my_labels

multigroupby

multigroupby 將兩個或多個包含 groupby 的查詢結果串聯為單一資料集。

使用 multigroupby

  • 效率:多次查詢只需掃描一次資料。

  • 同步:結果保持一致,避免執行獨立查詢時可能產生的差異。

multigroupby  (<grouping_expression_1> as <alias> [, <grouping_expression_2> as <alias_2>, ...])  [, (<grouping_expression_1> as <alias> [, <grouping_expression_2> as <alias_2>, ...]), ...][calculate]  <aggregation_expression> [as <result_keypath>] [, <aggregation_expression_2> [as <result_keypath_2], ...]

透過對兩個群組使用相同的別名 app,相同的語意會以統一的欄位呈現。 在下一個範例中,使用了不同的別名,資料會合併,但不會合併。

範例 - Multigroupby 具有相同的別名

在這個範例中,我們要將記錄分組如下:

  • 首先是 applicationname (app),然後進一步是 subsystemname (ss),為每個組合提供詳細的計數。

  • 然後獨立於 applicationname,得出每個應用程式的日誌總計數,不論 subsystems

source logs
| multigroupby ($l.applicationname as app, $l.subsystemname as ss),($l.applicationname as app) calculate count() | orderby app,ss

結果將類似於:

[
    {
        "_count0": 241,
        "app": "monitoring24",
        "ss": "NO_SUBSYSTEM_NAME"
    },
    {
        "_count0": 231,
        "app": "monitoring24",
        "ss": "logs-opentelemetry-agent"
    },
    {
        "_count0": 15,
        "app": "monitoring24",
        "ss": "logs-opentelemetry-collector"
    },
    {
        "_count0": 487,
        "app": "monitoring24",
        "ss": null
    }
]

前三行代表 appss 每個唯一組合的計數。 例如,有 241 個日誌,其中應用程式 (app) 是 monitoring24,子系統 (ss) 是 NO_SUBSYSTEM_NAME。 同樣地,同一應用程式也有 231 個日誌,但子系統 logs-opentelemetry-agent,以此類推。

最後一行提供應用程式的日誌總計數 monitoring24,彙總所有子系統。 在此,_count0 是 487,即上述所有詳細數字的總和。 ss 欄位是 null,表示這是整個申請的總和。

透過對兩個群組使用相同的別名 app,相同的語意會以統一的欄位呈現。 在下一個範例中,使用了不同的別名,資料會合併,但不會合併。

範例 - Multigroupby 與不同的別名

現在,請考慮為查詢引入 2 個不同別名的效果。 在這種情況下,第一組群標示為 app1,表示 applicationnamess 結合,而第二組群標示為 app2,表示 applicationname alone

source logs | multigroupby ($l.applicationname as app1, $l.subsystemname as ss),($l.applicationname as app2) calculate count()

結果將類似於:

[
    {
        "_count0": 241,
        "app1": "monitoring24",
        "app2": null,
        "ss": "logs-opentelemetry-agent"
    },
    {
        "_count0": 231,
        "app1": "monitoring24",
        "app2": null,
        "ss": "logs-opentelemetry-collector"
    },
    {
        "_count0": 15,
        "app1": "monitoring24",
        "app2": null,
        "ss": "no_subsystem_name"
    },
    {
        "_count0": 487,
        "app1": null,
        "app2": "monitoring24",
        "ss": null
    }
]

透過引入獨立的別名 (app1app2),查詢保持了兩個群組之間的區別,而不是合併資料。 app1 已填入且 app2null 的行對應於 applicationnamesubsystemname 的詳細分組。 例如,241 份記錄與 app1 = "monitoring24"ss = "logs-opentelemetry-agent" 相關聯。 這遵循第一組邏輯。

app2 已被填入且 app1null 的那一行反映了第二組的總計數,在這一組中,日誌僅按 applicationname 進行聚合。 對於 app2 = "monitoring24",計數是 487,而 app1ss 都是 null,以表示這個更高層次的彙總。

透過使用不同的別名 (app1app2),查詢並不會合併資料,而是清楚說明每個結果屬於哪一組。 整體邏輯維持不變:特定組合的詳細計數及總計數。

Multigroupby 限制

multigroupby 不會回傳重複群組集的重複資料。

如果使用 app 和 ss 執行 multigroupby,預期的結果 (如果允許重複) 可能如下所示:

[
  {"app": "monitoring24", "ss": "logs-opentelemetry-agent", "_count0": 2},
  {"app": "monitoring24", "ss": "logs-opentelemetry-collector", "_count0": 2}
]

由於限制的關係,multigroupby 會合併這些重複資料,並只會為每個唯一的組合返回一條記錄,即使該組合在資料中出現多次:

[
  {"app": "monitoring24", "ss": "logs-opentelemetry-agent", "_count0": 2}
]

orderby / sortby / order by / sort by

按表達值的升序/降序排序資料。 支援以多重表達方式排序。

(orderby|sortby|order by|sort by) <expression> [(asc|desc)] , ...

範例:

orderby $d.myfield.myfield
orderby $d.myfield.myfield:number desc
sortby $d.myfield desc

數值排序可透過將表達式轉換為類型:來完成,例如 <expression>: number。 在某些情況下,引擎會自動推斷。

redact

從某些 keypath 值取代所有符合 regexp 模式的子串,有效地隱藏原始內容。

匹配關鍵字是可選的,可用來增加可讀性。

redact <keypath> [matching] /<regular-expression>/ to '<redacted_str>'
redact <keypath> [matching] <string> to '<redacted_str>'

範例:

redact $d.mykey /[0-9]+/ to 'SOME_INTEGER'
redact $d.mysuperkey.user_id 'root' to 'UNKNOWN_USER'
redact $d.mysuperkey.user_id matching 'root' to 'UNKNOWN_USER'

remove

從物件移除關鍵字。

r|remove <keypath1> [ "," <keypath2> ]...

範例:

r $d.mydata.unneeded_key
remove $d.mysuperkey.service_name, $d.mysuperkey.unneeded_key

replace

使用新值取代某些關鍵的值。

如果替換值改變了 keypath 的資料類型,則可使用下列選項:

  • skip- 替換將被忽略

  • fail- 查詢將會失敗

  • overwrite- 新值會覆蓋先前的值,改變鍵路徑的資料類型

replace <keypath> with <expression> [on datatype changed skip/fail/overwrite]

範例:

replace $d.message with null
replace $d.some_superkey.log_length_plus_10 with $d.original_log.length()+10 on datatype changed overwrite

roundtime

將事件發生的時間取整為某個時間間隔,可能會為結果建立一個新的鍵。

  • 如果 source-timestamp 未提供,則 $m.timestamp 會用作來源時間戳記。

  • 如果提供 source-timestamp,它應該是 timestamp 類型 (或轉換為 )。

預設情況下,捨入的結果會寫回源鍵路徑 source-timestamp。 如果提供了 target-keypath,則 source-timestamp 不會修改,結果會寫入新的 target-keypath

支援的時間間隔為

  • Xns - X 納秒 (請小心來源時間戳記的解析度)
  • Xms - X 毫秒
  • Xs - X 秒
  • Xm - X 分鐘
  • Xh - X 小時
  • Xd - X 天

以及從較大的時間單位到較小的時間單位的任何組合,例如,1h30m15s

roundtime [source-timestamp] to <time-interval> [into <target-keypath>]

範例:

roundtime to 1h into $d.tm
roundtime $d.timestamp to 1h
roundtime $d.my_timestamp: timestamp to 60m
roundtime to 60s into $d.rounded_ts_to_the_minute

source

設定 DataPrime 查詢所依據的資料來源。

(source|from) <data_store>

其中 data_store 可以是任一種:

  • logs

  • 自訂增益的名稱。 在這種情況下,指令會顯示自訂的豐富表。

範例:

source logs

stitch

stitch 指令會執行兩個資料集的水平聯合,將兩個資料集並排合併。 它會將一個資料集的行與另一個資料集的行對齊,並將它們的列串聯起來,建立一個單一、統一的資料集。

使用 stitch 指令時:

  • 資料集必須是有序的,因為行是依序合併的 (也就是資料集 A 的第 1 行與資料集 B 的第 1 行縫合)。

  • 如果其中一個資料集的資料行數多於另一個,未對應的資料行會在拼接的列中出現空值。

  • 產生的資料集將包含兩個資料集中的所有欄位。

stitchunion 不同。stitch 以逐行追加列的方式水平合併資料集。union 以垂直追加行的方式,將資料集疊在彼此之上。

... | stitch (<subquery>) into <target-keypath>

範例:

您有這些 自訂的豐富表

sales 數據集:

{ "product": "Widget", "sales": 100 }
{ "product": "Gadget", "sales": 200 }
{ "product": "Dashboard", "sales": 150 }

revenue 數據集:

{ "product": "Widget", "revenue": 5000 }
{ "product": "Gadget", "revenue": 8000 }
{ "product": "Dashboard", "revenue": 6000 }

在此查詢中,您將並排結合這些資料集,確保其中一個資料集的每一行都與另一個資料集的對應行對齊:

source sales | orderby product
| stitch (source revenue | orderby product) into combined_data
  • source salessales 資料集中取得所有資料,其中包含產品及其對應的銷售數字。

  • orderby productproduct 欄位排序 sales 資料集,以建立一致的行排列順序。

  • stitch (source revenue | orderby product)revenue 資料集中取得資料列,並依 product 欄位排序。 salesrevenue 資料集以水平方式合併,排序後依順序對齊行。

  • into combined_data 將合併的資料集儲存到一個名為 combined_data 的變數中。

查詢的結果是

{ "product": "Widget", "sales": 100, "combined_data": { "product": "Widget", "revenue": 5000 } }
{ "product": "Gadget", "sales": 200, "combined_data": { "product": "Gadget", "revenue": 8000 } }
{ "product": "Dashboard", "sales": 150, "combined_data": { "product": "Dashboard", "revenue": 6000 } }

如果資料集的行數不相等,stitch 指令會以 null 填補缺失值。

例如,請考慮下列資料集:

sales 資料集(3 行):

{ "product": "Widget", "sales": 100 }
{ "product": "Gadget", "sales": 200 }
{ "product": "Dashboard", "sales": 150 }

revenue 資料集(2 行):

{ "product": "Widget", "revenue": 5000 }
{ "product": "Gadget", "revenue": 8000 }

執行此查詢:

source sales | orderby product
| stitch (source revenue | orderby product) into combined_data

結果為:

{ "product": "Widget", "sales": 100, "combined_data": { "product": "Widget", "revenue": 5000 } }
{ "product": "Gadget", "sales": 200, "combined_data": { "product": "Gadget", "revenue": 8000 } }
{ "product": "Dashboard", "sales": 150, "combined_data": { "product": "Dashboard", "revenue": null } }

stitch 使用注意事項

  • 行與行之間必須有邏輯上的關聯,縫合才能產生有意義的結果。 確保兩個資料集中的行代表相同的實體,且順序相同。 例如,如果 sales 資料集中的 product 欄位與 revenue 資料集中 product 欄位的對應行不匹配,則縫合將無法如預期般運作。

  • 如果資料集的行數不同,結果會包含 null 較短資料集中的缺失資料值。

top

沒有分組變化:將傳回的行數限制為指定的數目,並根據一組表達式對結果排序。

order_direction := "descending"/"ascending" according to top/bottom

top <limit> <result_expression1> [as <alias>] [, <result_expression2> [as <alias2>], ...] by <orderby_expression> [as alias>]

例如,下列查詢:

top 5 $m.severity as $d.log_severity by $d.duration

將導致以下形式的日誌:

[
   { "log_severity": "Warning", "duration": 2000 },
   { "log_severity": "Debug", "duration":  1000 }
   ...
]

群組變化:將傳回的行數限制為指定的數目,並透過一組聚集表達式進行分組,並透過一組表達式進行排序。

order_direction := "descending"/"ascending" according to top/bottom

top <limit> <(groupby_expression1|aggregate_function1)> [as <alias>] [, <(groupby_expression2|aggregate_function2)> [as <alias2>], ...] by <(groupby_expression1|aggregate_function1)> [as <alias>]

例如,下列查詢:

top 10 $m.severity, count() as $d.number_of_severities by avg($d.duration) as $d.avg_duration

將導致以下形式的日誌:

[
   { "severity": "Debug", "number_of_severities":  10, avg_duration: 2000 }
   { "severity": "Warning", "number_of_severities": 50, avg_duration: 1000 },
   ...
]

您可以套用 彙集功能。

union

union 指令會將兩個或更多資料集的結果串接成一個資料集。 這可讓使用者將多個查詢的結果結合為一個天衣無縫的資料集。 一個資料集可以是透過管道輸入 union 指令的結果集,然後與另一個資料集串接。

當您需要從一個資料集追加行到另一個資料集時,請使用 union。

處理大型資料集時,為了最佳化效能,可考慮在使用 union 之前,先使用 filter 來限制每個資料集的行數。

使用者每次查詢 優先洞察 資料時,最多只能使用 10 個 union 指令。 其他資料沒有限制。

unionjoin

  • union 結合結果集,方法是將一個資料集的記錄追加到另一個資料集。 它不會合併或比較來自多個文件的欄位。

  • join 根據條件匹配並合併兩個資料表中的列,建立包含兩個資料表資料的行。

<query> | union <query>

結合 2 個資料集的範例

您有這 2 個資料集:

日誌為 Team 58942

{ "id": "111", "name": "John" , "team.id": "58942" }
{ "id": "222", "name": "Emily", "team.id": "58942" }
{ "id": "333", "name": "Alice", "team.id": "58942" }

日誌為 Team 98361

{ "userid": "111", "timestamp": "2022-01-01T12:00:00Z", "team.id": "98361" }
{ "userid": "111", "timestamp": "2022-01-01T12:30:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }

您想要將它們合併為一個資料集。 您可以使用 union

source logs(teamId=58942) | union logs(teamId=98361)

查詢會處理兩個資料集:

  • source logs(teamId=58942):擷取所有文件 Team 58942
  • union logs (teamID=98361):將 Team 98361 資料集附加到 Team 58942 資料集

這會產生以下資料集:

{ "id": "111", "name": "John" , "team.id": "58942" }
{ "id": "222", "name": "Emily", "team.id": "58942" }
{ "id": "333", "name": "Alice", "team.id": "58942" }
{ "userid": "111", "timestamp": "2022-01-01T12:00:00Z", "team.id": "98361" }
{ "userid": "111", "timestamp": "2022-01-01T12:30:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }