日本語形態素解析システム「MeCab」を使って楽しく形態素解析をしているわけですが、セキュリティ用語が意外と辞書にないようで、期待通りの結果が出ないことが多いため、自分で作ってみることにしました。
とりあえずアウトプットしないと始まらないので、まだ102単語しか書いていないのですが公開します。
https://github.com/nekotricolor/mecab-it-security-dictionary
以下、苦労話です。読まなくてもいいですが読んだ上で褒めてほしい。
やりたいこと
たとえば「サイドチャネル」を解析してみると:
サイドチャネル サイド 名詞,一般,*,*,*,*,サイド,サイド,サイド チャネル 名詞,一般,*,*,*,*,チャネル,チャネル,チャネル EOS
これを
サイドチャネル 名詞,固有名詞,一般,*,*,*,サイドチャネル,サイドチャネル,サイドチャネル
と一単語として認識するようにします。
MeCab入りのDockerイメージを作る
Ubuntu 18.04にRubyとMeCabを入れた環境を作ります。nattoはbundlerで。
Gemfileは以下の通り。
source "https://rubygems.org" gem 'mecab' gem 'natto'
Dockerfileは以下の通り。
FROM ubuntu:18.04 ENV LANG=C.UTF-8 ENV WORK_DIR /work RUN mkdir -p ${WORK_DIR} WORKDIR ${WORK_DIR} RUN apt-get update && apt-get upgrade -y # basic tools RUN apt-get install -y git gdb file vim RUN apt-get install -y curl wget ruby ruby-dev # install mecab RUN apt-get install libmecab2 libmecab-dev mecab mecab-ipadic mecab-ipadic-utf8 mecab-utils RUN apt-get install -y make xz-utils build-essential ADD Gemfile Gemfile RUN gem install bundler RUN bundle install
LANG環境変数の設定をしないと以下のようなMeCabのエラーがでます。すっごくハマりました。
/var/lib/gems/2.5.0/gems/natto-1.2.0/lib/natto/natto.rb:423:in `rescue in block (2 levels) in initialize': MECAB_NBEST request type is not set (Natto::MeCabError)
これでイメージを作ります。
% docker build -t mecab-ruby:basic .
シェルで作業したいのでDocker起動用に以下のようなシェルスクリプトを作りました。/Users/nekotricolor/Documents/mecab-it-security-dictionaryフォルダを/root/shareとしてマウントしています。
docker run --rm -it --name mecab-ruby -v /Users/nekotricolor/Documents/mecab-it-security-dictionary:/root/share mecab-ruby:basic /bin/bash
単語のリスト作り
Googleスプレッドシートで単語のリストを作ります。MeCabの辞書のフォーマットは以下の通り。
表層形,左文脈ID,右文脈ID,コスト,品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用型,活用形,原形,読み,発音
品詞細分類はIPA品詞体系に基づくものです。定義通りに書いておかないとコンパイルできないので注意。
今回は全て以下に統一しています。
- 品詞:名詞
- 品詞細分類1:固有名詞
- 品詞細分類2:一般
例えば「サイドチャネル」の場合(左/右文脈IDとコストは後述):
サイドチャネル,1288,1288,20,名詞,固有名詞,一般,,,*,サイドチャネル,サイドチャネル,サイドチャネル
左/右文脈IDとコストはあとで入力するとして、とりあえず表層形・品詞・品詞細分類1・原形・読み・発音を埋めます。
単語登録の参考にさせていただいたサイトは以下の通りです。ありがとうございました。
左/右文脈IDの決定
以前のバージョンでは左/右文脈IDは空欄にしておくと自動でつけてくれていたのですが、最新バージョンでは自分でつける必要があります。IDは、以下のファイルで定義されています。
- left-id.def
- right-id.def
該当部分はここ。左右同じでした。
1288 名詞,固有名詞,一般,,,,
ということで、左/右文脈IDは1288でいいみたいですね。
この記事が大変参考になりました。
辞書のコンパイルと追加
辞書のスプレッドシートを「mecab-it-security-dic.csv」という名前でcsv形式でダウンロードし、MeCabのmecab-dict-indexというコマンドを使ってコンパイルします。
システム辞書があるディレクトリを渡す必要があるのでそれを調べます。
$ mecab -D filename: /var/lib/mecab/dic/debian/sys.dic version: 102 charset: UTF-8 type: 0 size: 392126 left size: 1316 right size: 1316
「/var/lib/mecab/dic/debian/」ですね。
$ /usr/lib/mecab/mecab-dict-index -d /var/lib/mecab/dic/debian -u mecab-it-security-dic.dic -f utf8 -t utf8 mecab-it-security-dic.csv
これで、カレントディレクトリに「mecab-it-security-dic.dic」というファイルができます。/etc/mecabrcに以下を追加。
userdic = /root/share/mecab-it-security-dic.dic
「サイドチャネル」を解析してみると、無事一単語として認識されました。
サイドチャネル サイドチャネル 名詞,固有名詞,一般,*,*,*,サイドチャネル,サイドチャネル,サイドチャネル EOS
辞書の作成と、mecabのユーザ辞書への追加は以下の本家の記事を参考にしました。
これを使ってやりたいこと
- 登録単語数を増やすために、いろいろな記事を形態素解析してみて出てこない単語を拾う
- 表記の揺れをなんとかしたい(「水飲み場"型"攻撃」と「水飲み場攻撃」とか)
- 4年前から溜め込んでいるセキュリティ系ニュースのフィードを解析して何か面白い結果が出るか見たい
- 形態素解析する必要はなくて、今回作った辞書の単語でパターンマッチすればいいだけかも・・・