Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

20160929_InnoDBの全文検索を使ってみた by 株式会社インサイトテクノロジー 中村範夫

745 Aufrufe

Veröffentlicht am

2016-09-29(木)にMySQLとPostgreSQLと日本語全文検索3で発表した内容となります!

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

20160929_InnoDBの全文検索を使ってみた by 株式会社インサイトテクノロジー 中村範夫

  1. 1. InnoDBの全文検索を使ってみた
  2. 2. 自己紹介 2 • 中村範夫(なかむらのりお) • 2013年(株)インサイトテクノロジー 入社 • プロダクトコンサルティング事業部所属 • 大阪で10年以上システム開発に従事した後に現社へ • 扱ったデータベース経験年数では、Oracle、SQL Server、MySQLの順
  3. 3. アジェンダ 3 • InnoDBの全文検索を使い始めた経緯 • InnoDBの全文検索を試してみる • INNODB_FT_INDEX_TABLEを使って分析してみる • まとめ
  4. 4. InnoDBの全文検索を使い始めた経緯 4 • 社内製品開発 • SNMPから上がってくる膨大な警告メッセージを全文検索したい • 全文検索だけじゃなくて分析したい • MySQL 5.7 登場! – InnoDB全文検索の日本語対応 経緯
  5. 5. MySQL InnoDBを使っての全文検索 5 • 2種類の わかち分かち書き をサポート • N-gram(デフォルト) • MeCab(形態素解析)※プラグインのインストールが必要 • 分かち書きされた結果もデータディクショナリで簡単参照 ( INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE) MySQL InnoDB全文検索の特徴 CREATE TABLE ALT_TAB( FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, HOST_NAME VARCHAR(20), MSG VARCHAR(400), INS_TIME datetime, FULLTEXT INDEX ftsidx (MSG) WITH PARSER mecab )ENGINE=InnoDB CHARACTER SET utf8;
  6. 6. 対象データを分かち書きした結果( N-Gram と Mecab の比較) 6 N-Gramは設定した(デフォルト2)文字数でのみ分割するのに対し、 Mecabは単語毎に分割し、辞書サイズも節約でき性能もよさそう 例)192.10.9.26: IF-MIB/ifHCInOctets_psec(1)=400 ※SNMPエラーメッセージ
  7. 7. まずは実際の検索性能をMecabで実施 7 mysql> select SQL_NO_CACHE count(*) from ALT_100 -> where match (MSG) against('使用時間' IN BOOLEAN MODE); +------------+ | count(MSG) | +------------+ | 9465 | +------------+ 1 row in set (0.73 sec) mysql> select SQL_NO_CACHE count(*) from ALT_1000 -> where match (MSG) against('使用時間' IN BOOLEAN MODE); +------------+ | count(MSG) | +------------+ | 94650 | +------------+ 1 row in set (30.70 sec) 検索処理性能は、およそ100万件で1秒程度、1000万件で30秒程度 ※母数に対し1%程度のデータがヒットする検索条件で実施 データ インデックス 100万件 500 57 1000万件 4200 473 総件数 InnoDB Mecab (MB)
  8. 8. 分かち書きした結果のMySQLでの見え方 8 mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE ORDER BY doc_id, position LIMIT 10; +-------------------+--------------+-------------+-----------+--------+----------+ | WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION | +-------------------+--------------+-------------+-----------+--------+----------+ | 192 | 1 | 22785 | 21846 | 1 | 0 | | 10 | 1 | 19652 | 18931 | 1 | 4 | | 100 | 1 | 383964 | 11774 | 1 | 7 | | 200 | 1 | 383935 | 10885 | 1 | 10 | | ip | 1 | 29784 | 21845 | 1 | 14 | | mib | 1 | 22785 | 21846 | 1 | 18 | | ipifstatsinoctets | 1 | 383899 | 18412 | 1 | 22 | | psec | 1 | 22785 | 21846 | 1 | 40 | | )= | 1 | 21971 | 21846 | 1 | 48 | | 15 | 1 | 374036 | 21459 | 1 | 50 | +-------------------+--------------+-------------+-----------+--------+----------+ 10 rows in set (18.39 sec) 分かち書き結果(転置インデックスの中身)の確認 分析にも使えそうな予感!
  9. 9. 分かち書きの結果データディクショナリと実テーブルとの関係 9 DOC_IDが外部キーとして使える! ※一意な識別子として、FTS_DOC_ID列を明示的に作成することを推奨とマニュアルにもあります。
  10. 10. 分析用SQL:時間を指定して上位ワードを取得 10 mysql> -- 時間を指定して特定の日のMSGに含まれるワードの一覧上位30件を取得 mysql> SELECT a.WORD, -> COUNT(*) -> FROM INNODB_FT_INDEX_TABLE AS a -- 分かち結果テーブル -> INNER JOIN ALT_TAB AS b -- ALTテーブル -> ON a.DOC_ID = b.FTS_DOC_ID -> WHERE b.INS_TIME BETWEEN '2016-05-23 01:00:00' AND '2016-05-23 01:59:59' -> GROUP BY b.HOST_NAME, a.word -> ORDER BY COUNT(*) DESC -> LIMIT 30; +--------------+----------+ | WORD | COUNT(*) | +--------------+----------+ | fan | 92 | | threshold | 72 | | over | 72 | | psec | 72 | | 192 | 72 | | 10 | 71 | | 168 | 71 | | over | 71 | | psec | 71 | | threshold | 67 | | 90 | 67 | | over | 67 | | psec | 67 | IPアドレスが分割されて残念な結果になっているの で、辞書に登録してみよう!
  11. 11. Mecab 辞書の登録方法 11 [root@Nlocalhost ~]# cd /usr/lib64/mysql/mecab/dic/ipadic_utf-8 [root@localhost ipadic_utf-8]# /usr/libexec/mecab/mecab-dict-index -d ./ -u user.dic -f utf8 -t utf8 user-dic.csv reading user-dic.csv ... 12 emitting double-array: 100% |###########################################| done! [root@localhost ipadic_utf-8]# ls -ltr 合計 51840 -rw-r--r--. 1 root root 6241 5月 11 20:36 2016 rewrite.def -rw-r--r--. 1 root root 49199027 5月 11 20:36 2016 sys.dic -rw-r--r--. 1 root root 5690 5月 11 20:36 2016 unk.dic -rw-r--r--. 1 root root 1477 5月 11 20:36 2016 pos-id.def -rw-r--r--. 1 root root 55910 5月 11 20:36 2016 left-id.def -rw-r--r--. 1 root root 693 5月 11 20:36 2016 dicrc -rw-r--r--. 1 root root 262496 5月 11 20:36 2016 char.bin -rw-r--r--. 1 root root 55910 5月 11 20:36 2016 right-id.def -rw-r--r--. 1 root root 3463716 5月 11 20:36 2016 matrix.bin -rw-r--r--. 1 root root 1073 5月 11 20:36 2016 user-dic.csv -rw-r--r--. 1 root root 4125 5月 20 10:32 2016 user.dic mecab-dict-index コマンでcsvファイルを元に ユーザー辞書を作成 できあがった、user.dicをmecabrcファイルに追記 mecab-dict-indexコマンドで辞書を作成する 表層形 左文脈ID 右文脈ID コスト 品詞 品詞細分類1 品詞細分類2 品詞細分類3 活用形 活用型 原形 読み 発音 172.16.32.1 * * 10000 名詞 一般 * * * * 172.16.32.1 172.16.32.1 172.16.32.1 icmpInEchoReps * * 10000 名詞 一般 * * * * icmpInEchoReps icmpInEchoReps icmpInEchoReps icmpInEchos * * 10000 名詞 一般 * * * * icmpInEchos icmpInEchos icmpInEchos 追加する辞書フォーマット サンプル
  12. 12. Mecab 辞書登録後の分かち書き結果 12 辞書登録前はIPアドレスが分割される 辞書登録後はIPアドレスが分割されない
  13. 13. 分析用SQL:時間を指定して上位ワードを取得 13 mysql> -- 時間を指定して特定の日のMSGに含まれるワードの一覧上位30件を取得 mysql> SELECT a.WORD, -> COUNT(*) -> FROM INNODB_FT_INDEX_TABLE AS a -- 分かち結果テーブル -> INNER JOIN ALT_TAB AS b -- ALTテーブル -> ON a.DOC_ID = b.FTS_DOC_ID -> WHERE b.INS_TIME BETWEEN '2016-05-23 01:00:00' AND '2016-05-23 01:59:59' -> GROUP BY b.HOST_NAME, a.word -> ORDER BY COUNT(*) DESC -> LIMIT 30; +-------------------+----------+ | WORD | COUNT(*) | +-------------------+----------+ | fan | 572 | | threshold | 351 | | hardware_resource | 351 | | 192.168.10.83 | 351 | | over | 351 | | tach | 286 | | 6500 | 78 | | 5900 | 65 | | 6700 | 52 | IPアドレスが分割されなくなったが、意味のない数 値のみ(しきい値の実数等)が邪魔
  14. 14. 除外リスト(STOPWORD)について 14 分かち書きさせたくない除外リスト(STOPWORD)に登録する方法 /etc/my.cnf ファイルに以下の設定を追記 # for stop words innodb_ft_server_stopword_table=‘test/STOP_WORDS‘ 自動判定したしきい値等の実数を除外したい場合(1~1000の整数値等)、MySQLの全文検索機能に は、STOPWORDテーブルが用意されている。予め予測できる数値等はここに登録しておくことで、 分かちの除外対象とすることができる。次に紹介するSQLの検索側で除外する方法に比べ、INSERT時 に除外できるので、分かち結果テーブルの件数を抑えられるメリットがある。以下その方法。 -- STOPWORDテーブルに単語登録 INSERT INTO test.STOP_WORDS VALUES (1),(2),(3),…(1000);
  15. 15. 正規表現によりSQLで数値のみや記号を除外する 15 -- MySQLでは正規表現が使えるので記号のみ、数値のみのワードは除外する SELECT a.WORD as WORD , count(*) as cnt FROM TFM_ALT_20160525_FTIDX AS a WHERE a.WORD NOT REGEXP ‘^[!-/:-@[-`{-~0-9]+$’ -- 数字のみ、記号のみは除外 GROUP BY a.WORD ORDER BY count(*) DESC LIMIT 100 自動判定したしきい値等の実数は、動的に変更するため、全てを予め辞 書に登録しておくことは不可能なので、SQL側で除外した
  16. 16. 分析用SQL:前日にはなかったエラーワード一覧 16 mysql> SELECT x.WORD -> , x.cnt as day25 -> FROM (-- 当日の頻出上位100件のワード一覧 -> SELECT a.WORD as WORD, count(*) as cnt -> FROM FTIDX_20160525 AS a -- INNODB_FT_INDEX_TABLEを日ごとに物理化したテーブル -> WHERE a.WORD NOT REGEXP ‘^[!-/:-@[-`{-~0-9]+$’ -> GROUP BY a.WORD -> ORDER BY count(*) DESC LIMIT 100) AS x -> LEFT JOIN ( -> -- 前日の頻出上位100件のワード一覧 -> SELECT a.WORD as WORD, count(*) as cnt -> FROM FTIDX_20160524 AS a -- INNODB_FT_INDEX_TABLEを日ごとに物理化したテーブル -> WHERE a.WORD NOT REGEXP ‘^[!-/:-@[-`{-~0-9]+$’ -> GROUP BY a.WORD -> ORDER BY count(*) DESC LIMIT 100) y -> ON x.WORD = y.WORD -> WHERE y.cnt IS NULL -- 前日(day24)には存在しなかった -> ORDER BY x.cnt DESC; +------------------------------+-------+ | WORD | day25 | +------------------------------+-------+ | 172.16.34.89 | 1027 | | 172.16.34.65 | 899 | | 172.16.34.87 | 886 | | ipsystemstatshcinmcastpkts | 700 | | ipsystemstatsinmcastpkts | 700 | | ipsystemstatshcinoctets | 680 | | ipsystemstatsinoctets | 680 | | ipsystemstatshcinmcastoctets | 628 | | ipsystemstatsinmcastoctets | 628 | ・ ・
  17. 17. MySQL InnoDBを使ってみての感想 17 • MySQL InnoDB 全文検索 • Ver5.7以上を使っているなら、日本語全文検索は直ぐに使える • 対象データに見合うトークナイザー(N-gram or MeCab)の選択が重要 • Mecabの場合 • 性能はデータに大きく依存するがそこそこ使える • 転置インデックスのデータディクショナリは有用 • 辞書と STOPWORD の活用により分かち書きの調整が可能 • 使いどころは? • 規模:全体の件数が数100万件程度まで、サイズは数GB~数十GB程度 • 向いていると思うシステム: • 例): グループウェア(社内メール)、チケット管理システム(redmine)等

×