読者です 読者をやめる 読者になる 読者になる

ログのURLをパースして指定した要素を抜き出すNorikraUDFを作った

プログラミング Ruby Norikra

f:id:mia_0032:20151112084622p:plain

URLをパースして指定した要素を抜き出してくれるUDF(splituri)と、GETパラメータを同じようにパースして指定したキーの値を抜き出してくれるUDF(splitquery)を作りました。

norikra-udf-uri_parser | RubyGems.org | your community gem host

github.com

なぜ作ったか?

流れてくるログに含まれるURLの中から特定のパスや、特定のGETパラメーターを取得したい要件があって、それを楽にするために作りました。

使い方

splituri(expression, string)

このUDFは基本的にはRubyURI.parseをラップしたようなUDFになっています。

第1引数にはURLまたはpathの文字列をとります。

第2引数には以下の文字列を指定できます。 scheme,userinfo,host,port,path,opaque,query,fragment

返り値は第1引数で指定したURI文字列の第2引数で指定した要素の部分の文字列になります。

クエリ例

pathフィールドには/hoge?foo=bar#topといった文字列が入っているとします。 以下にクエリその結果を返します。

SELECT
  splituri(path, 'scheme')   AS scheme,
  splituri(path, 'userinfo') AS userinfo,
  splituri(path, 'host')     AS host,
  splituri(path, 'port')     AS port,
  splituri(path, 'path')     AS path,
  splituri(path, 'opaque')   AS opaque,
  splituri(path, 'query')    AS query,
  splituri(path, 'fragment') AS fragment
FROM access_log
{
  "port":"",
  "host":"",
  "scheme":"",
  "query":"foo=bar",
  "opaque":"",
  "path":"/hoge",
  "userinfo":"",
  "fragment":"top"
}

URL形式の文字列を指定することもできます。 例えばrefererフィールドにhttp://example.com/hoge?foo=bar#topというURLが入っているとします。

SELECT
  splituri(referer, 'scheme')   AS scheme,
  splituri(referer, 'userinfo') AS userinfo,
  splituri(referer, 'host')     AS host,
  splituri(referer, 'port')     AS port,
  splituri(referer, 'path')     AS path,
  splituri(referer, 'opaque')   AS opaque,
  splituri(referer, 'query')    AS query,
  splituri(referer, 'fragment') AS fragment
FROM access_log

上記のクエリは以下の結果を返します。

{
  "port":"",
  "host":"example.com",
  "scheme":"http",
  "query":"foo=bar",
  "opaque":"",
  "path":"/hoge",
  "userinfo":"",
  "fragment":"top"
}

splitquery(expression, string)

GETパラメータなどのクエリ文字列(ex.key1=value1&key2=value2)の中から指定したキーの値を取得するUDFです。

確認したところURLエンコードされた文字列もデコードしてくれるようです。

第1引数には上記のクエリ文字列をとり、第2引数に値を取得したいキーを指定します。

クエリ例:

queryフィールドにfoo1=bar1&foo2=bar2&foo3=bar3という文字列が指定されているとします。

SELECT
  splitquery(query, 'foo1') AS foo1,
  splitquery(query, 'foo2') AS foo2,
  splitquery(query, 'foo3') AS foo3
FROM access_log

上記のクエリは以下の結果を返します。

{
  "foo3":"bar3",
  "foo2":"bar2",
  "foo1":"bar1"
}

配列でパラメータを渡すような場合(ex. foo[]=bar1&foo[]=bar2&foo[]=bar3)にも対応しています。

SELECT
  splitquery(query, 'foo[]') AS foo
FROM access_log

この場合は返り値が配列になる点に注意してください。

{
  "foo":[
    "bar1",
    "bar2",
    "bar3"
  ]
}

キーのみがついていて、値がない場合(ex. test&foo1=bar1&foo2=bar2test)には空文字を返すようになっています。

SELECT
  splitquery(query, 'test') AS test,
  splitquery(query, 'other') AS other
FROM access_log

存在しないキーについてはnullを返すようになっているため、存在するかを判定したいときはnullチェックをすればできると思います。

{
  "other":null,
  "test":""
}

splituriとsplitqueryの組み合わせ

もちろん入れ子にして使うこともでき、例えばpathフィールドに/hoge?foo=barという文字列が入っているとすると、

SELECT
  splitquery(splituri(path, 'query'), 'foo') AS val
FROM access_log

上記のクエリは以下の結果を返します。

{
  "val":"bar"
}

まとめ

  • Norikraでアクセスログの集計などを行う場合に便利かと思うので、よければ使ってください。

参考にしたもの

  • https://github.com/norikra/norikra-udf-mock
    • 初めてNorikraのUDFを書きましたが、これを見るだけで書けるくらいに手順が書いてあるので、非常に助かりました。ありがとうございます。

備考

  • splituriはログの中身によって文字列か配列かを返すようになっているため、逆に使いずらいかもしれないです。
    • 配列パラメータについては文字列か配列のどちらで返すか選べるようにしたほうがいいかもしれないと思っています。
  • 第2引数を指定せず、すべてハッシュで取得できるUDFもあると便利かもしれないです。