DataPrime オペレーター

このガイドでは、 IBM® Cloud Logs DataPrime オペレータの用語集を提供しています。

block

filter の否定。 条件が真であるすべてのイベントを除外する。 !(condition)filter を使っても同じ効果が得られる。

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, Error です、 Critical
    • 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>]

結果が書き込まれるキーパスを上書きするために、エイリアスを指定することができる。

例えば、クエリの次の部分:

count into $d.num_rows

その結果、次のような形式の1行が表示される:

{ "num_rows": 7532 }

countby

式でグループ化されたすべての行を数える行を返す。

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

結果が書き込まれるキーパスを上書きするために、エイリアスを指定することができる。

例えば、次のようなクエリがあります

countby $d.verb into $d.verb_count

各グループに1行ずつ表示される。

と機能的には同じである

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

指定した式の明確な組み合わせごとに1行を返す。

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 が見つからない場合、デスティネーション・キーはNULLになる。 その後、 DataPrime の機能を使用して、エンリッチフィールドの特定の値でログをフィルタリングするなど、結果をフィルタリングできます。

例:

オリジナルのログ

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

my_users と呼ばれるカスタム・エンリッチメント・ルックアップ・テーブル:

ルックアップテーブルのサンプル
ID 名前 所属
111 ジョン 金融
222 エミリー IT部門

以下のクエリーを実行する:

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

その結果、ログは次のように濃縮される:

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

enrich を使用する際は、以下の点を考慮すること:

  • DataPrime クエリーソース lookup_table を実行して、エンリッチメントテーブルを表示します。

  • 元のログがすでにエンリッチキーを含んでいる場合:

    • lookup_tablevalue_to_lookup が存在する場合、サブキーは新しい値で更新される。 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- 正規表現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オブジェクトを含む文字列から新しいオブジェクトを取り出す

  • max_unescape_count- jsonをパースする前に、エスケープを解除するレベルの最大数。 デフォルトは、1 です。 1以上に設定すると、エンジンは値にエスケープされたJSON文字列が含まれているかどうかを検出し、解析可能または最大アンエスケープ数を超えるまでアンエスケープします。

例:

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

datatypes句を使うことで、抽出の一部としてデータ型情報を提供することができる。 た と えば、 抽出に datatypes my_field:number を追加す る と、 抽出 my_field のキーパスは文字列ではな く 数値にな る。 以下に例を示します。

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

抽出されたデータは常にオブジェクトとして新しいキーパスに入り、その新しいオブジェクトの中で新しいキーをさらに処理することができる。 以下に例を示します。

# 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を返します。

キーパスと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アドレスをフィルタリングする。 フィルタを関数と組み合わせることで、例えば 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 は、現在の (左の) クエリの結果を、指定された条件に基づいて 2 番目の (右の) クエリとマージします。 データをどのように組み合わせるかを制御するための複数のフォームを提供し、ネストをサポートしているため、適切なクエリに独自の join コマンドを含めることができる。

Join は3つのバリエーションをサポートしている:

join left|join
左のクエリの各イベントに対して、コマンドは指定された条件に基づいて右のクエリから一致するイベントを選択する。 一致しない場合は、左のクエリに含まれるすべてのイベントの行が含まれる。 右のクエリのマッチしない行は、 null に設定される。
join full
どちらのクエリ(左または右)でも一致しない可能性があるものを含め、すべてのイベントの行を返し、欠損値を null で埋める。
join inner
両方のクエリの結果が NULL でない行のみを返します。
join cross
左のクエリの各行と右のクエリの各行を対にし、完全なデカルト積を生成する。 他の join タイプとは異なり、 join crossonusing conditions をサポートしていない。 join inner と同様の機能だが、フィルタリングは行わず、可能な行の組み合わせをすべて返す。

left (デフォルト)、 innerfull の場合、 on キーワードを使用して join 条件を指定するか、 keyword キーワードを使用してキーパスを指定することができます。 デカルト積は、条件が真であるか、キーパスの値が両辺で一致する行のみを保持するようにフィルタリングされる。

修飾子に関係なく、すべての結合はデカルト積に基づいているため、 join 条件が複数回マッチすると、重複した結果が発生する可能性があります。 意図しない重複を防ぐには、distinctを使うなど、サブクエリの前処理を考慮する。

構文:

