実施環境: Splunk Free 8.2.2
0. 概要
Splunk で、複数のフィールドについて処理を行いたい場合があります。
例えば、以下のようなデータを考えます。
| makeresults count=3
| streamstats count AS TEST
| eval TEST_1 = 5, TEST_2 = 7, NO_TEST = 10, NO_TEST_2 = 50
このデータで、「 TEST
」「 TEST_1
」「 TEST_2
」の3つのフィールドを足し算したいとします。
この場合、単に以下のようにすれば対応できます。
| makeresults count=3
| streamstats count AS TEST
| eval TEST_1 = 5, TEST_2 = 7, NO_TEST = 10, NO_TEST_2 = 50
| eval TOTAL = TEST + TEST_1 + TEST_2
では、例えば「 TEST_3
」が増えた場合はどうでしょうか。
この場合、 SPL を書き換えて TEST + TEST_1 + TEST_2 + TEST_3
にすれば対応できます。
では、「 TEST_4
」「 TEST_5
」と増えていく場合は?
そもそも「 TEST
」の後ろに何がくるかわからない場合は?
そのような場合に役立つのが、 foreach コマンドです。
1. 基本的な使い方
foreach コマンドの基本的な文法は以下の通りです。
foreach フィールド名 [ サブサーチ ]
| makeresults count=3
| streamstats count AS TEST
| eval TEST_1 = 5, TEST_2 = 7, NO_TEST = 10, NO_TEST_2 = 50
| eval TOTAL = 0
| foreach TEST*
[ eval TOTAL = TOTAL + <<FIELD>> ]
フィールド名にはワイルドカードの「 *
」が使用できます。
「 *
」は任意の文字列が当てはまります。
サブサーチでフィールド名を埋め込みたい箇所には「 <<FIELD>>
」を指定します。
サブサーチの先頭に「 |
」は不要ですが、入れても動きます。
| makeresults count=3
| streamstats count AS TEST
| eval TEST_1 = 5, TEST_2 = 7, NO_TEST = 10, NO_TEST_2 = 50
| eval TOTAL = 0
| foreach TEST*
[ | eval TOTAL = TOTAL + <<FIELD>> ]
2. 複数コマンド
サブサーチには複数のコマンドを入れることができます。
| makeresults count=3
| streamstats count AS TEST
| eval TEST_1 = 5, TEST_2 = 7, NO_TEST = 10, NO_TEST_2 = 50
| eval TOTAL = 0, COUNT = 0
| foreach TEST*
[ | eval TOTAL = TOTAL + <<FIELD>>
| eval COUNT = COUNT + 1 ]
3. 指定できるコマンド
上記では eval コマンドを使用していますが、 eval コマンド以外のコマンドも使用できます。
| makeresults count=3
| streamstats count AS TEST
| eval TEST_1 = 5, TEST_2 = 7, NO_TEST = 10, NO_TEST_2 = 50
| foreach TEST*
[ | rename <<FIELD>> AS <<FIELD>>_OK ]
4. 複数のフィールド名
フィールド名の指定を複数つなげることも可能です。
| makeresults count=3
| streamstats count AS TEST
| eval TEST_1 = 5, TEST_2 = 7, NO_TEST = 10, NO_TEST_2 = 50
| eval TOTAL = 0
| foreach TEST* NO_TEST*
[ | eval TOTAL = TOTAL + <<FIELD>> ]
5. NULL 処理についての注意点
注意するべき点として、ワイルドカードで指定したフィールド中に NULL 値が含まれる場合は想定外の挙動をもたらす可能性があります。
| makeresults count=3
| streamstats count AS TEST
| eval TEST_1 = 5
| eval TEST_2 = if(TEST==1, null(), 7)
| eval TOTAL = 0
| foreach TEST*
[ eval TOTAL = TOTAL + <<FIELD>> ]
そのような場合は、 fillnull で NULL 値を埋めたり if 文で分岐させるなどして、うまく NULL 処理をコントロールする必要があります。
| makeresults count=3
| streamstats count AS TEST
| eval TEST_1 = 5
| eval TEST_2 = if(TEST==1, null(), 7)
| eval TOTAL = 0
| foreach TEST*
[ eval TOTAL = TOTAL + if(isnull(<<FIELD>>), 0, <<FIELD>>) ]