Splunk: ワイルドカード・正規表現での検索におけるヒット条件毎の統計


必要な機会があったのでメモ。

実施環境: Splunk Free 8.2.2
前置き

文字列の検索において、条件毎のヒット数を算出することを考えます。
文字列が固定であれば、以下のように stats コマンドを使用することで容易に実現できます。

Splunk
| makeresults count=10
| streamstats count AS CNT
| eval NUM = CNT % 3
| eval STR = "A" + NUM
| where STR = "A1" OR STR = "A2"
| stats count BY STR

では、この条件がワイルドカードや正規表現を含むものであればどうでしょうか。

やりたいこと

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

STR
one
two
three
four
five
Splunk
| inputlookup "test_data.csv" 

検索条件は「 t で始まる文字列」「 e で終わる文字列」の2つを指定します。

STR
t*
*e
Splunk
| inputlookup "test_search.csv" 

上記のデータにおいて「 t で始まる文字列」は2つ、「 e で終わる文字列」は3つあります。
この数字を導出することを目指します。

単純に検索すると

まずは単純に format コマンドで検索条件を組み立てて search コマンドで検索してみます。
where コマンドを使用しないのは where コマンドだとワイルドカードをそのまま利用できないためです。

Splunk
| inputlookup "test_data.csv"
| search
    [
      | inputlookup "test_search.csv"
      | format
    ]

STR
one
two
three
five

上記の結果をいろいろこねくり回してみましたが、この方針で目的を達成するのは難しそうです。
何が悪いのかを考えると、「どの条件でヒットしたのかが結果から判断できない」ということに気づきます。

以下のように条件毎にサーチ文を作って合成するという方法も思いつきますが、汎用性が無さすぎます。

Splunk
| inputlookup "test_data.csv"
| search
    [
      | inputlookup "test_search.csv"
      | head 1
      | format
    ]
| eval STR_SEARCH = "t*"
| stats count BY STR_SEARCH
| append
    [
      | inputlookup "test_data.csv"
      | search
          [
            | inputlookup "test_search.csv"
            | tail 1
            | format
          ]
      | eval STR_SEARCH = "*e"
      | stats count BY STR_SEARCH
    ]
STR_SEARCH count
t* 2
*e 3

解決方法

いろいろ考えた結果、以下の方法に行き着きました。

Splunk
| inputlookup "test_data.csv"
| join max=0
    [
      | inputlookup "test_search.csv"
      | eval STR_SEARCH = STR
      | eval STR_SEARCH_R = replace(STR,"\*","%")
      | fields STR_SEARCH, STR_SEARCH_R
    ]
| where like(STR, STR_SEARCH_R)
| stats count BY STR_SEARCH
STR_SEARCH count
*e 3
t* 2

ポイントは以下の2点です。

  • join コマンドの max オプションを使用して検索対象と検索条件の組を全て書き出す

  • where コマンドの like 関数を使用して、組毎に検索を実施する

ポイントの1点目ですが、 join コマンドの max オプションに 0 を指定すると全ての組み合わせを網羅する形での結合(交差結合)が実現できます。
これを利用して、検索対象と検索条件の組み合わせを、1組1行で全て書き出します。

Splunk
| inputlookup "test_data.csv"
| join max=0
    [
      | inputlookup "test_search.csv"
      | eval STR_SEARCH = STR
      | fields STR_SEARCH
    ]
STR STR_SEARCH
one t*
one *e
two t*
two *e
three t*
three *e
four t*
four *e
five t*
five *e

書き出した組み合わせについて、ポイントの2点目で行毎に検索を実施し、ヒットした行のみを抽出します。
2つのフィールドを比較するので、先ほどは逆に where コマンドである必要があります。
注意点として、 like 関数のワイルドカードは「任意の文字列」を表す文字が「*」でなく「%」になるので、そのように条件の文字列を変換しないとうまく動きません。

Splunk
| inputlookup "test_data.csv"
| join max=0
    [
      | inputlookup "test_search.csv"
      | eval STR_SEARCH = STR
      | eval STR_SEARCH_R = replace(STR,"\*","%")
      | fields STR_SEARCH, STR_SEARCH_R
    ]
| where like(STR, STR_SEARCH_R)
STR STR_SEARCH STR_SEARCH_R
one *e %e
two t* t%
three t* t%
three *e %e
five *e %e

このようにすれば、「ヒットした値」と「ヒットした条件」の組が残るので、 stats コマンドで集計することができます。

正規表現

さらにこの方法だと、 like 関数を match 関数に変えるだけで正規表現にも対応することができます。
search コマンドで正規表現は使えないので、この方法は統計処理をしない検索だけでも有用かと思います。

Splunk
| makeresults count=200
| streamstats count AS STR
| join max=0
    [
      | makeresults count=2
      | streamstats count AS STR
      | eval STR_SEARCH = "^" + STR + "*5{1,2}$"
      | fields STR_SEARCH
    ]
| where match(STR, STR_SEARCH)
| stats count BY STR_SEARCH