<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=> という接頭辞を使って、それぞれ左クエリーと右クエリーのイベントを参照することができる。 ただし、キーパスが1つのクエリにしか存在しない場合は必要ない。

    == (等号)演算子を条件で使用する場合、左クエリのキーパスと右クエリのキーパスを比較する必要があります。 しかし、キーパスは一意でなければならないか、 left=> または right=> を先頭に付けなければならないことを考えると、オペランドの順序は重要ではない。

  • <join_keypath_n>- <join_keypath_n> を結合キーとして指定することは、左側のクエリと右側のクエリの両方の結果において、指定されたキーパスが等しい結果を結合することを意味する。

  • <right_side_target>- 結合されたデータが現在のクエリに追加されるキーパス。

join

あなたは、名前に関連するIDの情報を提供する users という カスタム・エンリッチメント・テーブルを持って いる:

{ "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)にはログインがなかったので、 join 条件に一致する結果がないため、loginsフィールドは null であることに注意してください。

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 }

異なる名前の2つのフィールドがあり、 join クエリを簡略化したい場合は、次のようにします。 move を使ってフィールドの1つを移動させ、キーパスが両側で一致するようにします。

join left=> と キーワードを使った例 right=>

left=>right=> という接頭辞を使って、左右のクエリのイベントを参照することができる。 ただし、キーパスが1つのクエリにしか存在しない場合は必要ない。

前の例のデータを使って、次のクエリーを考えてみよう:

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

これは、両方のデータセットに同じ名前のフィールド(id )が含まれているためである。 DataPrime、フィールドを一意に識別するためには、どちらのクエリを参照しているのかを知る必要があります。 このクエリでは、 using キーワードを使用した前回と同じ出力が得られる。

== (等号)演算子を条件で使用する場合、左クエリのキーパスと右クエリのキーパスを比較する必要があります。 しかし、キーパスは一意でなければならないか、 left=> または right=> を先頭に付けなければならないことを考えると、オペランドの順序は重要ではない。

join full

あなたは、名前に関連するIDの情報を提供する users という カスタム・エンリッチメント・テーブルを持って いる:

{ "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" }

2つ目の文書セット(右のクエリー)には、1つ目の文書セット(左のクエリー)には存在しない "id": "001"。 標準的なjoinを使用した場合、右のクエリからのこのエントリは無視され、結果には表示されません。 左右どちらのクエリに表示されていても、 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 、このデータポイントが含まれる。 これは、グラフ上で2つの時系列を比較する場合に特に便利である。

join inner

左または右のクエリーのカラム結果がNULL値を生成した場合、その行を削除したい場合は、 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 が両方のデータセットに存在する行をマッチさせ、データを1つのレコードにマージする。

  • どちらのデータセットでも一致しない行は、最終結果から除外される。

この場合、上記の2つの文書セットについて、結果は次のようになる:

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

join cross

join cross は、左のクエリの各行と右のクエリの各行を結合し、2つのセットのデカルト積を生成する。

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" }

join cross は、左のクエリのすべての行と右のクエリのすべての行を、マッチする条件に関係なくペアにするので、次のクエリは、 userslogs のデータセットのデカルト積を生成する。

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 の使用は、データの全体像を見ることに興味があり、その結果に left または right join を追加する場合に特に便利です。

制限と考慮事項

クエリーに join

  • join の条件は、キーパスの等号(== )にのみ対応している。複数の等号条件が必要な場合は、 && (論理 AND)と組み合わせることができる。

  • 結合の片側(現在のクエリまたは結合クエリ)は小さくなければならない(< 200MB )。 を使用することができます。 filterremove を使ってクエリのサイズを小さくすることができます。

  • 左外部結合では、条件内のすべてのカラムが非NULLである必要があります。 NULLカラムは結合されない。 右クエリのNULLカラムを含めるには、 join full。 左結合と右結合によって生成されるすべてのNULL列を除外するには、 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 を組み込んだ2つ以上のクエリの結果を1つのデータセットに連結する。

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
    }
]

最初の3行は、 appss のユニークな組み合わせごとのカウントである。 例えば、アプリケーション(app)が monitoring24 で、サブシステム(ss)が NO_SUBSYSTEM_NAME であるログが241件ある。 同様に、同じアプリケーションのログが231件あるが、サブシステム logs-opentelemetry-agent、以下同様である。

