正規表現検索の効率化

GMO NIKKOのT.Iです。
今回は当社のTRUE データフィードで使用している正規表現検索の効率化についての記事となります。

前提(背景と目的)

まずは宣伝(笑)


当社公式サイトでは上記となっていますが、簡単にいうと
・クライアントからデータを預かる
・預かったデータを広告媒体毎のフォーマットの変換する
・変換したデータを指定された場所に送信する
ということをやっています。

その中のデータの変換時に禁止文言が入ったデータを行ごと除外するということをやっています。
大量のデータに禁止文言が入っているかをチェックする必要があるのですが、
初期想定では精々10万件に対して100~1000個の禁止文言をチェックする程度(1億回程度)で十分と判断していました。
ですが運用後に禁止文言が3万を超えてしまい、チェック処理が10万件×3万=30億回のチェックを行う場合があり、処理時間がかなり長くなってしまいました。
これが問題となり、上長とも相談してチェック処理の効率化を図ることになりました。

対処内容

対処方法はシンプルです。
1件のチェック時に1個ずつ文言が含まれているかチェックしていたので、
1件のチェックで100個の文言を同時にチェックするようにしました。

具体的にはPHPのpreg_match、joinを使用します。 このように配列$stocksに禁止文言を格納し、joinで禁止文言を1行に纏めた後にpreg_matchで$check_textに正規表現検索をかけるようにした。
これにより従来の処理の100分の1の処理時間で済むようになりました。
やろうと思えば1000分の1なども出来ると思うが禁止文言の長さによってはPHPの制約に引っかかる可能性があるので100分の1までにしています。

おまけ(preg_matchの最大値)

pcre.backtrack_limit(PCRE のバックトラック処理の制限値)
1000000バイト(PHP5.3.7以降)
100000バイト(PHP5.3.7以前)
pcre.recursion_limit(PCRE の再帰処理の制限値)
100000回

10万件以上のNGワードを登録されていたらエラーになっていましたね・・
現在は100倍まで問題ないので良かった。
まあPHPのメモリ使いすぎで落ちていたかもしれない。

まとめ

正規表現をまだまだ使いこなせていないな、と思いました。
上長にこのやり方を教わって目から鱗が落ちる思いでした。
まだまだ改善や効率化できることがあると思うので尽力したいと思います。