Splunk: ワイルドカードで指定した複数フィールドを処理する foreach コマンド


###### 実施環境： Splunk Free 8.2.2

### 0. 概要

 Splunk で、複数のフィールドについて処理を行いたい場合があります。

例えば、以下のようなデータを考えます。

```Splunk:Splunk
| makeresults count=3
| streamstats count AS TEST
| eval TEST_1 = 5, TEST_2 = 7, NO_TEST = 10, NO_TEST_2 = 50
```

![WS000260.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/09a9133d-eb8c-10a3-486b-c2a3337ccd03.jpeg "元データ")

このデータで、「 `TEST` 」「 `TEST_1` 」「 `TEST_2` 」の3つのフィールドを足し算したいとします。
この場合、単に以下のようにすれば対応できます。

```Splunk:Splunk
| 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 フィールド名 [ サブサーチ ]

```Splunk:Splunk
| 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>> ]
```

![WS000261.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/2b7b0053-33b5-7668-964f-719c106ff7a1.jpeg "基本")

フィールド名にはワイルドカードの「 `*` 」が使用できます。
「 `*` 」は任意の文字列が当てはまります。

サブサーチでフィールド名を埋め込みたい箇所には「 `<<FIELD>>` 」を指定します。
サブサーチの先頭に「 `|` 」は不要ですが、入れても動きます。

```Splunk:Splunk
| 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>> ]
```

![WS000263.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/5dd1c6f6-7f06-0f69-dddd-78be15824e61.jpeg "サブサーチ")

### 2. 複数コマンド

サブサーチには複数のコマンドを入れることができます。

```Splunk:Splunk
| 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 ]
```

![WS000264.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/338da743-ae88-924c-4486-925626812899.jpeg "複数コマンド")

### 3. 指定できるコマンド

上記では eval コマンドを使用していますが、 eval コマンド以外のコマンドも使用できます。

```Splunk:Splunk
| 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 ]
```

![WS000265.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/f24842ad-33d3-da20-bf05-bd7a69ec3aa6.jpeg "rename")

### 4. 複数のフィールド名

フィールド名の指定を複数つなげることも可能です。

```Splunk:Splunk
| 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>> ]
```

![WS000266.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/1d7f0b04-f69b-cb62-d0e2-646fdbfded3d.jpeg "フィールド名")

### 5. NULL 処理についての注意点

注意するべき点として、ワイルドカードで指定したフィールド中に NULL 値が含まれる場合は想定外の挙動をもたらす可能性があります。

```Splunk:Splunk
| 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>> ]
```

![WS000274.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/ee9fa2fb-322c-77ed-7728-9b1143acd5ef.jpeg "NULL")

そのような場合は、 fillnull で NULL 値を埋めたり if 文で分岐させるなどして、うまく NULL 処理をコントロールする必要があります。

```Splunk:Splunk
| 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>>) ]
```

![WS000275.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/d762f716-38c6-fab8-7f75-b0445a736d8b.jpeg "NULL処理")