最後の行は、すべてのサブシステムを集約した、アプリケーション( monitoring24 )のログの総カウント数です。 ここで、 _count0 は、上記のすべての詳細なカウントの合計である487である。 ss フィールドは、 null 、アプリケーション全体の合計であることを示す。

両方のグループ分けに同じエイリアス( app )を使うことで、同じ意味合いが統一されたフィールドとして提示される。 次の例では、異なるエイリアスが使用され、データは結合されるが、マージはされない。

例-異なるエイリアスを持つ Multigroupby

ここで、クエリに2つの異なるエイリアスを導入した場合の効果を考えてみよう。 この場合、最初のグルーピングは、 applicationnamess の組み合わせに対して app1 とラベル付けされ、2番目のグルーピングは applicationname alone に対して app2 とラベル付けされる。

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 )を導入することで、クエリはデータを統合するのではなく、2つのグループ分けの区別を維持する。 app1 が入力され、 app2null である行は、 applicationnamesubsystemname による詳細なグループ分けに対応する。 例えば、241のログが app1 = "monitoring24"ss = "logs-opentelemetry-agent"。 これは最初のグループ分けの論理に従う。

app2 が入力され、 app1null である行は、ログが applicationname によってのみ集計される2番目のグループ化の合計カウントを反映している。 app2 = "monitoring24" では、カウントは487であり、 app1ss の両方は、この上位の集計を示すために null となっている。

別々のエイリアス(app1app2 )を使用することで、クエリーはデータをマージせず、各結果がどのグループに属するかを明確にします。 全体的なロジックは変わらない:特定の組み合わせの詳細なカウントと、合計のカウント。

Multigroupby の制限

multigroupby は、重複したグループ・セットに対して重複した行を返しません。

multigroupby 、appとssを指定して実行すると、(重複が許されるなら)予想される結果は次のようになる:

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

この制限のため、 multigroupby はこれらの重複をマージし、たとえその組み合わせがデータ内で複数回発生したとしても、一意な組み合わせごとに1行のみを返す:

[
  {"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値から正規表現パターンにマッチするすべての部分文字列を置換し、元の内容を効果的に隠す。

マッチング・キーワードはオプションで、可読性を高めるために使用できる。

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

あるキーの値を新しい値に置き換える。

置換値がキーパスのデータ型を変更する場合、以下のオプションが利用できる:

  • 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。 もしinto 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 コマンドは、2つのデータセットを横に並べて結合する。 あるデータセットの行を別のデータセットの行に整列させ、その列を連結することで、単一の統一されたデータセットを作成する。

stitch

  • データセットは順番に並べなければならない。行は順番に組み合わされるからである(つまり、データセットAの1行目はデータセットBの1行目と縫い合わされる)。

  • 一方のデータセットの行数が他方のデータセットの行数より多い場合,マッチしていない行は,つなぎ合わせた列にNULL値が入る.

  • できあがったデータセットには、両方のデータセットのすべてのカラムが含まれる。

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 sales sales データセットからすべての行を取得する。このデータセットには商品とそれに対応する販売数が含まれている。

  • orderby product sales データセットを フィールドでソートし、行の整列順序に一貫性を持たせる。 product

  • 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 コマンドは、2つ以上のデータセットの結果を1つのデータセットに連結する。 これにより、ユーザーは複数のクエリの結果を1つのシームレスなデータセットにまとめることができる。 あるデータセットは、 union コマンドにパイプされた結果セットで、別のデータセットと連結することができる。

unionは、あるデータセットから別のデータセットに行を追加する必要があるときに使う。

大規模なデータセットを処理する場合、パフォーマンスを最適化するために、 union を使用する前に、 filter を使用して各データセットから行を制限することを検討してください。

優先順位の洞察、1つのクエリにつき最大10個の union。 その他のデータに制限はない。

union との違い join

  • union あるデータセットから別のデータセットに行を追加することで、結果セットを結合する。 複数の文書の列をマージしたり、比較したりはしない。

  • join は、条件に基づいて2つのテーブルのカラムをマッチさせて結合し、両方のテーブルのデータを含む行を作成します。

<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" }

そして、それらを1つのデータセットにまとめたい。 これは union を使って行うことができる。

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

クエリーは2つのデータセットを処理する:

  • 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" }