時々使うのでメモ。
実施環境: Splunk Free 8.2.2
目的
Splunk の stats コマンドでは、 count 関数を使用することでデータの個数を集計することができます。
また、 BY 句を指定することによって指定のフィールドの値ごとに分けた個数を取得することもできます。
| makeresults count=10000
| eval NUM = random() % 10
| stats count BY NUM
では、「あるフィールドが特定の値であるデータの個数」が欲しい場合はどうすればよいでしょうか。
「特定の値」が単一の値である場合は、以下のように stats コマンドの前か後で where コマンドを使用して対象データを抜き出せば取得できます。
| makeresults count=10000
| eval NUM = random() % 10
| where NUM = 0
| stats count BY NUM
| makeresults count=10000
| eval NUM = random() % 10
| stats count BY NUM
| where NUM = 0
ただ、少々冗長な気がしますし、何よりこれだと複雑な条件には対応できません。
基本
では、どうすればよいでしょうか。
実は、 stats コマンドの count 関数では、「eval(フィールド名=値)」という表現を用いることで、フィールドが特定の値であるデータのカウントを行うことが可能です。
| makeresults count=10000
| eval NUM = random() % 10
| stats count(eval(NUM = 0)) AS NUM0
なお、この条件付きカウントで得られる集計値は、必ず AS 句を用いてリネームする必要があります。
| makeresults count=10000
| eval NUM = random() % 10
| stats count(eval(NUM = 0))
応用
この条件付きカウントの条件には、 AND や OR も使用できます。
| makeresults count=10000
| eval NUM = random() % 10
| stats count(eval(NUM = 1)) AS NUM1,
count(eval(NUM = 2)) AS NUM2,
count(eval(NUM = 1 OR NUM = 2)) AS NUM12
また、 eval コマンドで使用できる様々な関数も使用可能です。
| makeresults count=10000
| eval NUM = if(random() % 2 = 0, null(), 3)
| stats count(eval(isnull(NUM))) AS NULL,
count(eval(NUM = round(pi()))) AS NUM3
複数のフィールドを使用した条件も作れます。
| makeresults count=10000
| eval NUM1 = random() % 10,
NUM2 = random() % 10
| stats count(eval(NUM1 = NUM2)) AS NUM12
なお、あまり複雑な条件を入れてしまうと、非常に読みにくい SPL 文となる可能性があります。
そのような際は以下のように、 stats コマンドの前で条件が成立するなら 1 、それ以外は 0 を示すフラグフィールドを作り、その合計をとるようにすると整理しやすいです。
| makeresults count=10000
| eval NUM = random() % 10
| eval FLG = if(NUM = 0, 1, 0)
| stats count(eval(NUM = 0)) AS NUM0,
sum(FLG) AS FLG0
補足
この条件付きカウントの方法は、 stats コマンド以外でも使用できます。
| makeresults count=10000
| eval NUM = random() % 10
| timechart span=1h count(eval(NUM = 0)) AS NUM0
また、 count 以外の関数でも使用できます。
ただし、 count 以外の関数では eval 単体だとうまく動作しません。
eval は「新しいフィールドを作成するコマンド」のため、 if 等を使用して「新しいフィールドに格納する値」をしっかり定義する必要があります。
以下の例では、「3で割り切れる値=0,3,6,9」の時は元の値、それ以外では NULL を格納したフィールドの平均を取得しています。
0ではなく NULL なのは、平均計算時の総データ数を「3で割り切れる値=0,3,6,9」のデータのみに限定するためです。
| makeresults count=10000
| eval NUM = random() % 10
| stats avg(eval( NUM % 3 = 0 )) AS AVG,
avg(eval(if(NUM % 3 = 0, NUM, 0 ))) AS AVG0,
avg(eval(if(NUM % 3 = 0, NUM, null()))) AS AVGnull
無論、先に記載したフラグフィールドを作成する方法を応用して使うことも可能です。
何なら、こちらのほうがわかりやすいかもしれません。
| makeresults count=10000
| eval NUM = random() % 10
| eval FLG = if(NUM % 3 = 0, NUM, null())
| stats avg(FLG) AS AVG