概要
LTSVの簡易パーサーを作成してみた(高速化版)
詳細
下記の記事で作成したパーサーは低速だったため、高速化しました。
ログ管理 | LTSV | LTSVの簡易パーサーを作成してみた(高速化版)
http://d.hatena.ne.jp/tbpg/20130714/1373819084
根本的な作りを変更し、パース処理の実態はシェルのegrepコマンドになっています。
検索条件に合わせてegrepコマンドを生成してRubyからシェルを実行しています。
サンプルで作成した10MBのファイルに対して検索を行ったところ、
元処理では9秒かかっていたところが、改善後は1.1秒になりました。
仕様
・シェルから引数を指定しての呼び出しを想定
・第一引数は対象ログファイル
・第二引数以降をオプションとして扱い、key:value形式で絞込み要素を指定
※ログファイル内のltsvのvalue部に角括弧([])があってもなくても動作します
オプションの指定時は角括弧不要です。
・valueは大文字小文字無視で絞り込まれる
・複数の絞り込み内容を指定した場合はAND条件で絞る
・絞り込みは部分一致検索とする
Gemfile
source "https://rubygems.org" gem "active_support", "~> 3.0.0"
実装コード
# encoding: utf-8 require "shell" require 'active_support' module StandardIo extend ActiveSupport::Concern module ClassMethods def validate_args_counts(count) define_method "validate_args_counts" do $*.size == count end end def validate_file(index) define_method "validate_file_#{index}" do return false unless args_has_index?(index) FileTest.exist?($*[index]) end end end def validate self.methods.grep(/^validate_.*/).each do |m| return false unless method(m).call end true end def args_has_index?(index) $*.size > index end end module LtsvParser class Parser include StandardIo validate_file 0 attr_accessor :ltsv_file, :filter_words def initialize @ltsv_file = $*[0] @filter_words = get_filter_words end def output commands = "" if @filter_words.size == 0 puts `cat #{ltsv_file}` return end commands << "egrep -i \"#{@filter_words.first[0]}:\\\[{0,1}[^\t]*#{@filter_words.first[1]}[^\t]*\\\]{0,1}\" #{ltsv_file} | " @filter_words.delete @filter_words.first[0] @filter_words.each do |k, v| commands << "egrep -i \"#{k}:\\\[*?[^\t]*#{v}[^\t]*\\\]{0,1}\" | " end puts `#{commands.chop.chop}` end private def get_filter_words filter_words = {} filters.each do |fil| kv = fil.split(":") filter_words[kv[0].to_sym] = kv[1] if (fil.count(":")) == 1 end filter_words end def filters $*[1..-1] end end end ps = LtsvParser::Parser.new exit unless ps.validate ps.output
サンプル実行
対象ログLTSV:hoge.log
key1:value1_1 key2:value2_1 key1:value1_2_1 key2:value2_2_1 key1:value1_2_2 key2:value2_2_2 key1:value1_3 key2:value2_3
実行結果
$ruby ltsv_parser.rb hoge.log key1:value1_1 key2:value2_1 key1:value1_2_1 key2:value2_2_1 key1:value1_2_2 key2:value2_2_2 key1:value1_3 key2:value2_3 $ruby ltsv_parser.rb hoge.log key1:value1_2 key1:value1_2_1 key2:value2_2_1 key1:value1_2_2 key2:value2_2_2 $ruby ltsv_parser.rb hoge.log key1:value1_2 key2:value2_2_2 key1:value1_2_2 key2:value2_2_2