2015927

squidログから検索クエリーのテキスト解析

 

1.squidログのログ・クレンジング

 ログのクレンジングにはいろいろな方法がある。試行錯誤で次のようなログのクレンジングを行った。

 

1.1 squidログの読み込み

 ログの項目数が正しいこと、転送バイト数がゼロでないこと、リクエストメソッドが所定のものに合致していること(基本はGETPOST)、ポート443の通信でないこと、ステータスコードが200であること、コンテンツタイプが”text/xxxx”または”-”であることを条件に読み込みを行った。

 

1.2 QueryStringのデコード

 GET文字列の中で、エンコードタイプが明示されているものもあれば、エンコードタイプがないものもある。検索クエリーでエンコードがきっちりできなければ、何を検索しようしているか、全く分からなくなる。いろいろ挑戦するが中々うまくエンコードできない中、”エンコード時の文字コードが不明なURLJavaでデコード”(http://blog.grush.jp/?p=20)のサイトに従い、QueryStringのエンコード問題を解決した。

 

1.3 どこを対象とするか

 今回はクエリーの収集・解析であるが、対象とするサイトやそのサイトの検索パラメータが分からない。少し古いが、“検索エンジンのURL“(http://www.geocities.jp/hima_hibi/surl.html)のサイトでは、いろいろな検索サイトが紹介されていて、これをベースに、更に収集ログの目視により調査を行った。これらの調査を元に、”http://・・・/search?・・・”、”http://・・・/Suggestions?・・・”などの持つURL検索サイトをクエリー解析の対象とした。これらのurlの中で、”q=”、”p=”、”qu=”、”qry=”、”query=”、”keyword=”などに続く文字列がQueryStringである。尚、”/search?”で始まる次のようなサイトは対象外とした。

http://www.navitime.co.jp/transfer/search?orvStationName=東京&dnvStationName=名古屋・・・

 

1.4 やっかいな話

 日本語変換中のインクリメンタルサーチの検索では次のようなクエリーが流れる。これらは日本語変換中のもので、時系列的には同一のものである。変換中のそれぞれを検索ワードとするのはおかしく、検索クエリーとしては、最後のもの以外は検索クエリーとすることはできない。

 インクリメンタルサーチ型検索の例

              http://suggestqueries.google.com/complete/search?hl=ja&qu=wifi

              http://suggestqueries.google.com/complete/search?hl=ja&qu=wifi

              http://suggestqueries.google.com/complete/search?hl=ja&qu=wifi

              http://suggestqueries.google.com/complete/search?hl=ja&qu=wifiせt

              http://suggestqueries.google.com/complete/search?hl=ja&qu=wifiせつ

              http://suggestqueries.google.com/complete/search?hl=ja&qu=wifiせつz

              http://suggestqueries.google.com/complete/search?hl=ja&qu=wifiせつぞ

              http://suggestqueries.google.com/complete/search?hl=ja&qu=wifiせつぞk

              http://suggestqueries.google.com/complete/search?hl=ja&qu=wifiせつぞく

              http://suggestqueries.google.com/complete/search?hl=ja&qu=wifi接続

 

1.5 QueryStringに対する前処理

 日本語にはいろいろな”揺らぎ”があるため、多くの日本語解析ではテキストの前処理が成されている。今回QueryStringの解析に当たり、次のような前処理を施した。

(1) 日本語のノーマライズ

              日本語解析の最初の前処理として、次のような日本語のノーマライズを行う。

              ・スペースの半角化、連続スペースを1つにする。

              ・複数ある長音記号を”ー”に統一、並びに連続長音を1つにする。

              ・同様にダブルクォート、カンマも同様に対応する。

              ・英数字に挟まれた長音はハイフンに変換する。

              ・全角英数字、記号の半角変換及び英文字の小文字化をする。

              ・半角カタカナを全角カタカナに変換する。

 

(2) 漢字、カタカナのひらがな変換

日本語を、”Kakasi”(http://kakasi.namazu.org/index.html.ja)を用い、ひらがなに変換する。

 

(3) Hebon変換

ひらがな文字列をヘボン式英字列に変換する。

上記のインクリメンタルサーチ型クエリーは次のような入力ストリームとなる。

              wifi

              wifi s

              wifi se

              wifi set

              wifi setsu

              wifi setsuz

              wifi setsuzo

              wifi setsuzok

              wifi setsuzoku

              wifi setsuzoku

 

(4) 文字列比較

同一IPで、事前のクエリーq0と、次に来たクエリーq1を比較し、次の判定式に従い、包含関係から”大”なものを最終的なクエリーとして採用する。比較関数は、String.startsWithString.endsWithを用いた。

                            q0 q1  →  q0 nullq0 q1

                            q0 q1  →  q1 null

 

この処理を順次繰り返すと、変換過程の文字列はなくなり、最終的に“wifi 接続”がインクリメンタルサーチ型クエリーとして残る。

但し、Hebon変換では、じしん(jishin)、自信(jishin)、自身(jishin)、地震(jishin)など同じ読み文字列は、同じアルファベット列となる。

 

(5) 比較関数の改良

 ログを調べる中から、次のようなログを発見した。”ハンディクリーナー おすすめ”で検索した後、”おすすめ”の前から新しいインクリメンタルサーチを始めている例である。前述の比較関数では、包含関係はなく、異なる文字列となる。

 インクリメンタルサーチを行っている文字列では、1文字しか追加されないため、Levenshtein距離(編集距離)による判定を検討した。しかし汎用的に考えると、異なるところが1文字のみならず、複数個ある場合も考慮しなければならない。そこでunix流のdiff流れを汲んでいるdiff.jarhttp://aarkiton.blogspot.jp/2009/05/diff.html)を利用した。

 diff.jarを利用すると、文字列a、文字列bから成る文字列Aと、文字列a、文字列c、文字列bから成る文字列Bとの間で、文字列A 文字列Bの関係を見出すことができる。

                            文字列A              文字列a 文字列b

                            文字列B              文字列a 文字列c 文字列b

 次の例では、Hebon式変換を経て、最終的クエリーとして”ハンディクリーナー コードレス おすすめ”を得ることができた。

              1401409079706 192.168.161.87 bing.com ハンディクリーナー おすすめ

              1401409080824 192.168.161.87 bing.com ハンディクリーナー kおすすめ

              1401409080824 192.168.161.87 bing.com ハンディクリーナー koおすすめ

              1401409081217 192.168.161.87 bing.com ハンディクリーナー ko-おすすめ

              1401409081217 192.168.161.87 bing.com ハンディクリーナー ko-dおすすめ

              1401409081334 192.168.161.87 bing.com ハンディクリーナー ko-doおすすめ

              1401409081524 192.168.161.87 bing.com ハンディクリーナー ko-dorおすすめ

              1401409081613 192.168.161.87 bing.com ハンディクリーナー ko-doreおすすめ

              1401409081817 192.168.161.87 bing.com ハンディクリーナー ko-doresおすすめ

              1401409082072 192.168.161.87 bing.com ハンディクリーナー ko-doresuおすすめ

              1401409103219 192.168.161.87 bing.com ハンディクリーナー コードレスおすすめ

              1401409103219 192.168.161.87 bing.com ハンディクリーナー コードレス おすすめ

 

(6) 形態素解析

              ・形態素解析はJava環境で動作する”Igo”(http://igo.sourceforge.jp/)を利用。

            1.5(1)のノーマライズ処理及び英字の小文字化の後、String.split(' ')により得られた文字列配列に対して、検索対象となり難い文字列の除外を行う。

                            数字列及び記号列の除外

                                          数字のみ、記号のみ、郵便番号、電話番号、IPアドレスなどの文字列を除外

                            1文字の英字、ひらがな、カタカナの除外

                            数詞+助数詞で表される数値の除外

                                          500円、千五百円、10代、40台、37度などの数値を除外

              ・英数記号列はキーワードとして採用する。

              ・日本語混じりのテキストは形態素解析し、名詞を中心にそれぞれをキーワードとして採用する。この処理で、助詞などのストップワードが除外できる。尚、ストップワード除外辞書を利用してないため、”これ”、”それ”などのキーワードとして採用される。

              ・キーワードの連結

                            ”接続エラー”、”データ削除”などは分離せず、連結操作を行った。

                            ”子供の病気”などで、連体化助詞”の”を挟む名詞も連結操作を行った。

              ・ダブルクォートや括弧で囲まれている場合、これらの削除を行った。

 

   形態素解析の例

1401423101943 192.168.161.71 yahoo.co.jp 【本日の一枚】この写真を出すか迷ったのですが、あまりに衝撃写真だったので(*´ω`*)ねこじゃらしをキャッチできなかった表情と姿がポイントです(笑)

                                          ↓  形態素解析を行うと。

                            本日

                            写真

                            衝撃写真

                            ねこ

                            キャッチ

                            表情

                            姿

                            ポイント

                           

 

2.ログの保存と集計

 ログの保存にはMongoDBを採用した。MongoDBはドキュメント指向のデータベースで、JSON形式のドキュメントが簡単に保存でき、JSONオブジェクトとして参照や変更も簡単にできる。JSONが分かるプログラマーにとって大変扱い易いDBである。

 今回。MongoDBの扱いに慣れていないため、単純なシングルノード構成とした。

 

2.1 squidのログ保存

 squidのログデータから、"time", "year", "month", "day", "hour", "duration", "clientAddress", "resultCode", "statusCode", "byte", "requestMethod", "url", "domain", "type"を読み込み、これらをJSONデータとしてMongoDBに登録した。squidログに加え、"year", "month", "day", "hour""time"から、"domain""url"から求めたもので、以後の検索・集計を簡便に行うためのデータである。

 

2.2 登録・集計スピード

squidログ(2014/4/10から5/91,700万件のMongoDB登録時間は、70分強(ノートPC)であった。

また、1,700万件の収集ログに対してMapReduce(本来aggregateを使うべきであろう)による12時台で、各ドメインへのアクセス数集計は、i5-3337U CPU, 1.8GHzPC環境で、14分強の時間で終わった(総なめでこの速さ)。

 

3.結果

 多くの検索サイトが採用しているインクリメンタルサーチではタイピングの都度、クエリーが流されていて、クレンジングしなければ正しいログ収集ができない。今回、テキスト解析を行い、有効なクレンジングができた。

 

4.リソース

 利用ライブラリー

  mongo-2.10.1.jar

  commons-lang.jar

  kakasi.jar

  igo-0.4.5.jar

  kuromoji-0.7.7.jar

  diff.jar

 

 プログラム(querystring.zip

  FileReadSquidQuery.java

  FileSearch.java

  HebonConvert.java

  LogString.java

  QueryString.java

  StringCompare.java

  StringUtil.java

  TokenizerModeSample.java

  TwoByteToOneByte.java

 

(記 大坂 哲司)