KNPの固有表現認識モデル学習方法
KNPでも学習データを用意すれば、CaboChaのように固有表現認識モデルを学習させることができる。
学習方法は、ここに書かれている通りだけど、試してみてセグフォに嵌ったのでメモ_φ(・_・
- JUMAN 7.01
- KNP 4.16
学習データの用意(アノテーション)
学習データは、JUMANの出力に対して<NE:タグ名:ポジション名>のように固有表現アノテーションが付与された形式をとる。
タグは、{"ORGANIZATION", "PERSON", "LOCATION", "ARTIFACT", "DATE", "TIME", "MONEY", "PERCENT"} ポジションは、{"B", "I", "E", "S"} を使う。
実際に作業する際は、KNPの解析結果から形態素行を抜き出して、必要に応じて固有表現を修正する。
$ cat train.txt 昨夜、安倍晋三首相は赤崎氏に電話した $ cat train.txt | juman | knp -simple | grep ^[^#*+] > train.jmn $ vim train.jmn 昨夜 さくや 昨夜 名詞 6 時相名詞 10 * 0 * 0 "代表表記:昨夜/さくや カテゴリ:時間" <NE:TIME:S> 、 、 、 特殊 1 読点 2 * 0 * 0 NIL 安倍 あべ 安倍 名詞 6 人名 5 * 0 * 0 "人名:日本:姓:189:0.00134 疑似代表表記 代表表記:安倍/あべ" <NE:PERSON:B> 晋三 すすむさん 晋三 名詞 6 人名 5 * 0 * 0 "人名:日本:名:427:0.00035 疑似代表表記 代表表記:晋三/すすむさん 品詞変更:晋-すすむ-晋-6-5-0-0 品詞変更:晋-すすむ-晋-6-5-0-0" <NE:PERSON:E> 首相 しゅしょう 首相 名詞 6 普通名詞 1 * 0 * 0 "代表表記:首相/しゅしょう 人名末尾 カテゴリ:人 ドメイン:政治" は は は 助詞 9 副助詞 2 * 0 * 0 NIL 赤 あか 赤 名詞 6 普通名詞 1 * 0 * 0 "代表表記:赤/あか 漢字読み:訓 カテゴリ:色" <NE:PERSON:B> 崎 崎 崎 名詞 6 普通名詞 1 * 0 * 0 "疑似代表表記 代表表記:崎/崎 品詞変更:崎-崎-崎-15-1-0-0" <NE:PERSON:E> 氏 し 氏 接尾辞 14 名詞性名詞接尾辞 2 * 0 * 0 "代表表記:氏/し" に に に 助詞 9 格助詞 1 * 0 * 0 NIL 電話 でんわ 電話 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:電話/でんわ 補文ト カテゴリ:人工物-その他 ドメイン:家庭・暮らし" した した する 動詞 2 * 0 サ変動詞 16 タ形 10 "代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる" EOS
CRF++で学習させる
まず、KNPに固有表現学習オプション(-ne-train)があるので、それを使ってCRF++へ入力する学習データへ変換できる。
$ knp -ne-train < train.jmn 2> train.data $ cat train.data 昨夜 名詞 時相名詞 漢字 L:2 NIL CT:時間 CS:無格 P:電話 S:昨夜 SINGLE C 123 、 特殊 読点 記号 L:1 NIL CT NIL NIL NIL OTHER C 132 安倍 名詞 人名 漢字 L:2 H:人名末尾 CT CS:未格 P:電話 H:首相 BEGIN C 104 晋三 名詞 人名 漢字 L:2 H:人名末尾 CT CS:未格 P:電話 H:首相 INTER C 106 首相 名詞 普通名詞 漢字 L:2 S:人名末尾 CT:人 CS:未格 P:電話 S:首相 END C 132 は 助詞 副助詞 ひらがな L:1 NIL CT NIL NIL NIL OTHER C 132 赤 名詞 普通名詞 漢字 L:1 NIL CT:色 CS:ニ格 P:電話 H:崎 BEGIN C 104 崎 名詞 普通名詞 漢字 L:1 NIL CT CS:ニ格 P:電話 S:崎 END C 106 氏 接尾辞 名詞性名詞接尾辞 漢字 L:1 NIL CT NIL NIL NIL OTHER C 132 に 助詞 格助詞 ひらがな L:1 NIL CT NIL NIL NIL OTHER C 132 電話 名詞 サ変名詞 漢字 L:2 NIL CT:人工物-その他 NIL NIL S:電話 SINGLE C 132 した 動詞 動詞 ひらがな L:2 NIL CT NIL NIL NIL OTHER C 132
学習データが生成されたら、KNPのソースに含まれている素性テンプレート(knp-4.16/crf/template)とCRF++を使って学習させる。
$ crf_learn -f 1 template train.data crf.model CRF++: Yet Another CRF Tool Kit Copyright (C) 2005-2013 Taku Kudo, All rights reserved. reading training data: Done!0.00 s Number of sentences: 1 Number of features: 4128 Number of thread(s): 1 Freq: 1 eta: 0.00010 C: 1.00000 shrinking size: 20 iter=0 terr=0.83333 serr=1.00000 act=4128 obj=16.63553 diff=1.00000 iter=1 terr=0.16667 serr=1.00000 act=4128 obj=4.17870 diff=0.74881 iter=2 terr=0.00000 serr=0.00000 act=4128 obj=1.14238 diff=0.72662 iter=3 terr=0.00000 serr=0.00000 act=4128 obj=1.12581 diff=0.01450 iter=4 terr=0.00000 serr=0.00000 act=4128 obj=1.06598 diff=0.05314 iter=5 terr=0.00000 serr=0.00000 act=4128 obj=1.05841 diff=0.00710 iter=6 terr=0.00000 serr=0.00000 act=4128 obj=1.05495 diff=0.00327 iter=7 terr=0.00000 serr=0.00000 act=4128 obj=1.05394 diff=0.00095 iter=8 terr=0.00000 serr=0.00000 act=4128 obj=1.05353 diff=0.00039 iter=9 terr=0.00000 serr=0.00000 act=4128 obj=1.05341 diff=0.00011 iter=10 terr=0.00000 serr=0.00000 act=4128 obj=1.05331 diff=0.00010 iter=11 terr=0.00000 serr=0.00000 act=4128 obj=1.05331 diff=0.00000 iter=12 terr=0.00000 serr=0.00000 act=4128 obj=1.05330 diff=0.00000 Done!0.00 s
動作確認
生成されたモデルを使うようにknprcを変更する。
$ cp crf.model /usr/local/share/knp/dict/mycrf.model $ vim /usr/local/etc/knprc : (NEモデルファイル ; /usr/local/share/knp/dict/crf.model /usr/local/share/knp/dict/mycrf.model ) :
試しに学習したテキストを解析させてみると Segmentation Fault になってしまう。
$ cat train.txt | juman | knp -simple Segmentation fault (core dumped)
デバッグしてみたところ、全てのラベル候補の周辺確率を取得しようとしているので、一回も学習させていないラベルがあるとエラーになってしまうだけだった。
104(PERSON:B)、106(PERSON:E)、123(TIME:S)、132(OTHER)しか学習してないから。
crf_test -v2 -m crf.model train.data # 0.725886 昨夜 名詞 時相名詞 漢字 L:2 NIL CT:時間 CS:無格 P:電話 S:昨夜 SINGLE C 123 123/0.966497 104/0.009152 106/0.009384 123/0.966497 132/0.014967 、 特殊 読点 記号 L:1 NIL CT NIL NIL NIL OTHER C 132 132/0.976693 104/0.008768 106/0.007523 123/0.007016 132/0.976693 安倍 名詞 人名 漢字 L:2 H:人名末尾 CT CS:未格 P:電話 H:首相 BEGIN C 104 104/0.968226 104/0.968226 106/0.007983 123/0.006219 132/0.017572 晋三 名詞 人名 漢字 L:2 H:人名末尾 CT CS:未格 P:電話 H:首相 INTER C 106 106/0.969562 104/0.009320 106/0.969562 123/0.005628 132/0.015490 首相 名詞 普通名詞 漢字 L:2 S:人名末尾 CT:人 CS:未格 P:電話 S:首相 END C 132 132/0.975734 104/0.007709 106/0.009869 123/0.006688 132/0.975734 は 助詞 副助詞 ひらがな L:1 NIL CT NIL NIL NIL OTHER C 132 132/0.981199 104/0.007942 106/0.006335 123/0.004524 132/0.981199 赤 名詞 普通名詞 漢字 L:1 NIL CT:色 CS:ニ格 P:電話 H:崎 BEGIN C 104 104/0.966110 104/0.966110 106/0.010123 123/0.005958 132/0.017809 崎 名詞 普通名詞 漢字 L:1 NIL CT CS:ニ格 P:電話 S:崎 END C 106 106/0.964598 104/0.007980 106/0.964598 123/0.005982 132/0.021440 氏 接尾辞 名詞性名詞接尾辞 漢字 L:1 NIL CT NIL NIL NIL OTHER C 132 132/0.980925 104/0.006594 106/0.007754 123/0.004727 132/0.980925 に 助詞 格助詞 ひらがな L:1 NIL CT NIL NIL NIL OTHER C 132 132/0.979295 104/0.008626 106/0.007978 123/0.004101 132/0.979295 電話 名詞 サ変名詞 漢字 L:2 NIL CT:人工物-その他 NIL NIL S:電話 SINGLE C 132 132/0.976011 104/0.009213 106/0.008686 123/0.006089 132/0.976011 した 動詞 動詞 ひらがな L:2 NIL CT NIL NIL NIL OTHER C 132 132/0.978093 104/0.006737 106/0.009539 123/0.005631 132/0.978093
学習データの追加
強引にラベルを一通り用意する。
昨夜 さくや 昨夜 名詞 6 時相名詞 10 * 0 * 0 "代表表記:昨夜/さくや カテゴリ:時間" <NE:TIME:S> 、 、 、 特殊 1 読点 2 * 0 * 0 NIL 安倍 あべ 安倍 名詞 6 人名 5 * 0 * 0 "人名:日本:姓:189:0.00134 疑似代表表記 代表表記:安倍/あべ" <NE:PERSON:B> 晋三 すすむさん 晋三 名詞 6 人名 5 * 0 * 0 "人名:日本:名:427:0.00035 疑似代表表記 代表表記:晋三/すすむさん 品詞変更:晋-すすむ-晋-6-5-0-0 品詞変更:晋-すすむ-晋-6-5-0-0" <NE:PERSON:E> 首相 しゅしょう 首相 名詞 6 普通名詞 1 * 0 * 0 "代表表記:首相/しゅしょう 人名末尾 カテゴリ:人 ドメイン:政治" は は は 助詞 9 副助詞 2 * 0 * 0 NIL 赤 あか 赤 名詞 6 普通名詞 1 * 0 * 0 "代表表記:赤/あか 漢字読み:訓 カテゴリ:色" <NE:PERSON:B> 崎 崎 崎 名詞 6 普通名詞 1 * 0 * 0 "疑似代表表記 代表表記:崎/崎 品詞変更:崎-崎-崎-15-1-0-0" <NE:PERSON:E> 氏 し 氏 接尾辞 14 名詞性名詞接尾辞 2 * 0 * 0 "代表表記:氏/し" に に に 助詞 9 格助詞 1 * 0 * 0 NIL 電話 でんわ 電話 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:電話/でんわ 補文ト カテゴリ:人工物-その他 ドメイン:家庭・暮らし" した した する 動詞 2 * 0 サ変動詞 16 タ形 10 "代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる" EOS 太郎 たろう 太郎 名詞 6 人名 5 * 0 * 0 "人名:日本:名:45:0.00106 疑似代表表記 代表表記:太郎/たろう" <NE:PERSON:S> は は は 助詞 9 副助詞 2 * 0 * 0 NIL 朝 あさ 朝 名詞 6 時相名詞 10 * 0 * 0 "代表表記:朝/あさ 漢字読み:訓 カテゴリ:時間" <NE:TIME:B> 9 きゅう 9 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:9/きゅう" <NE:TIME:I> 時 じ 時 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:時/じ 準内容語 カテゴリ:時間" <NE:TIME:E> に に に 助詞 9 格助詞 1 * 0 * 0 NIL 花子 はなこ 花子 名詞 6 人名 5 * 0 * 0 "人名:日本:名:912:0.00019 疑似代表表記 代表表記:花子/はなこ" <NE:LOCATION:S> に に に 助詞 9 格助詞 1 * 0 * 0 NIL 会い あい 会う 動詞 2 * 0 子音動詞ワ行 12 基本連用形 8 "代表表記:会う/あう 反義:動詞:分かれる/わかれる;動詞:別れる/わかれる" に に に 助詞 9 格助詞 1 * 0 * 0 NIL 行った いった 行く 動詞 2 * 0 子音動詞カ行促音便形 3 タ形 10 "代表表記:行く/いく 付属動詞候補(タ系) ドメイン:交通 反義:動詞:帰る/かえる" EOS 藤本 ふじもと 藤本 名詞 6 人名 5 * 0 * 0 "人名:日本:姓:167:0.00147 疑似代表表記 代表表記:藤本/ふじもと" <NE:PERSON:B> 太郎 たろう 太郎 名詞 6 人名 5 * 0 * 0 "人名:日本:名:45:0.00106 疑似代表表記 代表表記:太郎/たろう" <NE:PERSON:I> 喜 喜 喜 名詞 6 普通名詞 1 * 0 * 0 "疑似代表表記 代表表記:喜/喜 品詞変更:喜-喜-喜-15-1-0-0" <NE:PERSON:I> 左 ひだり 左 名詞 6 普通名詞 1 * 0 * 0 "代表表記:左/ひだり 漢字読み:訓 カテゴリ:場所-機能" <NE:PERSON:I> 衛 まもる 衛 名詞 6 人名 5 * 0 * 0 "人名:日本:名:628:0.00025 疑似代表表記 代表表記:衛/まもる" <NE:PERSON:I> 門 もん 門 名詞 6 普通名詞 1 * 0 * 0 "代表表記:門/もん 漢字読み:音 カテゴリ:場所-施設" <NE:PERSON:I> 将 すすむ 将 名詞 6 人名 5 * 0 * 0 "人名:日本:名:1439:0.00012 疑似代表表記 代表表記:将/すすむ" <NE:PERSON:I> 時 じ 時 名詞 6 時相名詞 10 * 0 * 0 "代表表記:時/じ 漢字読み:音 弱時相名詞 カテゴリ:時間" <NE:PERSON:I> 能 のう 能 名詞 6 普通名詞 1 * 0 * 0 "代表表記:能/のう 漢字読み:音 カテゴリ:抽象物" <NE:PERSON:E> と と と 助詞 9 格助詞 1 * 0 * 0 NIL いう いう いう 動詞 2 * 0 子音動詞ワ行 12 基本形 2 "代表表記:言う/いう 補文ト" 名前 なまえ 名前 名詞 6 普通名詞 1 * 0 * 0 "代表表記:名前/なまえ カテゴリ:抽象物" の の の 助詞 9 接続助詞 3 * 0 * 0 NIL 人 じん 人 名詞 6 普通名詞 1 * 0 * 0 "代表表記:人/じん 漢字読み:音 カテゴリ:人" が が が 助詞 9 格助詞 1 * 0 * 0 NIL いる いる いる 動詞 2 * 0 子音動詞ラ行 10 基本形 2 "代表表記:煎る/いる ドメイン:料理・食事" らしい らしい らしい 助動詞 5 * 0 イ形容詞イ段 19 基本形 2 NIL EOS 今年 ことし 今年 名詞 6 時相名詞 10 * 0 * 0 "代表表記:今年/ことし カテゴリ:時間" <NE:DATE:S> の の の 助詞 9 接続助詞 3 * 0 * 0 NIL 人工 じんこう 人工 名詞 6 普通名詞 1 * 0 * 0 "代表表記:人工/じんこう カテゴリ:抽象物" <NE:ORGANIZATION:B> 知能 ちのう 知能 名詞 6 普通名詞 1 * 0 * 0 "代表表記:知能/ちのう カテゴリ:抽象物" <NE:ORGANIZATION:I> 学会 がっかい 学会 名詞 6 普通名詞 1 * 0 * 0 "代表表記:学会/がっかい 組織名末尾 カテゴリ:組織・団体;抽象物 ドメイン:科学・技術" <Wikipedia上位語:学会/がっかい:2-4><Wikipediaエ>ントリ:人工知能学会:2-4> <NE:ORGANIZATION:E> 全国 ぜんこく 全国 名詞 6 普通名詞 1 * 0 * 0 "代表表記:全国/ぜんこく カテゴリ:場所-その他" 大会 たいかい 大会 名詞 6 普通名詞 1 * 0 * 0 "代表表記:大会/たいかい カテゴリ:抽象物" <Wikipediaエントリ:全国大会:5-6> は は は 助詞 9 副助詞 2 * 0 * 0 NIL 2016 にぜろいちろく 2016 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:2016/にぜろいちろく" <NE:DATE:B> 年 ねん 年 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:年/ねん 準内容語 カテゴリ:時間" <NE:DATE:I> 6 ろく 6 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:6/ろく" <NE:DATE:I> 月 がつ 月 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:月/がつ 準内容語 カテゴリ:時間" <NE:DATE:I> 6 ろく 6 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:6/ろく" <NE:DATE:I> 日 にち 日 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:日/にち 準内容語 カテゴリ:時間" <NE:DATE:E> 〜 〜 〜 特殊 1 記号 5 * 0 * 0 NIL 9 きゅう 9 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:9/きゅう" <NE:DATE:B> 日 にち 日 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:日/にち 準内容語 カテゴリ:時間" <NE:DATE:E> まで まで まで 助詞 9 格助詞 1 * 0 * 0 NIL 北九州 きたきゅう 北九州 名詞 6 地名 4 * 0 * 0 "代表表記:北九州/きたきゅう 地名:日本:福岡県:市" <NE:LOCATION:B> 国際 こくさい 国際 名詞 6 普通名詞 1 * 0 * 0 "代表表記:国際/こくさい カテゴリ:抽象物" <NE:LOCATION:I> 会議 かいぎ 会議 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:会議/かいぎ 組織名末尾 カテゴリ:抽象物" <NE:LOCATION:I> 場 ば 場 名詞 6 普通名詞 1 * 0 * 0 "代表表記:場/ば 漢字読み:訓 カテゴリ:場所-その他;抽象物" <Wikipedia上位語:コンベンションセンター:18-21><Wikipediaエントリ:北九州国際会議場:18-21> <NE:LOCATION:E> で で で 助詞 9 格助詞 1 * 0 * 0 NIL 開催 かいさい 開催 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:開催/かいさい カテゴリ:抽象物" さ さ する 動詞 2 * 0 サ変動詞 16 未然形 3 "代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる" れ れ れる 接尾辞 14 動詞性接尾辞 7 母音動詞 1 基本連用形 8 "代表表記:れる/れる" ます ます ます 接尾辞 14 動詞性接尾辞 7 動詞性接尾辞ます型 31 基本形 2 "代表表記:ます/ます" EOS この前 このまえ この前 名詞 6 時相名詞 10 * 0 * 0 "代表表記:此前/このまえ カテゴリ:時間" の の の 助詞 9 接続助詞 3 * 0 * 0 NIL 祝日 しゅくじつ 祝日 名詞 6 普通名詞 1 * 0 * 0 "代表表記:祝日/しゅくじつ カテゴリ:時間" <NE:DATE:S> に に に 助詞 9 格助詞 1 * 0 * 0 NIL 原野 げんや 原野 名詞 6 普通名詞 1 * 0 * 0 "代表表記:原野/げんや カテゴリ:場所-自然" <NE:LOCATION:B> 谷川 たにがわ 谷川 名詞 6 普通名詞 1 * 0 * 0 "代表表記:谷川/たにがわ カテゴリ:場所-自然" <Wikipedia上位語:河川/かせん:4-5><Wikipediaエントリ:原野谷川:4-5><NE:LOCATION:I> 親水 親水 親水 名詞 6 普通名詞 1 * 0 * 0 "自動獲得:テキスト 疑似代表表記 代表表記:親水/親水" <NE:LOCATION:I> 公園 こうえん 公園 名詞 6 普通名詞 1 * 0 * 0 "代表表記:公園/こうえん カテゴリ:場所-施設 ドメイン:レクリエーション" <Wikipediaエントリ:親水公園:6-7><NE:LOCATION:E> で で で 助詞 9 格助詞 1 * 0 * 0 NIL バーベキュー ばーべきゅー バーベキュー 名詞 6 普通名詞 1 * 0 * 0 "代表表記:バーベキュー/ばーべきゅー カテゴリ:人工物-食べ物 ドメイン:料理・食事" を を を 助詞 9 格助詞 1 * 0 * 0 NIL した した する 動詞 2 * 0 サ変動詞 16 タ形 10 "代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる" EOS この前 このまえ この前 名詞 6 時相名詞 10 * 0 * 0 "代表表記:此前/このまえ カテゴリ:時間" の の の 助詞 9 接続助詞 3 * 0 * 0 NIL 祝日 しゅくじつ 祝日 名詞 6 普通名詞 1 * 0 * 0 "代表表記:祝日/しゅくじつ カテゴリ:時間" <NE:DATE:S> に に に 助詞 9 格助詞 1 * 0 * 0 NIL 原野 げんや 原野 名詞 6 普通名詞 1 * 0 * 0 "代表表記:原野/げんや カテゴリ:場所-自然" <NE:LOCATION:B> 谷川 たにがわ 谷川 名詞 6 普通名詞 1 * 0 * 0 "代表表記:谷川/たにがわ カテゴリ:場所-自然" <Wikipedia上位語:河川/かせん:4-5><Wikipediaエントリ:原野谷川:4-5><NE:LOCATION:I> 親水 親水 親水 名詞 6 普通名詞 1 * 0 * 0 "自動獲得:テキスト 疑似代表表記 代表表記:親水/親水" <NE:LOCATION:I> 公園 こうえん 公園 名詞 6 普通名詞 1 * 0 * 0 "代表表記:公園/こうえん カテゴリ:場所-施設 ドメイン:レクリエーション" <Wikipediaエントリ:親水公園:6-7><NE:LOCATION:E> で で で 助詞 9 格助詞 1 * 0 * 0 NIL バーベキュー ばーべきゅー バーベキュー 名詞 6 普通名詞 1 * 0 * 0 "代表表記:バーベキュー/ばーべきゅー カテゴリ:人工物-食べ物 ドメイン:料理・食事" を を を 助詞 9 格助詞 1 * 0 * 0 NIL した した する 動詞 2 * 0 サ変動詞 16 タ形 10 "代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる" EOS 掛川 かけがわ 掛川 名詞 6 地名 4 * 0 * 0 "代表表記:掛川/かけがわ 地名:日本:静岡県:市" <NE:LOCATION:S> は は は 助詞 9 副助詞 2 * 0 * 0 NIL こだま こだま こだま 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:木霊/こだま カテゴリ:抽象物" <NE:ARTIFACT:S> しか しか しか 助詞 9 副助詞 2 * 0 * 0 NIL 止まら とまら 止まる 動詞 2 * 0 子音動詞ラ行 10 未然形 3 "代表表記:止まる/とまる 自他動詞:他:止める/とめる 反義:動詞:動く/うごく" ない ない ない 接尾辞 14 形容詞性述語接尾辞 5 イ形容詞アウオ段 18 基本形 2 "代表表記:ない/ない" EOS 天竜 てんりゅう 天竜 名詞 6 地名 4 * 0 * 0 "代表表記:天竜/てんりゅう 地名:日本:静岡県:区" <NE:ARTIFACT:B> 浜名湖 浜名湖 浜名湖 名詞 6 普通名詞 1 * 0 * 0 "自動獲得:テキスト 疑似代表表記 代表表記:浜名湖/浜名湖" <NE:ARTIFACT:I> 線 せん 線 名詞 6 普通名詞 1 * 0 * 0 "代表表記:線/せん 漢字読み:音 カテゴリ:形・模様" <Wikipediaエントリ:天竜浜名湖線:0-2><NE:ARTIFACT:E> が が が 助詞 9 格助詞 1 * 0 * 0 NIL なくなる なくなる なくなる 動詞 2 * 0 子音動詞ラ行 10 基本形 2 "代表表記:無くなる/なくなる 自他動詞:他:無くす/なくす" と と と 助詞 9 格助詞 1 * 0 * 0 NIL 意外に いがいに 意外だ 形容詞 3 * 0 ナノ形容詞 22 ダ列基本連用形 8 "代表表記:意外だ/いがいだ" 困る こまる 困る 動詞 2 * 0 子音動詞ラ行 10 基本形 2 "代表表記:困る/こまる" EOS 今 こん 今 接頭辞 13 名詞接頭辞 1 * 0 * 0 "代表表記:今/こん 内容語" シーズン しーずん シーズン 名詞 6 時相名詞 10 * 0 * 0 "代表表記:シーズン/しーずん 弱時相名詞 カテゴリ:時間" の の の 助詞 9 接続助詞 3 * 0 * 0 NIL 打率 だりつ 打率 名詞 6 普通名詞 1 * 0 * 0 "代表表記:打率/だりつ カテゴリ:数量 ドメイン:スポーツ" は は は 助詞 9 副助詞 2 * 0 * 0 NIL 3 さん 3 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:3/さん" <NE:PERCENT:B> 割 わり 割 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:割/わり 準内容語" <NE:PERCENT:I> 5 ご 5 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:5/ご" <NE:PERCENT:I> 分 ふん 分 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:分/ふん 準内容語 カテゴリ:時間" <NE:PERCENT:I> 5 ご 5 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:5/ご" <NE:PERCENT:I> 厘 りん 厘 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:厘/りん 準内容語" <NE:PERCENT:E> と と と 助詞 9 格助詞 1 * 0 * 0 NIL まあまあ まあまあ まあまあだ 形容詞 3 * 0 ナノ形容詞 22 語幹 1 "代表表記:まあまあ/まあまあa 代表表記変更:まあまあだ/まあまあだ" 調子 ちょうし 調子 名詞 6 普通名詞 1 * 0 * 0 "代表表記:調子/ちょうし カテゴリ:抽象物" が が が 助詞 9 格助詞 1 * 0 * 0 NIL いい いい いい 形容詞 3 * 0 イ形容詞イ段 19 基本形 2 "代表表記:良い/よい 反義:形容詞:悪い/わるい" EOS バナナ ばなな バナナ 名詞 6 普通名詞 1 * 0 * 0 "代表表記:バナナ/ばなな カテゴリ:植物;人工物-食べ物 ドメイン:料理・食事" 半分 はんぶん 半分 名詞 6 普通名詞 1 * 0 * 0 "代表表記:半分/はんぶん カテゴリ:数量" <NE:PERCENT:S> ちょうだいな ちょうだいな ちょうだいだ 形容詞 3 * 0 ナ形容詞 21 ダ列基本連体形 3 "代表表記:長大だ/ちょうだいだ" EOS 参加 さんか 参加 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:参加/さんか カテゴリ:抽象物" 費 ひ 費 接尾辞 14 名詞性名詞接尾辞 2 * 0 * 0 "代表表記:費/ひ 内容語 カテゴリ:人工物-金銭 同義:名詞:費用/ひよう" と と と 助詞 9 格助詞 1 * 0 * 0 NIL して して する 動詞 2 * 0 サ変動詞 16 タ系連用テ形 14 "代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる" 1万 いちまん 1万 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:1万/いちまん" <NE:MONEY:S> いただき いただき いただく 動詞 2 * 0 子音動詞カ行 2 基本連用形 8 "代表表記:頂く/いただく 付属動詞候補(タ系) 謙譲動詞:貰う/もらう;食べる/たべる;飲む/のむ" ます ます ます 接尾辞 14 動詞性接尾辞 7 動詞性接尾辞ます型 31 基本形 2 "代表表記:ます/ます" EOS 明日 あす 明日 名詞 6 時相名詞 10 * 0 * 0 "代表表記:明日/あす カテゴリ:時間" まで まで まで 助詞 9 格助詞 1 * 0 * 0 NIL に に に 助詞 9 格助詞 1 * 0 * 0 NIL 100万 いちぜろぜろまん 100万 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:100万/いちぜろぜろまん" <NE:MONEY:B> 香港 ほんこん 香港 名詞 6 地名 4 * 0 * 0 "代表表記:香港/ほんこん 地名:国:中国:特別行政区" <NE:MONEY:I> ドル どる ドル 名詞 6 普通名詞 1 * 0 * 0 "代表表記:ドル/どる カテゴリ:数量 ドメイン:ビジネス" <Wikipedia上位語:通貨/つうか:4-5><Wikipediaエントリ:香港ドル:4-5> <NE:MONEY:E> 用意 ようい 用意 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:用意/ようい カテゴリ:抽象物" しろ しろ する 動詞 2 * 0 サ変動詞 16 命令形 6 "代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる" EOS Google Google Google 名詞 6 普通名詞 1 * 0 * 0 "自動獲得:Wikipedia Wikipedia上位語:検索エンジン 読み不明 疑似代表表記 代表表記:Google/Google" <Wikipedia上位語:検索エンジン> <NE:ORGANIZATION:S> が が が 助詞 9 格助詞 1 * 0 * 0 NIL 、 、 、 特殊 1 読点 2 * 0 * 0 NIL 「 「 「 特殊 1 括弧始 3 * 0 * 0 NIL SyntaxNet SyntaxNet SyntaxNet 名詞 6 組織名 6 * 0 * 0 "疑似代表表記 代表表記:SyntaxNet/SyntaxNet 品詞変更:SyntaxNet-Syn taxNet-SyntaxNet-15-3-0-0" <NE:ARTIFACT:S> 」 」 」 特殊 1 括弧終 4 * 0 * 0 NIL を を を 助詞 9 格助詞 1 * 0 * 0 NIL オープンソース オープンソース オープンソース 名詞 6 普通名詞 1 * 0 * 0 "自動獲得:Wikipedia 疑似代表表記 代表表記:オープンソース/オープンソース" で で で 助詞 9 格助詞 1 * 0 * 0 NIL 公開 こうかい 公開 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:公開/こうかい カテゴリ:抽象物" した した する 動詞 2 * 0 サ変動詞 16 タ形 10 "代表表記:する/する 付属動詞候補(基本) 自他動詞:自:成る/なる" EOS
再度モデルを作り直してテスト。
$ knp -ne-train < train.jmn 2> train.data $ crf_learn -f 1 template train.data crf.model CRF++: Yet Another CRF Tool Kit Copyright (C) 2005-2013 Taku Kudo, All rights reserved. reading training data: Done!0.01 s Number of sentences: 12 Number of features: 213708 Number of thread(s): 1 Freq: 1 eta: 0.00010 C: 1.00000 shrinking size: 20 iter=0 terr=0.99275 serr=1.00000 act=213708 obj=482.51804 diff=1.00000 iter=1 terr=0.42029 serr=1.00000 act=213708 obj=257.48250 diff=0.46638 iter=2 terr=0.42029 serr=1.00000 act=213708 obj=221.64201 diff=0.13920 iter=3 terr=0.23913 serr=1.00000 act=213708 obj=149.06598 diff=0.32745 iter=4 terr=0.07246 serr=0.66667 act=213708 obj=83.50011 diff=0.43984 iter=5 terr=0.00000 serr=0.00000 act=213708 obj=28.64027 diff=0.65700 iter=6 terr=0.00000 serr=0.00000 act=213708 obj=24.48020 diff=0.14525 iter=7 terr=0.00000 serr=0.00000 act=213708 obj=22.59193 diff=0.07713 iter=8 terr=0.00000 serr=0.00000 act=213708 obj=21.50966 diff=0.04791 iter=9 terr=0.00000 serr=0.00000 act=213708 obj=20.50080 diff=0.04690 iter=10 terr=0.00000 serr=0.00000 act=213708 obj=19.63163 diff=0.04240 iter=11 terr=0.00000 serr=0.00000 act=213708 obj=18.92093 diff=0.03620 iter=12 terr=0.00000 serr=0.00000 act=213708 obj=18.43905 diff=0.02547 iter=13 terr=0.00000 serr=0.00000 act=213708 obj=18.27158 diff=0.00908 iter=14 terr=0.00000 serr=0.00000 act=213708 obj=18.21956 diff=0.00285 iter=15 terr=0.00000 serr=0.00000 act=213708 obj=18.16238 diff=0.00314 iter=16 terr=0.00000 serr=0.00000 act=213708 obj=18.13418 diff=0.00155 iter=17 terr=0.00000 serr=0.00000 act=213708 obj=18.11071 diff=0.00129 iter=18 terr=0.00000 serr=0.00000 act=213708 obj=18.09165 diff=0.00105 iter=19 terr=0.00000 serr=0.00000 act=213708 obj=18.08471 diff=0.00038 iter=20 terr=0.00000 serr=0.00000 act=213708 obj=18.08399 diff=0.00004 iter=21 terr=0.00000 serr=0.00000 act=213708 obj=18.08047 diff=0.00019 iter=22 terr=0.00000 serr=0.00000 act=213708 obj=18.07992 diff=0.00003 iter=23 terr=0.00000 serr=0.00000 act=213708 obj=18.07892 diff=0.00006 iter=24 terr=0.00000 serr=0.00000 act=213708 obj=18.07867 diff=0.00001 Done!1.56 s $ vim test.txt 大谷選手の今シーズンの打率は3割4分8厘と調子がいい $ cat test.txt | juman | knp -simple # S-ID:1 KNP:4.16-CF1.1 DATE:2016/05/22 SCORE:-30.36771 * 2D <体言><係:ノ格> + 1D <係:文節内><体言> 大谷 おおたに 大谷 名詞 6 人名 5 * 0 * 0 "人名:日本:姓:199:0.00129 疑似代表表記 代表表記:大谷/おおたに" + 4D <体言><係:ノ格> 選手 せんしゅ 選手 名詞 6 普通名詞 1 * 0 * 0 "代表表記:選手/せんしゅ 人名末尾 カテゴリ:人 ドメイン:スポーツ" の の の 助詞 9 接続助詞 3 * 0 * 0 NIL * 2D <体言><係:ノ格> + 3D <係:文節内> 今 こん 今 接頭辞 13 名詞接頭辞 1 * 0 * 0 "代表表記:今/こん 内容語" + 4D <体言><係:ノ格> シーズン しーずん シーズン 名詞 6 時相名詞 10 * 0 * 0 "代表表記:シーズン/しーずん 弱時相名詞 カテゴリ:時間" の の の 助詞 9 接続助詞 3 * 0 * 0 NIL * 7D <体言><係:未格> + 9D <体言><係:未格> 打率 だりつ 打率 名詞 6 普通名詞 1 * 0 * 0 "代表表記:打率/だりつ カテゴリ:数量 ドメイン:スポーツ" は は は 助詞 9 副助詞 2 * 0 * 0 NIL * 4D <体言><係:隣> + 6D <体言><係:隣><NE内:PERCENT> 3 さん 3 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:3/さん" <NE:PERCENT:B> 割 わり 割 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:割/わり 準内容語" <NE:PERCENT:I> * 6D <体言><係:隣> + 8D <体言><係:隣><NE内:PERCENT> 4 よん 4 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:4/よん" <NE:PERCENT:I> 分 ふん 分 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:分/ふん 準内容語 カテゴリ:時間" <NE:PERCENT:I> * 6P <体言><係:ト格> + 8P <体言><係:ト格><NE:PERCENT:3割4分8厘> 8 はち 8 名詞 6 数詞 7 * 0 * 0 "カテゴリ:数量 疑似代表表記 代表表記:8/はち" <NE:PERCENT:I> 厘 りん 厘 接尾辞 14 名詞性名詞助数辞 3 * 0 * 0 "代表表記:厘/りん 準内容語" <NE:PERCENT:E> と と と 助詞 9 格助詞 1 * 0 * 0 NIL * 7D <体言><係:ガ格> + 9D <体言><係:ガ格> 調子 ちょうし 調子 名詞 6 普通名詞 1 * 0 * 0 "代表表記:調子/ちょうし カテゴリ:抽象物" が が が 助詞 9 格助詞 1 * 0 * 0 NIL * -1D <用言:形><レベル:C><ID:(文末)> + -1D <用言:形><レベル:C><ID:(文末)><格解析結果:良い/よい:形4:ガ/C/厘/7/0/1;ガ/C/調子/8/0/1;ニ/U/-/-/-/-;ト/U/-/-/-/-;デ/U/-/-/-/-;カラ/U/-/-/-/-;ヨリ/U/-/-/-/-;マデ/U/-/-/-/-;時間/U/-/-/-/-;外の関係/U/-/-/-/-;修飾/U/-/-/-/-;ノ/U/-/-/-/-;ガ2/N/打率/4/0/1;トスル/U/-/-/-/-;ニカギル/U/-/-/-/-;ニクラベル/U/-/-/-/-;ニツヅク/U/-/-/-/-;ヲツウジル/U/-/-/-/-;ニオク/U/-/-/-/-> いい いい いい 形容詞 3 * 0 イ形容詞イ段 19 基本形 2 "代表表記:良い/よい 反義:形容詞:悪い/わるい" EOS
動くようになった。
ValueError: numpy.dtype has the wrong size, try recompiling
scikit-learnとかpandas環境のセットアップ作業で、手間取ってnumpyのバージョン動かしてると出るエラー。
単純に再インストールしてもキャッシュを見てビルドされないらしー。
$ pip uninstall scikit-learn $ pip install scikit-learn==0.16.1 --no-cache-dir
とやる_φ(・_・
係り受け解析器の学習機能
もう少し自然言語処理の意味理解よりのことをちゃんと勉強してみようと思う今日この頃。のやったことメモ_φ(・_・
今回は、係り受け解析器のうち、CaboChaとJ.DepP の学習機能を動かしてみたのでその辺の備忘メモ
準備
CaboChaは既にインストール済み。
モデルは今回、KNBコーパスから学習させるので品詞体系をJUMANにしておく。モデル(係り受け、チャンキング、固有表現)もとりあえずJUMANに変更。
$ cat /usr/local/etc/cabocharc : posset = JUMAN : # Parser model file name parser-model = /usr/local/lib/cabocha/model/dep.juman.model : # Chunker model file name chunker-model = /usr/local/lib/cabocha/model/chunk.juman.model : # NE model file name ne-model = /usr/local/lib/cabocha/model/ne.juman.model :
MeCabのデフォルト辞書もJUMANに変更(辞書のインストールは既に済み)
$ cat /usr/local/etc/mecabrc : dicdir = /usr/local/lib/mecab/dic/jumandic :
動作確認
$ echo "クロールで泳いでいる少女を見た" | cabocha -f 2 -n 1 dep.cpp(90) [decode_posset(p) == posset()] model posset and dependency parser's posset are different: JUMAN != IPA
なぜか品詞体系がIPAのまま?実行時オプションは利いたので、とりあえず今はスルー
$ echo "クロールで泳いでいる少女を見た" | cabocha -P JUMAN -f 2 -n 1 クロールで-D 泳いでいる-D 少女を-D 見た EOS * 0 1D 0/1 1.421559 クロール 名詞,普通名詞,*,*,クロール,くろーる,代表表記:クロール/くろーる カテゴリ:抽象物 ドメイン:スポーツ O で 助詞,格助詞,*,*,で,で,* O * 1 2D 0/1 1.458612 泳いで 動詞,*,子音動詞ガ行,タ系連用テ形,泳ぐ,およいで,代表表記:泳ぐ/およぐ O いる 接尾辞,動詞性接尾辞,母音動詞,基本形,いる,いる,連語 O * 2 3D 0/1 1.458612 少女 名詞,普通名詞,*,*,少女,しょうじょ,代表表記:少女/しょうじょ カテゴリ:人 O を 助詞,格助詞,*,*,を,を,* O * 3 -1D 0/0 0.000000 見た 動詞,*,母音動詞,タ形,見る,みた,代表表記:見る/みる 補文ト 自他動詞:自:見える/みえる O EOS
続いてJ.DepP。 聞いたことなかったけど、CaboCha同様にコーパスから学習させることができるようなので入れてみた。学習、解析速度が速く、学習したモデルの精度もSVMに匹敵するらしい。
こちらは、デフォルトでMeCab、JUMAN辞書、モデルの学習にKNBコーパスを使うようになってる。
$ wget http://www.tkl.iis.u-tokyo.ac.jp/~ynaga/jdepp/jdepp-latest.tar.gz $ tar xzf jdepp-latest.tar.gz $ cd jdepp-2015-10-05/ $ ./configure $ make model $ sudo make install $ echo "クロールで泳いでいる少女を見た" | mecab | jdepp (input: STDIN [-I 0]) # S-ID: 1; J.DepP * 0 1D クロール 名詞,普通名詞,*,*,クロール,くろーる,代表表記:クロール/くろーる カテゴリ:抽象物 ドメイン:スポーツ で 助詞,格助詞,*,*,で,で,* * 1 2D 泳いで 動詞,*,子音動詞ガ行,タ系連用テ形,泳ぐ,およいで,代表表記:泳ぐ/およぐ いる 接尾辞,動詞性接尾辞,母音動詞,基本形,いる,いる,連語 * 2 3D 少女 名詞,普通名詞,*,*,少女,しょうじょ,代表表記:少女/しょうじょ カテゴリ:人 を 助詞,格助詞,*,*,を,を,* * 3 -1D 見た 動詞,*,母音動詞,タ形,見る,みた,代表表記:見る/みる 補文ト 自他動詞:自:見える/みえる EOS J.DepP profiler: io : 0.0166 ms./trial (0.06638521/4) dict : 0.3317 ms. preproc : 0.0194 ms. chunk : 0.0536 ms. depnd : 0.0250 ms.
ついでに、KNPも入れた。解析速度とか今のところ大規模なテキスト処理は厳しいけど、70億分のWebテキストから自動構築した格フレームとかいろいろ興味深いところもあるので、また別途時間をとっていろいろ確認したい。
$ tar xjf juman-7.01.tar.bz2 $ cd juman-7.01 $ ./configure --prefix=/usr/local $ make $ sudo make install $ echo "クロールで泳いでいる少女を見た" | juman クロール くろーる クロール 名詞 6 普通名詞 1 * 0 * 0 "代表表記:クロール/くろーる カテゴリ:抽象物 ドメイン:スポーツ" で で で 助詞 9 格助詞 1 * 0 * 0 NIL 泳いで およいで 泳ぐ 動詞 2 * 0 子音動詞ガ行 4 タ系連用テ形 14 "代表表記:泳ぐ/およぐ" いる いる いる 接尾辞 14 動詞性接尾辞 7 母音動詞 1 基本形 2 "代表表記:いる/いる" 少女 しょうじょ 少女 名詞 6 普通名詞 1 * 0 * 0 "代表表記:少女/しょうじょ カテゴリ:人" を を を 助詞 9 格助詞 1 * 0 * 0 NIL 見た みた 見る 動詞 2 * 0 母音動詞 1 タ形 10 "代表表記:見る/みる 補文ト 自他動詞:自:見える/みえる" EOS $ tar xjf knp-4.15.tar.bz2 $ cd knp-4.15 $ ./configure --prefix=/usr/local --with-juman-prefix=/usr/local/ $ make $ sudo make install $ echo "クロールで泳いでいる少女を見た" | juman | knp # S-ID:1 KNP:4.15-CF1.1 DATE:2015/11/26 SCORE:-19.12316 クロールで──┐ 泳いでいる──┐ 少女を──┐ 見た EOS
CaboChaのモデルをKNBコーパスから作る
CaboChaの学習/評価手順の確認。今回は手軽につかえるKNBコーパスを使ってチャンキングと係り受けモデルを作成する。
4ジャンルに分かれているので、単純に1つを評価用、残りの3つを学習用として作業する。
入力フォーマットは、CaboCha形式に変換する必要があるが、後述のJ.DepP付属のスクリプトがほぼそのまま使えるのでそちらを調整(ヘッダを消しただけ)して使わせてもらう。
評価用のスクリプト(eval.py)とかもJ.DepP付属のものを使用している。
最後に、各ジャンルの評価結果を↓でガッちゃんこしただけ
以下、コーパスの作成からモデルの作成、テスト、評価までの作業メモ
# KNBコーパスの変換 $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Keitai*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2cabocha.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc1.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Kyoto*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2cabocha.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc2.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Gourmet*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2cabocha.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc3.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Sports*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2cabocha.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc4.euc $ for i in `seq 1 1 4`; > do > iconv -f EUC-JP -t UTF-8 knbc$i.euc > knbc$i.utf8; > done # 学習用と評価用に分ける $ cat knbc2.utf8 knbc3.utf8 knbc4.utf8> corpus1 $ cat knbc1.utf8 > gold1 $ cat knbc3.utf8 knbc4.utf8 knbc1.utf8> corpus2 $ cat knbc2.utf8 > gold2 $ cat knbc4.utf8 knbc1.utf8 knbc2.utf8> corpus3 $ cat knbc3.utf8 > gold3 $ cat knbc1.utf8 knbc2.utf8 knbc3.utf8> corpus4 $ cat knbc4.utf8 > gold4 # 文節と係り受けを学習させてそのまま評価 $ for i in `seq 1 1 4`; > do > /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN -t utf-8 corpus$i chunk$i.model; > /usr/local/libexec/cabocha/cabocha-learn -e dep -P JUMAN -t utf-8 corpus$i dep$i.model > cat gold$i | python ../tools/to_sent.py | mecab -d /usr/local/lib/mecab/dic/jumandic | cabocha -m dep$i.model -M chunk$i.model -P JUMAN -I1 -f1 > result$i > done $ for i in `seq 1 1 4`; > do > python ../tools/eval.py result$i gold$i 2> eval$i; > done # 評価結果をガッちゃんこ $ cat eval[1-4] | python ../tools/eval_all.py chunk: precision: 0.8221 (22713/27628) recall: 0.8189 (22713/27737) f1: 0.8205 sent acc.: 0.4853 (2031/4185) depnd: precision: 0.6288 (14742/23443) recall: 0.6259 (14742/23552) f1: 0.6274 sent acc.: 0.3642 (1524/4185)
あんまりよくない気が、、、そもそもMeCabを学習させてないからこんなもんか??
J.DepPのモデルをKNBコーパスから作る
同じことをJ.DepPでもやってみる。
$ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Keitai*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2kyoto.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc1.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Kyoto*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2kyoto.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc2.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Gourmet*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2kyoto.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc3.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Sports*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2kyoto.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc4.euc $ for i in `seq 1 1 4`; > do > iconv -f EUC-JP -t UTF-8 knbc$i.euc > knbc$i.utf8; > done $ cat knbc2.utf8 knbc3.utf8 knbc4.utf8> corpus1 $ cat knbc1.utf8 > gold1 $ cat knbc3.utf8 knbc4.utf8 knbc1.utf8> corpus2 $ cat knbc2.utf8 > gold2 $ cat knbc4.utf8 knbc1.utf8 knbc2.utf8> corpus3 $ cat knbc3.utf8 > gold3 $ cat knbc1.utf8 knbc2.utf8 knbc3.utf8> corpus4 $ cat knbc4.utf8 > gold4 $ for i in `seq 1 1 4`; > do > mkdir -p model/knbc$i && rm -rf model/knbc$i/* > jdepp -t 0 -I 1 -c corpus$i -m model/knbc$i -- -t 1 -d 2 -c 0.0008 -i 40 -p > jdepp -t 3 -I 1 -c corpus$i -m model/knbc$i -- -t 1 -d 2 -c 0.0008 -i 40 -p -- -s 0.02 -i 5 -t 1; > jdepp -t 0 -I 2 -c corpus$i -m model/knbc$i -- -t 1 -d 2 -c 0.00005 -i 40 -p > jdepp -t 3 -I 2 -c corpus$i -m model/knbc$i -- -t 1 -d 2 -c 0.00005 -i 40 -p -- -- -s 0.005 -i 5 -t 1; > cat gold$i | python ../tools/to_sent.py | mecab -d /usr/local/lib/mecab/dic/jumandic | jdepp -m model/knbc$i > result$i > done $ for i in `seq 1 1 4`; > do > python ../tools/eval.py result$i gold$i 2> eval$i; > done $ cat eval[1-4] | python ../tools/eval_all.py chunk: precision: 0.9304 (25918/27856) recall: 0.9344 (25918/27737) f1: 0.9324 sent acc.: 0.7510 (3143/4185) depnd: precision: 0.7843 (18564/23671) recall: 0.7882 (18564/23552) f1: 0.7862 sent acc.: 0.4937 (2066/4185)
これを見るとやはりCaboChaの結果が怪しい、、、なにかやらかしてる感じか:-)
念のため、J.DepPをCaboChaと同じSVMで学習させたらどうなるか見てみる。
#そして、ちゃんと計測してないけどJ.DepPの学習明らかに速いな。学習/解析速度ももう少しデータ用意して比べてみたい。
TinySVMをインストール。
$ brew install tinysvm
以下、学習部分のみ。
SVM(-l 1)を使うときのオプションがよくわかってないが、とりあえずモデルディレクトリにSVMLight形式の学習データができてたからTinySVMにそいつを学習させた。結構時間がかかる。。。
: [省略] : $ for i in `seq 1 1 4`; > do > mkdir -p model/knbc$i && rm -rf model/knbc$i/* > jdepp -t 0 -I 1 -c corpus$i -m model/knbc$i -- -t 0 > svm_learn -t 1 -d 2 -c 1 model/knbc$i/chunk.train model/knbc$i/chunk > jdepp -t 3 -I 1 -c corpus$i -m model/knbc$i -- -t 0 -- -s 0.02 -i 5 -t 1; > jdepp -t 0 -I 2 -c corpus$i -m model/knbc$i -- -t 0 > svm_learn -t 1 -d 2 -c 1 model/knbc$i/depnd.p0.train model/knbc$i/depnd.p0 > jdepp -t 3 -I 2 -c corpus$i -m model/knbc$i -- -t 0 -- -- -s 0.005 -i 5 -t 1; > cat gold$i | python ../tools/to_sent.py | mecab -d /usr/local/lib/mecab/dic/jumandic | jdepp -m model/knbc$i > result$i > done $ for i in `seq 1 1 4`; > do > python ../tools/eval.py result$i gold$i 2> eval$i; > done $ cat eval[1-4] | python ../tools/eval_all.py chunk: precision: 0.9308 (25893/27818) recall: 0.9335 (25893/27737) f1: 0.9322 sent acc.: 0.7513 (3144/4185) depnd: precision: 0.7809 (18455/23633) recall: 0.7836 (18455/23552) f1: 0.7822 sent acc.: 0.4875 (2040/4185)
やはり、こっちはそれっぽい精度がでてる。。。にゃぜだ
ん〜、気になって眠れないけど眠いのでねる。
つづく(かも)
Python requests SSLError: EOF occurred in violation of protocol
とあるs付きのAPIにリクエストを投げた時に発生したエラー_φ(・_・
- python 2.7.10
- opelssl 1.0.1e
- requests 2.8.1
In [21]: r = requests.get(url) --------------------------------------------------------------------------- SSLError Traceback (most recent call last) <ipython-input-21-0aec23ab0de0> in <module>() ----> 1 r = requests.get(url) /root/.pyenv/versions/2.7.10/envs/pydata_env_2.7.10/lib/python2.7/site-packages/requests/api.pyc in get(url, params, **kwargs) 67 68 kwargs.setdefault('allow_redirects', True) ---> 69 return request('get', url, params=params, **kwargs) 70 71 /root/.pyenv/versions/2.7.10/envs/pydata_env_2.7.10/lib/python2.7/site-packages/requests/api.pyc in request(method, url, **kwargs) 48 49 session = sessions.Session() ---> 50 response = session.request(method=method, url=url, **kwargs) 51 # By explicitly closing the session, we avoid leaving sockets open which 52 # can trigger a ResourceWarning in some cases, and look like a memory leak /root/.pyenv/versions/2.7.10/envs/pydata_env_2.7.10/lib/python2.7/site-packages/requests/sessions.pyc in request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json) 466 } 467 send_kwargs.update(settings) --> 468 resp = self.send(prep, **send_kwargs) 469 470 return resp /root/.pyenv/versions/2.7.10/envs/pydata_env_2.7.10/lib/python2.7/site-packages/requests/sessions.pyc in send(self, request, **kwargs) 574 575 # Send the request --> 576 r = adapter.send(request, **kwargs) 577 578 # Total elapsed time of the request (approximately) /root/.pyenv/versions/2.7.10/envs/pydata_env_2.7.10/lib/python2.7/site-packages/requests/adapters.pyc in send(self, request, stream, timeout, verify, cert, proxies) 431 except (_SSLError, _HTTPError) as e: 432 if isinstance(e, _SSLError): --> 433 raise SSLError(e, request=request) 434 elif isinstance(e, ReadTimeoutError): 435 raise ReadTimeout(e, request=request) SSLError: EOF occurred in violation of protocol (_ssl.c:590)
使われるSSLのバージョンの問題らしい。
requestsで使われるのは基底となるurllib3の実装によるようなので、特定のバージョンを使いたい場合は、下記のようにHTTPAdapterのサブクラスを作って、ssl_versionを明示するようにするとのこと。
今回は、ssl_version=ssl.PROTOCOL_TLSv1 とすることでうまくいった。
In [28]: from requests.adapters import HTTPAdapter In [29]: from requests.packages.urllib3.poolmanager import PoolManager In [30]: import ssl In [31]: class MyAdapter(HTTPAdapter): ....: def init_poolmanager(self, connections, maxsize, block=False): ....: self.poolmanager = PoolManager(num_pools=connections, ....: maxsize=maxsize, ....: block=block, ....: ssl_version=ssl.PROTOCOL_TLSv1) ....: In [32]: import requests In [33]: s = requests.Session() In [34]: s.mount('https://', MyAdapter()) In [35]: r = s.get(url)
参考
Curl, Python, PHP で HTTPS 接続する際固まるサイトがあるので、TLS1.2 を使わないようにする | ytyng.com
Choosing The SSL Version In Python Requests • Lukasa's Echochamber
Advanced Usage — Requests 2.8.1 documentation
openssl - Python Requests requests.exceptions.SSLError: [Errno 8] _ssl.c:504: EOF occurred in violation of protocol - Stack Overflow
OpenSSL 1.0.1c and TLSv1 Handshake Failures · Issue #1083 · kennethreitz/requests · GitHub
MeCabのドメイン適応(再学習)
MeCabのドメイン適応(再学習)すぐ忘れるので、他にも記事たくさんあるけど、なんとなく備忘メモ(手順だけ)。
MeCab: オリジナル辞書/コーパスからのパラメータ推定
まず、MeCabがGoogle Project Hostingから消えてた。。。今はGooglドライブからもろもろダウンロード可能。
https://drive.google.com/folderview?id=0B4y35FiV1wh7fjQ5SkJETEJEYzlqcUY4WUlpZmR4dDlJMWI5ZUlXN2xZN2s2b0pqT3hMbTQ&usp=drive_web#list
準備するもの
- MeCab本体:mecab-0.996.tar.gz
- 辞書(IPA):mecab-ipadic-2.7.0-20070801.tar.gz
- パラメータ推定モデル(IPA):mecab-ipadic-2.7.0-20070801.model.bz2
本体とIPA辞書は、下記の通りインストール済み
$ curl -O https://mecab.googlecode.com/files/mecab-0.996.tar.gz $ tar xzf mecab-0.996.tar.gz $ cd mecab-0.996 $ ./configure $ make $ make check $ sudo make install $ curl -O https://mecab.googlecode.com/files/mecab-ipadic-2.7.0-20070801.tar.gz $ tar xzf mecab-ipadic-2.7.0-20070801.tar.gz $ cd mecab-ipadic-2.7.0-20070801 $ ./configure --with-charset=utf8 $ make $ sudo make install
サンプル文(形態素解析の誤り例)
以下の2文のうち、とりあえず明らかに誤りとわかる「外国人参政権」と「学校へ行こう!」を単語の追加とモデルの再学習で直してみます。
$ echo "外国人参政権は世界的には一般的でないものの、欧州地域など一定の制約下で認められているケースもある。" | mecab 外国 名詞,一般,*,*,*,*,外国,ガイコク,ガイコク 人参 名詞,一般,*,*,*,*,人参,ニンジン,ニンジン 政権 名詞,一般,*,*,*,*,政権,セイケン,セイケン は 助詞,係助詞,*,*,*,*,は,ハ,ワ 世界 名詞,一般,*,*,*,*,世界,セカイ,セカイ 的 名詞,接尾,形容動詞語幹,*,*,*,的,テキ,テキ に 助詞,格助詞,一般,*,*,*,に,ニ,ニ は 助詞,係助詞,*,*,*,*,は,ハ,ワ 一般 名詞,一般,*,*,*,*,一般,イッパン,イッパン 的 名詞,接尾,形容動詞語幹,*,*,*,的,テキ,テキ で 助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ ない 助動詞,*,*,*,特殊・ナイ,基本形,ない,ナイ,ナイ ものの 助詞,接続助詞,*,*,*,*,ものの,モノノ,モノノ 、 記号,読点,*,*,*,*,、,、,、 欧州 名詞,固有名詞,地域,一般,*,*,欧州,オウシュウ,オーシュー 地域 名詞,一般,*,*,*,*,地域,チイキ,チイキ など 助詞,副助詞,*,*,*,*,など,ナド,ナド 一定 名詞,サ変接続,*,*,*,*,一定,イッテイ,イッテイ の 助詞,連体化,*,*,*,*,の,ノ,ノ 制約 名詞,サ変接続,*,*,*,*,制約,セイヤク,セイヤク 下 名詞,接尾,一般,*,*,*,下,カ,カ で 助詞,格助詞,一般,*,*,*,で,デ,デ 認め 動詞,自立,*,*,一段,未然形,認める,ミトメ,ミトメ られ 動詞,接尾,*,*,一段,連用形,られる,ラレ,ラレ て 助詞,接続助詞,*,*,*,*,て,テ,テ いる 動詞,非自立,*,*,一段,基本形,いる,イル,イル ケース 名詞,一般,*,*,*,*,ケース,ケース,ケース も 助詞,係助詞,*,*,*,*,も,モ,モ ある 動詞,自立,*,*,五段・ラ行,基本形,ある,アル,アル 。 記号,句点,*,*,*,*,。,。,。 EOS $ echo "TBSの伝説の番組『学校へ行こう!』が、この秋、一夜限り復活することが決まった。" | mecab TBS 名詞,固有名詞,組織,*,*,*,* の 助詞,連体化,*,*,*,*,の,ノ,ノ 伝説 名詞,一般,*,*,*,*,伝説,デンセツ,デンセツ の 助詞,連体化,*,*,*,*,の,ノ,ノ 番組 名詞,一般,*,*,*,*,番組,バングミ,バングミ 『 記号,括弧開,*,*,*,*,『,『,『 学校 名詞,一般,*,*,*,*,学校,ガッコウ,ガッコー へ 助詞,格助詞,一般,*,*,*,へ,ヘ,エ 行こ 動詞,自立,*,*,五段・カ行促音便,未然ウ接続,行く,イコ,イコ う 助動詞,*,*,*,不変化型,基本形,う,ウ,ウ ! 記号,一般,*,*,*,*,!,!,! 』 記号,括弧閉,*,*,*,*,』,』,』 が 助詞,格助詞,一般,*,*,*,が,ガ,ガ 、 記号,読点,*,*,*,*,、,、,、 この 連体詞,*,*,*,*,*,この,コノ,コノ 秋 名詞,一般,*,*,*,*,秋,アキ,アキ 、 記号,読点,*,*,*,*,、,、,、 一夜 名詞,副詞可能,*,*,*,*,一夜,イチヤ,イチヤ 限り 名詞,非自立,副詞可能,*,*,*,限り,カギリ,カギリ 復活 名詞,サ変接続,*,*,*,*,復活,フッカツ,フッカツ する 動詞,自立,*,*,サ変・スル,基本形,する,スル,スル こと 名詞,非自立,一般,*,*,*,こと,コト,コト が 助詞,格助詞,一般,*,*,*,が,ガ,ガ 決まっ 動詞,自立,*,*,五段・ラ行,連用タ接続,決まる,キマッ,キマッ た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ 。 記号,句点,*,*,*,*,。,。,。 EOS
辞書とモデルの下準備
辞書、モデルともに文字コードがEUC-JPなのでUTF-8に変換します。
$ tar xzf mecab-ipadic-2.7.0-20070801.tar.gz $ nkf --overwrite -Ew mecab-ipadic-2.7.0-20070801/* $ bzip2 -d mecab-ipadic-2.7.0-20070801.model.bz2 $ nkf --overwrite -Ew mecab-ipadic-2.7.0-20070801.model
設定ファイルとモデルファイルのcharsetの記述があるのでutf-8に変更しておきます。
mecab-ipadic-2.7.0-20070801/dicrc
: config-charset = UTF-8 : ; yomi
mecab-ipadic-2.7.0-20070801.model
: charset: utf-8 -0.0001744043301648 B00:BOS/EOS/その他 :
追加する単語のコスト推定をさせるために、バイナリ辞書を作成しておきます。(インストールしちゃう場合は、sudo make install もする)
$ cd mecab-ipadic-2.7.0-20070801 $ /usr/local/libexec/mecab/mecab-dict-index -f utf-8 -t utf-8
追加する単語をCSVで用意
追加する単語をCSVで用意します。
$ cat seed_with_empty_cost.csv 外国人参政権,,,,名詞,一般,*,*,*,*,外国人参政権,ガイコクジンサンセイケン,ガイコクジンサンセイケン 学校へ行こう!,,,,名詞,一般,*,*,*,*,学校へ行こう!,ガッコウヘイコウ,ガッコーエイコー
並びは、
表層形,左文脈ID,右文脈ID,コスト,品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音
のようになってます。
#活用がある語は、活用を一行ずつ展開する必要あり。
今回は、始め試しに左文脈ID、右文脈ID、コストをオリジナルモデルに推定させてみるので空にしておきます。通常の再学習では「0,0,0」で問題無し。
コストの自動推定
オリジナルのモデルを使って、作成した追加単語CSVのコストを推定してもらいます。
$ /usr/local/libexec/mecab/mecab-dict-index -m mecab-ipadic-2.7.0-20070801.model -d mecab-ipadic-2.7.0-20070801 -f utf-8 -t utf-8 -a seed_with_empty_cost.csv -u seed.csv $ cat seed.csv 外国人参政権,1285,1285,5078,名詞,一般,*,*,*,*,外国人参政権,ガイコクジンサンセイケン,ガイコクジンサンセイケン 学校へ行こう!,1285,1285,5078,名詞,一般,*,*,*,*,学校へ行こう!,ガッコウヘイコウ,ガッコーエイコー
バイナリ辞書の再構築
コスト推定された追加単語のCSVを含めて、バイナリ辞書を再構築します。
$ cp seed.csv mecab-ipadic-2.7.0-20070801 $ cd mecab-ipadic-2.7.0-20070801 $ /usr/local/libexec/mecab/mecab-dict-index -f utf-8 -t utf-8
ここまでで、再テスト
単語が追加されたバイナリ辞書で、サンプル文を解析してみます。
$ echo "外国人参政権は世界的には一般的でないものの、欧州地域など一定の制約下で認められているケースもある。" | mecab -d . 外国人参政権 名詞,一般,*,*,*,*,外国人参政権,ガイコクジンサンセイケン,ガイコクジンサンセイケン は 助詞,係助詞,*,*,*,*,は,ハ,ワ 世界 名詞,一般,*,*,*,*,世界,セカイ,セカイ 的 名詞,接尾,形容動詞語幹,*,*,*,的,テキ,テキ に 助詞,格助詞,一般,*,*,*,に,ニ,ニ は 助詞,係助詞,*,*,*,*,は,ハ,ワ 一般 名詞,一般,*,*,*,*,一般,イッパン,イッパン 的 名詞,接尾,形容動詞語幹,*,*,*,的,テキ,テキ で 助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ ない 助動詞,*,*,*,特殊・ナイ,基本形,ない,ナイ,ナイ ものの 助詞,接続助詞,*,*,*,*,ものの,モノノ,モノノ 、 記号,読点,*,*,*,*,、,、,、 欧州 名詞,固有名詞,地域,一般,*,*,欧州,オウシュウ,オーシュー 地域 名詞,一般,*,*,*,*,地域,チイキ,チイキ など 助詞,副助詞,*,*,*,*,など,ナド,ナド 一定 名詞,サ変接続,*,*,*,*,一定,イッテイ,イッテイ の 助詞,連体化,*,*,*,*,の,ノ,ノ 制約 名詞,サ変接続,*,*,*,*,制約,セイヤク,セイヤク 下 名詞,接尾,一般,*,*,*,下,カ,カ で 助詞,格助詞,一般,*,*,*,で,デ,デ 認め 動詞,自立,*,*,一段,未然形,認める,ミトメ,ミトメ られ 動詞,接尾,*,*,一段,連用形,られる,ラレ,ラレ て 助詞,接続助詞,*,*,*,*,て,テ,テ いる 動詞,非自立,*,*,一段,基本形,いる,イル,イル ケース 名詞,一般,*,*,*,*,ケース,ケース,ケース も 助詞,係助詞,*,*,*,*,も,モ,モ ある 動詞,自立,*,*,五段・ラ行,基本形,ある,アル,アル 。 記号,句点,*,*,*,*,。,。,。 EOS $ echo "TBSの伝説の番組『学校へ行こう!』が、この秋、一夜限り復活することが決まった。" | mecab -d . TBS 名詞,固有名詞,組織,*,*,*,* の 助詞,連体化,*,*,*,*,の,ノ,ノ 伝説 名詞,一般,*,*,*,*,伝説,デンセツ,デンセツ の 助詞,連体化,*,*,*,*,の,ノ,ノ 番組 名詞,一般,*,*,*,*,番組,バングミ,バングミ 『 記号,括弧開,*,*,*,*,『,『,『 学校 名詞,一般,*,*,*,*,学校,ガッコウ,ガッコー へ 助詞,格助詞,一般,*,*,*,へ,ヘ,エ 行こ 動詞,自立,*,*,五段・カ行促音便,未然ウ接続,行く,イコ,イコ う 助動詞,*,*,*,不変化型,基本形,う,ウ,ウ ! 記号,一般,*,*,*,*,!,!,! 』 記号,括弧閉,*,*,*,*,』,』,』 が 助詞,格助詞,一般,*,*,*,が,ガ,ガ 、 記号,読点,*,*,*,*,、,、,、 この 連体詞,*,*,*,*,*,この,コノ,コノ 秋 名詞,一般,*,*,*,*,秋,アキ,アキ 、 記号,読点,*,*,*,*,、,、,、 一夜 名詞,副詞可能,*,*,*,*,一夜,イチヤ,イチヤ 限り 名詞,非自立,副詞可能,*,*,*,限り,カギリ,カギリ 復活 名詞,サ変接続,*,*,*,*,復活,フッカツ,フッカツ する 動詞,自立,*,*,サ変・スル,基本形,する,スル,スル こと 名詞,非自立,一般,*,*,*,こと,コト,コト が 助詞,格助詞,一般,*,*,*,が,ガ,ガ 決まっ 動詞,自立,*,*,五段・ラ行,連用タ接続,決まる,キマッ,キマッ た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ 。 記号,句点,*,*,*,*,。,。,。 EOS
再学習用コーパスの準備
モデルを再学習させるために、コーパス(正しい解析結果)を用意します。フォーマットは、MeCabのデフォルトの出力と同じです。
$ cat corpus TBS 名詞,固有名詞,組織,*,*,*,* の 助詞,連体化,*,*,*,*,の,ノ,ノ 伝説 名詞,一般,*,*,*,*,伝説,デンセツ,デンセツ の 助詞,連体化,*,*,*,*,の,ノ,ノ 番組 名詞,一般,*,*,*,*,番組,バングミ,バングミ 『 記号,括弧開,*,*,*,*,『,『,『 学校へ行こう! 名詞,一般,*,*,*,*,学校へ行こう!,ガッコウヘイコウ,ガッコーエイコー 』 記号,括弧閉,*,*,*,*,』,』,』 が 助詞,格助詞,一般,*,*,*,が,ガ,ガ 、 記号,読点,*,*,*,*,、,、,、 この 連体詞,*,*,*,*,*,この,コノ,コノ 秋 名詞,一般,*,*,*,*,秋,アキ,アキ 、 記号,読点,*,*,*,*,、,、,、 一夜 名詞,副詞可能,*,*,*,*,一夜,イチヤ,イチヤ 限り 名詞,非自立,副詞可能,*,*,*,限り,カギリ,カギリ 復活 名詞,サ変接続,*,*,*,*,復活,フッカツ,フッカツ する 動詞,自立,*,*,サ変・スル,基本形,する,スル,スル こと 名詞,非自立,一般,*,*,*,こと,コト,コト が 助詞,格助詞,一般,*,*,*,が,ガ,ガ 決まっ 動詞,自立,*,*,五段・ラ行,連用タ接続,決まる,キマッ,キマッ た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ 。 記号,句点,*,*,*,*,。,。,。 EOS
モデル(CRF パラメータ)の再学習
コーパスを使って、モデルを更新します。
$ /usr/local/libexec/mecab/mecab-cost-train -d mecab-ipadic-2.7.0-20070801 -M mecab-ipadic-2.7.0-20070801.model -c 1.0 corpus mecab-ipadic-2.7.0-20070801_custom.model
配布用辞書の作成
更新したモデルで配布用辞書を作成します。-o で元の辞書とは別の辞書として出力しています。
$ mkdir mecab-ipadic-2.7.0-20070801_custom $ /usr/local/libexec/mecab/mecab-dict-gen -d mecab-ipadic-2.7.0-20070801 -o mecab-ipadic-2.7.0-20070801_custom -m mecab-ipadic-2.7.0-20070801_custom.model
コストが変わりました。
$ cat mecab-ipadic-2.7.0-20070801_custom/seed.csv 外国人参政権,1135,1135,5176,名詞,一般,*,*,*,*,外国人参政権,ガイコクジンサンセイケン,ガイコクジンサンセイケン 学校へ行こう!,1135,1135,5087,名詞,一般,*,*,*,*,学校へ行こう!,ガッコウヘイコウ,ガッコーエイコー
バイナリ辞書の再構築
この状態で、もう一回辞書を再構築すれば出来上がり。
$ cd mecab-ipadic-2.7.0-20070801_custom $ /usr/local/libexec/mecab/mecab-dict-index -f utf-8 -t utf-8
もっかい、テスト
ビルドした辞書で『学校へ行こう!』を再テストしてみます。
$ echo "TBSの伝説の番組『学校へ行こう!』が、この秋、一夜限り復活することが決まった。" | mecab -d . TBS 名詞,固有名詞,組織,*,*,*,* の 助詞,連体化,*,*,*,*,の,ノ,ノ 伝説 名詞,一般,*,*,*,*,伝説,デンセツ,デンセツ の 助詞,連体化,*,*,*,*,の,ノ,ノ 番組 名詞,一般,*,*,*,*,番組,バングミ,バングミ 『 記号,括弧開,*,*,*,*,『,『,『 学校へ行こう! 名詞,一般,*,*,*,*,学校へ行こう!,ガッコウヘイコウ,ガッコーエイコー 』 記号,括弧閉,*,*,*,*,』,』,』 が 助詞,格助詞,一般,*,*,*,が,ガ,ガ 、 記号,読点,*,*,*,*,、,、,、 この 連体詞,*,*,*,*,*,この,コノ,コノ 秋 名詞,一般,*,*,*,*,秋,アキ,アキ 、 記号,読点,*,*,*,*,、,、,、 一夜 名詞,副詞可能,*,*,*,*,一夜,イチヤ,イチヤ 限り 名詞,非自立,副詞可能,*,*,*,限り,カギリ,カギリ 復活 名詞,サ変接続,*,*,*,*,復活,フッカツ,フッカツ する 動詞,自立,*,*,サ変・スル,基本形,する,スル,スル こと 名詞,非自立,一般,*,*,*,こと,コト,コト が 助詞,格助詞,一般,*,*,*,が,ガ,ガ 決まっ 動詞,自立,*,*,五段・ラ行,連用タ接続,決まる,キマッ,キマッ た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ 。 記号,句点,*,*,*,*,。,。,。 EOS $ echo "昨日の『学校へ行こう!』は、面白かった。" | mecab -d . 昨日 名詞,副詞可能,*,*,*,*,昨日,キノウ,キノー の 助詞,連体化,*,*,*,*,の,ノ,ノ 『 記号,括弧開,*,*,*,*,『,『,『 学校へ行こう! 名詞,一般,*,*,*,*,学校へ行こう!,ガッコウヘイコウ,ガッコーエイコー 』 記号,括弧閉,*,*,*,*,』,』,』 は 助詞,係助詞,*,*,*,*,は,ハ,ワ 、 記号,読点,*,*,*,*,、,、,、 面白かっ 形容詞,自立,*,*,形容詞・アウオ段,連用タ接続,面白い,オモシロカッ,オモシロカッ た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ 。 記号,句点,*,*,*,*,。,。,。 EOS $ echo "昨日の「学校へ行こう!」は、面白かった。" | mecab -d . 昨日 名詞,副詞可能,*,*,*,*,昨日,キノウ,キノー の 助詞,連体化,*,*,*,*,の,ノ,ノ 「 記号,括弧開,*,*,*,*,「,「,「 学校へ行こう! 名詞,一般,*,*,*,*,学校へ行こう!,ガッコウヘイコウ,ガッコーエイコー 」 記号,括弧閉,*,*,*,*,」,」,」 は 助詞,係助詞,*,*,*,*,は,ハ,ワ 、 記号,読点,*,*,*,*,、,、,、 面白かっ 形容詞,自立,*,*,形容詞・アウオ段,連用タ接続,面白い,オモシロカッ,オモシロカッ た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ 。 記号,句点,*,*,*,*,。,。,。 EOS $ echo "昨日の学校へ行こう!は、面白かった。" | mecab -d . 昨日 名詞,副詞可能,*,*,*,*,昨日,キノウ,キノー の 助詞,連体化,*,*,*,*,の,ノ,ノ 学校へ行こう! 名詞,一般,*,*,*,*,学校へ行こう!,ガッコウヘイコウ,ガッコーエイコー は 助詞,係助詞,*,*,*,*,は,ハ,ワ 、 記号,読点,*,*,*,*,、,、,、 面白かっ 形容詞,自立,*,*,形容詞・アウオ段,連用タ接続,面白い,オモシロカッ,オモシロカッ た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ 。 記号,句点,*,*,*,*,。,。,。 EOS $ echo "明日こそ、学校へ行こう!" | mecab -d . 明日 名詞,副詞可能,*,*,*,*,明日,アシタ,アシタ こそ 助詞,係助詞,*,*,*,*,こそ,コソ,コソ 、 記号,読点,*,*,*,*,、,、,、 学校 名詞,一般,*,*,*,*,学校,ガッコウ,ガッコー へ 助詞,格助詞,一般,*,*,*,へ,ヘ,エ 行こ 動詞,自立,*,*,五段・カ行促音便,未然ウ接続,行く,イコ,イコ う 助動詞,*,*,*,不変化型,基本形,う,ウ,ウ ! 記号,一般,*,*,*,*,!,!,! EOS $ echo "明日こそ、学校へ行こう!を見よう!" | mecab -d . 明日 名詞,副詞可能,*,*,*,*,明日,アシタ,アシタ こそ 助詞,係助詞,*,*,*,*,こそ,コソ,コソ 、 記号,読点,*,*,*,*,、,、,、 学校へ行こう! 名詞,一般,*,*,*,*,学校へ行こう!,ガッコウヘイコウ,ガッコーエイコー を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ 見よ 動詞,自立,*,*,一段,未然ウ接続,見る,ミヨ,ミヨ う 助動詞,*,*,*,不変化型,基本形,う,ウ,ウ ! 記号,一般,*,*,*,*,!,!,! EOS
1サンプル学習させただけだけど、そこそこ正しく形態素として認識するようになってる気がする。
おしまい
とりあえず、手順だけ。
設定ファイルの細かいところとか、実務的なところに踏み込んだ内容は、もう少し勉強しないとダメだ。。。
#そして「学校へ行こう!」は、固有名詞だった。。。めんどいからそのまま
ApacheアクセスログをElasticsearchへ流す
Elasticsearchはdockerコンテナで用意、Apache側は落ちてたwordpressのコンテナにtd-agentをインストールしてテスト
- td-agent 0.12.12
- Elasticsearch 1.7.1
td-agent のインストール
curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh
標準出力で確認
apache2のテンプレート↓がデフォルトで用意されているのでそのまま使う
format /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$/ time_format %d/%b/%Y:%H:%M:%S %z
/etc/td-agent/td-agent.conf
<source> type tail format apache2 path /var/log/apache2/access.log pos_file /var/log/td-agent/apache_access.pos tag apache.access </source> <match *.**> type copy <store> type stdout </store> </match>
td-agent を起動
/etc/init.d/td-agent start
dockerコンテナの上なんでもrootで動かしてるせいでログが読めない。。。
2015-10-04 17:16:11 +0000 [error]: Permission denied @ rb_sysopen - /var/log/apache2/access.log 2015-10-04 17:16:11 +0000 [error]: suppressed same stacktrace
適当対応
/etc/init.d/td-agent
: TD_AGENT_USER=root TD_AGENT_GROUP=root :
こんなん出た
2015-10-06 22:25:17 +0900 raw.apache.access: {"host":"192.168.1.1","user":null,"method":"POST","path":"/wp-admin/admin-ajax.php","code":200,"size":580,"referer":"http://192.168.1.10/wp-admin/index.php","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"} 2015-10-06 22:25:35 +0900 raw.apache.access: {"host":"192.168.1.1","user":null,"method":"GET","path":"/wp-admin/index.php","code":200,"size":14048,"referer":"http://192.168.1.10/wp-admin/index.php","agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3"} 2015-10-06 22:25:55 +0900 raw.apache.access: {"host":"192.168.1.1","user":null,"method":"GET","path":"/wp-admin/index.php","code":200,"size":14046,"referer":"http://192.168.1.10/wp-admin/index.php","agent":"Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3"}
UAを解析したい
tagomoris/fluent-plugin-woothee · GitHub
# td-agent-gem install fluent-plugin-woothee WARN: Unresolved specs during Gem::Specification.reset: json (>= 1.4.3) WARN: Clearing out unresolved specs. Please report a bug if this causes problems. ERROR: While executing gem ... (Gem::RemoteFetcher::FetchError) Errno::ECONNREFUSED: Connection refused - connect(2) for "your-dns-needs-immediate-attention.dev" port 443 (https://your-dns-needs-immediate-attention.dev/quick/Marshal.4.8/woothee-1.2.0.gemspec.rz)
変なエラーでた、コンテナをdevドメインにしてあるせいらしい
your-dns-needs-immediate-attention | Triple-networks
# echo "search home.local" >> /etc/resolv.conf
/etc/td-agent/td-agent.conf
<source> type tail format apache2 path /var/log/apache2/access.log pos_file /var/log/td-agent/apache_access.pos tag raw.apache.access </source> <match raw.**> type woothee key_name agent remove_prefix raw add_prefix parsed merge_agent_info yes out_key_name agent_name out_key_category agent_category out_key_os agent_os out_key_os_version agent_os_version out_key_version agent_version out_key_vendor agent_vendor </match> <match *.**> type copy <store> type stdout </store> </match>
こうなった。
2015-10-06 23:17:10 +0900 parsed.apache.access: {"host":"192.168.1.1","user":null,"method":"GET","path":"/wp-admin/index.php","code":200,"size":14014,"referer":"http://192.168.1.10/wp-admin/plugins.php","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36","agent_name":"Chrome","agent_category":"pc","agent_os":"Mac OSX","agent_os_version":"10.10.5","agent_version":"45.0.2454.101","agent_vendor":"Google"} 2015-10-06 23:18:17 +0900 parsed.apache.access: {"host":"192.168.1.1","user":null,"method":"GET","path":"/wp-admin/index.php","code":200,"size":14051,"referer":"http://192.168.1.10/wp-admin/index.php","agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3","agent_name":"Safari","agent_category":"smartphone","agent_os":"iPhone","agent_os_version":"5.0","agent_version":"5.1","agent_vendor":"Apple"} 2015-10-06 23:19:11 +0900 parsed.apache.access: {"host":"192.168.1.1","user":null,"method":"GET","path":"/wp-admin/index.php","code":200,"size":14049,"referer":"http://192.168.1.10/wp-admin/index.php","agent":"Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30","agent_name":"Safari","agent_category":"smartphone","agent_os":"Android","agent_os_version":"4.0.4","agent_version":"4.0","agent_vendor":"Apple"}
他にも、filter_categories、drop_categories で特定のカテゴリを出力、破棄できる。
クローラリクエストを効率良くざっくり破棄した場合は、'woothee_fast_crawler_filter' を使う、完璧に破棄したい場合は、'woothee' + 'drop_categories crawler'を併せて使う。
geoipも使ってみる
y-ken/fluent-plugin-geoip · GitHub
# apt-get install build-essential # apt-get install libgeoip-dev # td-agent-gem install fluent-plugin-geoip
デフォルトでバンドルされてる無償データベースだと国レベル(緯度経度も)
/etc/td-agent/td-agent.conf
<source> type tail format apache2 path /var/log/apache2/access.log pos_file /var/log/td-agent/apache_access.pos tag raw.apache.access </source> <match raw.**> type woothee key_name agent remove_prefix raw add_prefix ua_parsed merge_agent_info yes out_key_name agent_name out_key_category agent_category out_key_os agent_os out_key_os_version agent_os_version out_key_version agent_version out_key_vendor agent_vendor </match> <match ua_parsed.**> type geoip # Specify one or more geoip lookup field which has ip address (default: host) # in the case of accessing nested value, delimit keys by dot like 'host.ip'. geoip_lookup_key host # Specify optional geoip database (using bundled GeoLiteCity databse by default) #geoip_database "/path/to/your/GeoIPCity.dat" #enable_key_country_code geoip_country # Set adding field with placeholder (more than one settings are required.) <record> #city ${city["host"]} geoip_latitude ${latitude["host"]} geoip_longitude ${longitude["host"]} geoip_country_code3 ${country_code3["host"]} geoip_country ${country_code["host"]} country_name ${country_name["host"]} #dma ${dma_code["host"]} #area ${area_code["host"]} #region ${region["host"]} geoip_location_properties '{ "lat" : ${latitude["host"]}, "lon" : ${longitude["host"]} }' geoip_location_string ${latitude["host"]},${longitude["host"]} geoip_location_array '[${longitude["host"]},${latitude["host"]}]' </record> # Settings for tag remove_tag_prefix ua_parsed. tag parsed.${tag} # To avoid get stacktrace error with `[null, null]` array for elasticsearch. skip_adding_null_record true # Set log_level for fluentd-v0.10.43 or earlier (default: warn) log_level info # Set buffering time (default: 0s) flush_interval 1s </match> <match *.**> type copy <store> type stdout </store> </match>
geoip_locationはどの形式でもO.K. 適当なIPを流して確認
2015-10-07 01:35:08 +0900 geoip.apache.access: {"host":"1.0.0.0","user":null,"method":"POST","path":"/wp-admin/admin-ajax.php","code":200,"size":580,"referer":"http://192.168.1.10/wp-admin/index.php","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36","agent_name":"Chrome","agent_category":"pc","agent_os":"Mac OSX","agent_os_version":"10.10.5","agent_version":"45.0.2454.101","agent_vendor":"Google","geoip_latitude":-27.0,"geoip_longitude":133.0,"geoip_country_code3":"AUS","geoip_country":"AU","country_name":"Australia","geoip_location_properties":{"lat":-27.0,"lon":133.0},"geoip_location_string":"-27.0,133.0","geoip_location_array":[133.0,-27.0]} 2015-10-07 01:36:08 +0900 geoip.apache.access: {"host":"128.0.0.0","user":null,"method":"POST","path":"/wp-admin/admin-ajax.php","code":200,"size":580,"referer":"http://192.168.1.10/wp-admin/index.php","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36","agent_name":"Chrome","agent_category":"pc","agent_os":"Mac OSX","agent_os_version":"10.10.5","agent_version":"45.0.2454.101","agent_vendor":"Google","geoip_latitude":46.0,"geoip_longitude":25.0,"geoip_country_code3":"ROU","geoip_country":"RO","country_name":"Romania","geoip_location_properties":{"lat":46.0,"lon":25.0},"geoip_location_string":"46.0,25.0","geoip_location_array":[25.0,46.0]} 2015-10-07 01:37:08 +0900 geoip.apache.access: {"host":"114.170.237.217","user":null,"method":"POST","path":"/wp-admin/admin-ajax.php","code":200,"size":580,"referer":"http://192.168.1.10/wp-admin/index.php","agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36","agent_name":"Chrome","agent_category":"pc","agent_os":"Mac OSX","agent_os_version":"10.10.5","agent_version":"45.0.2454.101","agent_vendor":"Google","geoip_latitude":35.689998626708984,"geoip_longitude":139.69000244140625,"geoip_country_code3":"JPN","geoip_country":"JP","country_name":"Japan","geoip_location_properties":{"lat":35.689998626708984,"lon":139.69000244140625},"geoip_location_string":"35.689998626708984,139.69000244140625","geoip_location_array":[139.69000244140625,35.689998626708984]}
Elasticsearchへ流す
uken/fluent-plugin-elasticsearch · GitHub
# td-agent-gem install fluent-plugin-elasticsearch
/etc/td-agent/td-agent.conf
: <match parsed.**> type elasticsearch hosts es1.containers.dev:9200,es2.containers.dev:9200 type_name access logstash_format true logstash_prefix apache_log_wordpress logstash_dateformat %Y.%m flush_interval 10s </match>
geoipの緯度経度がそのままだとgeo_pointにマッピングされないので、明示的にタイプをマッピングしておく。
curl -XPUT 'es1.containers.dev:9200/_template/apache_log/?pretty' -d ' { "template": "apache_log*", "mappings": { "access": { "properties": { "geoip_location_properties": { "type": "geo_point" }, "geoip_location_string": { "type": "geo_point" }, "geoip_location_array": { "type": "geo_point" } } } } } '
適当にログを流す、ドキュメントはこんな感じになった
{ "_index": "apache_log_wordpress-2015.10", "_type": "access", "_id": "AVBOD5OpAEC4whOefbLc", "_score": 1, "_source": { "host": "1.0.0.0", "user": null, "method": "POST", "path": "/wp-admin/admin-ajax.php", "code": 200, "size": 580, "referer": "http://192.168.1.10/wp-admin/index.php", "agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36", "agent_name": "Chrome", "agent_category": "pc", "agent_os": "Mac OSX", "agent_os_version": "10.10.5", "agent_version": "45.0.2454.101", "agent_vendor": "Google", "geoip_latitude": -27, "geoip_longitude": 133, "geoip_country_code3": "AUS", "geoip_country": "AU", "country_name": "Australia", "geoip_location_properties": { "lat": -27, "lon": 133 }, "geoip_location_string": "-27.0,133.0", "geoip_location_array": [133, -27], "@timestamp": "2015-10-07T01:35:08+09:00" } }
マッピングも確認
# curl -XGET 'es1.containers.dev:9200/apache_log_wordpress-2015.10/_mapping/?pretty' { "apache_log_wordpress-2015.10" : { "mappings" : { "access" : { "properties" : { "@timestamp" : { "type" : "date", "format" : "dateOptionalTime" }, "agent" : { "type" : "string" }, "agent_category" : { "type" : "string" }, "agent_name" : { "type" : "string" }, "agent_os" : { "type" : "string" }, "agent_os_version" : { "type" : "string" }, "agent_vendor" : { "type" : "string" }, "agent_version" : { "type" : "string" }, "code" : { "type" : "long" }, "country_name" : { "type" : "string" }, "geoip_country" : { "type" : "string" }, "geoip_country_code3" : { "type" : "string" }, "geoip_latitude" : { "type" : "double" }, "geoip_location_array" : { "type" : "geo_point" }, "geoip_location_properties" : { "type" : "geo_point" }, "geoip_location_string" : { "type" : "geo_point" }, "geoip_longitude" : { "type" : "double" }, "host" : { "type" : "string" }, "method" : { "type" : "string" }, "path" : { "type" : "string" }, "referer" : { "type" : "string" }, "size" : { "type" : "long" } } } } } }
ここまで
Kibanaで軽く確認してチャートや地図も問題無し、@timestampもちゃんとログのリクエスト時間になってる。
とりあえず導入としてはこんなもんで。
RDBのデータをELKで集計・可視化する
たまにくる「これの件数教えて」とか「Kibana見て」にしたい
とりあえずとっかかりとして、MySQLからElasticsearchにデータもってって、Aggregationを触ってみる
あたりの備忘録
- Elasticssearch 1.7.1
- Logstash 1.5.4
適当なデータを用意する
特定の場所(バッセンとか)とそのレビューのデータ
- spot: ○スローバッティングセンター とか
- location: 荻窪○スローバッティングセンター とか、locationには、緯度経度が、"lat,lon" 形式(get_pointとしてそのまま扱える形)で入っている
- review: 星3つ とか
mysql> desc spot; +-----------------+-------------+------+-----+---------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+-------------+------+-----+---------------------+-----------------------------+ | sid | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(50) | NO | | NULL | | | regist_datetime | datetime | NO | | 0000-00-00 00:00:00 | | | update_datetime | datetime | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +-----------------+-------------+------+-----+---------------------+-----------------------------+ 4 rows in set (0.00 sec) mysql> desc location; +-----------------+-------------+------+-----+---------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+-------------+------+-----+---------------------+-----------------------------+ | lid | int(11) | NO | PRI | NULL | auto_increment | | sid | int(11) | NO | | NULL | | | pref | varchar(4) | NO | | NULL | | | location | varchar(30) | NO | | NULL | | | regist_datetime | datetime | NO | | 0000-00-00 00:00:00 | | | update_datetime | datetime | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +-----------------+-------------+------+-----+---------------------+-----------------------------+ 6 rows in set (0.01 sec) mysql> desc review; +-----------------+--------------+------+-----+---------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+--------------+------+-----+---------------------+-----------------------------+ | rid | int(11) | NO | PRI | NULL | auto_increment | | lid | int(11) | NO | | NULL | | | nickname | varchar(10) | NO | | NULL | | | rate | decimal(2,1) | NO | | 0.0 | | | regist_datetime | datetime | NO | | 0000-00-00 00:00:00 | | | update_datetime | datetime | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +-----------------+--------------+------+-----+---------------------+-----------------------------+ 6 rows in set (0.00 sec)
マッピング
{ "settings" : { "number_of_shards" : 2, "number_of_replica" : 2, "analysis": { "analyzer": { "custom_bigram": { "tokenizer": "custom_bigram_tokenizer" } }, "tokenizer": { "custom_bigram_tokenizer": { "type": "nGram", "min_gram": "2", "max_gram": "2", "token_chars": [ "letter", "digit" ] } } } }, "mappings" : { "spot" : { "properties" : { "name" : { "type" : "string", "index" : "not_analyzed", "fields": { "bigram": {"type": "string", "index": "analyzed", "analyzer": "custom_bigram" } } }, "pref" : { "type" : "string", "index" : "not_analyzed" }, "location": { "type": "geo_point" }, "regist_datetime" : { "type" : "date" }, "update_datetime" : { "type" : "date" } } }, "review": { "properties" : { "name" : { "type" : "string", "index" : "not_analyzed", "fields": { "bigram": {"type": "string", "index": "analyzed", "analyzer": "custom_bigram" } } }, "pref" : { "type" : "string", "index" : "not_analyzed" }, "lid": { "type": "integer" }, "location": { "type": "geo_point" }, "nickname": { "type": "string" }, "rate": { "type": "float" }, "regist_datetime" : { "type" : "date" } } } } }
MySQL to Elasticsearch
RDBからの入力は、jdbcプラグインがあるので今回はそれを使う。
bin/plugin install logstash-input-jdbc
jdbc_es_pipeline_spot.conf
input { jdbc { jdbc_driver_library => "./mysql-connector-java-5.1.34.jar" jdbc_driver_class => "com.mysql.jdbc.Driver" jdbc_connection_string => "jdbc:mysql://127.0.0.1:3306/elk" jdbc_user => "root" jdbc_password => "" statement => " SELECT l.lid `_id` , s.name , l.pref , l.location , DATE_FORMAT(l.regist_datetime, '%Y-%m-%dT%H:%i:%s.000+0900') `regist_datetime` , DATE_FORMAT(l.update_datetime, '%Y-%m-%dT%H:%i:%s.000+0900') `update_datetime` FROM location l INNER JOIN spot s ON s.sid = l.sid ORDER BY l.lid " } } filter { ruby { code => "localtime = event.timestamp.time.localtime" } } output { elasticsearch { protocol => "http" host => "192.168.1.10" port => "9200" index => "learning_elk" document_type => "spot" document_id => "%{_id}" } }
jdbc_es_pipeline_review.conf
input { jdbc { jdbc_driver_library => "./mysql-connector-java-5.1.34.jar" jdbc_driver_class => "com.mysql.jdbc.Driver" jdbc_connection_string => "jdbc:mysql://127.0.0.1:3306/elk" jdbc_user => "root" jdbc_password => "" statement => " SELECT r.rid `_id` , s.name , l.pref , l.lid , l.location , r.nickname , r.rate , DATE_FORMAT(r.regist_datetime, '%Y-%m-%dT%H:%i:%s.000+0900') `regist_datetime` , DATE_FORMAT(r.update_datetime, '%Y-%m-%dT%H:%i:%s.000+0900') `update_datetime` FROM review r INNER JOIN location l ON l.lid = r.lid INNER JOIN spot s ON s.sid = l.sid ORDER BY r.rid " } } filter { ruby { code => "localtime = event.timestamp.time.localtime" } } output { elasticsearch { protocol => "http" host => "192.168.1.10" port => "9200" index => "learning_elk" document_type => "review" document_id => "%{_id}" } }
なんか冗長だけどそのままそれぞれ実行
bin/logstash -f jdbc_es_pipeline_spot.conf bin/logstash -f jdbc_es_pipeline_review.conf
集計操作
単純カウント
SELECT s.name , l.pref , COUNT(l.sid) `num_spot` FROM location l INNER JOIN spot s ON s.sid = l.sid GROUP BY s.name , l.pref ORDER BY `num_spot` DESC
Aggregation
複数軸は常にネストさせる必要がある?階層的に集約とれるのはいいけど、親いらない時はtermsに2つ書きたい。。。
{ "aggs": { "count_by_name": { "terms": { "field": "name", "order": { "_count" : "desc" } }, "aggs": { "count_by_pref": { "terms": { "field": "pref", "order": { "_count" : "desc" } } } } } } }
ユニーク数カウント
SELECT l.pref , COUNT(DISTINCT s.name) `num_spot_name` FROM location l INNER JOIN spot s ON s.sid = l.sid GROUP BY l.pref ORDER BY `num_spot_name` DESC
Aggregation
{ "aggs": { "count_by_pref": { "terms": { "field": "pref", "order": { "_count" : "desc" } }, "aggs": { "count_unique_name": { "cardinality": { "field": "name" } } } } } }
基本統計量(カウント、最小、最大、平均、合計)
SELECT s.name , l.lid , COUNT(r.rid) `num_rate` , MIN(r.rate) `min_rate` , MAX(r.rate) `max_rate` , AVG(r.rate) `avg_rate` , SUM(r.rate) `total_rate` FROM review r INNER JOIN location l ON l.lid = r.lid INNER JOIN spot s ON s.sid = l.sid GROUP BY s.name , l.lid
Aggregation
{ "aggs": { "group_by_name": { "terms": { "field": "name" }, "aggs": { "stats_rate": { "stats": { "field": "rate" } }, "group_by_location": { "terms": { "field": "lid" }, "aggs": { "stats_rate": { "stats": { "field": "rate" } } } } } } } }
条件付き
SELECT s.name , COUNT(r.rid) `num_rate` , MIN(r.rate) `min_rate` , MAX(r.rate) `max_rate` , AVG(r.rate) `avg_rate` , SUM(r.rate) `total_rate` , COUNT(IF(r.nickname = 'mike', r.rid, NULL)) `mikes_num_rate` , MIN(IF(r.nickname = 'mike', r.rate, NULL)) `mikes_min_rate` , MAX(IF(r.nickname = 'mike', r.rate, NULL)) `mikes_max_rate` , AVG(IF(r.nickname = 'mike', r.rate, NULL)) `mikes_avg_rate` , SUM(IF(r.nickname = 'mike', r.rate, NULL)) `mikes_total_rate` FROM review r INNER JOIN location l ON l.lid = r.lid INNER JOIN spot s ON s.sid = l.sid GROUP BY s.name
Aggregation?
{ "aggs": { "group_by_name": { "terms": { "field": "name" }, "aggs": { "stats_rate": { "stats": { "field": "rate" } } } }, "if_mike": { "filter": { "term" : { "nickname": "mike" } }, "aggs": { "group_by_name": { "terms": { "field": "name" }, "aggs": { "stats_rate": { "stats": { "field": "rate" } } } } } } } }
とりあえずここまで
なんとなく、集計クエリとなると、大きなデータの日次なり月次なりの統計量を別のインデックスに保存して(INSERT ... SELECT ... 的な)推移とか見たくなりそうだけど、Aggregationだとさすがにそれは、Pythonとか書く必要があるか。
あと今回は、Logstash使ったけどRDBからのインポートは、他に
jprante/elasticsearch-jdbc · GitHub
embulk/embulk · GitHub
とかがつかえる。embulkの方がよかったかな。。。
#Kなし
とりあえず、ドキュメントを一通り読まねば。。。
おまけメモ
こないだ触ったデータが、緯度と経度をテーブルの別のカラムに複数もっててそれをElasticsearchのgeo_pointにマッピングする必要があったんだけど、SQL以外書きたくなかったので、zip関数(のようなもの)を作った
mysql> select * from pivot; +--------+ | rownum | +--------+ | 1 | | 2 | | 3 | | 4 | | 5 | +--------+ mysql> select zip('a b c', '1 2 3', ' ', ','); +----------------------------------------+ | zip('a b c', '1 2 3', ' ', ',') | +----------------------------------------+ | a,1 b,2 c,3 | +----------------------------------------+ 1 row in set (0.00 sec)