MySQLのMECABによる最近つぶやかれている単語の解析

MySQLのMecabプラグインを利用して集計したデータを解析する過程で、INNODB_FT_INDEX_TABLEにて含まれている単語を確認し集計しようとしたが、
サーバーのスペックが低く集計中にハングしてしまったので、メモリーのINNODB_FT_INDEX_TABLEの内容をInnoDBテーブルに落として集計してみた。
もし、同様に形態素解析で解析されたワードを集計したいけれども、メモリー量が不足していて単語を集計出来ない場合の回避策として。参考までに。


root@localhost [(none)]> desc INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
+--------------+---------------------+------+-----+---------+-------+
| Field        | Type                | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+-------+
| WORD         | varchar(337)        | NO   |     |         |       |
| FIRST_DOC_ID | bigint(21) unsigned | NO   |     |         |       |
| LAST_DOC_ID  | bigint(21) unsigned | NO   |     |         |       |
| DOC_COUNT    | bigint(21) unsigned | NO   |     |         |       |
| DOC_ID       | bigint(21) unsigned | NO   |     |         |       |
| POSITION     | bigint(21) unsigned | NO   |     |         |       |
+--------------+---------------------+------+-----+---------+-------+
6 rows in set (0.03 sec)

root@localhost [confirm]> show create table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE\G
*************************** 1. row ***************************
       Table: INNODB_FT_INDEX_TABLE
Create Table: CREATE TEMPORARY TABLE `INNODB_FT_INDEX_TABLE` (
  `WORD` varchar(337) NOT NULL DEFAULT '',
  `FIRST_DOC_ID` bigint unsigned NOT NULL DEFAULT '0',
  `LAST_DOC_ID` bigint unsigned NOT NULL DEFAULT '0',
  `DOC_COUNT` bigint unsigned NOT NULL DEFAULT '0',
  `DOC_ID` bigint unsigned NOT NULL DEFAULT '0',
  `POSITION` bigint unsigned NOT NULL DEFAULT '0'
) ENGINE=MEMORY DEFAULT CHARSET=utf8
1 row in set (0.06 sec)

メモリーのINNODB_FT_INDEX_TABLEからInnoDBのテーブルにデータをコピーする


root@localhost [(confirm)]> SET GLOBAL innodb_ft_aux_table='APP/Tweets';
Query OK, 0 rows affected (0.00 sec)

root@localhost [(confirm)]> SET GLOBAL innodb_optimize_fulltext_only=ON;optimize table Tweets;
Query OK, 0 rows affected (0.00 sec)

root@localhost [confirm]> CREATE TEMPORARY TABLE `FTS_INDEX_TABLE` (
    ->   `WORD` varchar(337) NOT NULL DEFAULT '',
    ->   `FIRST_DOC_ID` bigint unsigned NOT NULL DEFAULT '0',
    ->   `LAST_DOC_ID` bigint unsigned NOT NULL DEFAULT '0',
    ->   `DOC_COUNT` bigint unsigned NOT NULL DEFAULT '0',
    ->   `DOC_ID` bigint unsigned NOT NULL DEFAULT '0',
    ->   `POSITION` bigint unsigned NOT NULL DEFAULT '0'
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.01 sec)


root@localhost [confirm]> insert into FTS_INDEX_TABLE select * from INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
Query OK, 11642045 rows affected (12 min 51.51 sec)
Records: 11642045  Duplicates: 0  Warnings: 0


オーバーヘッド
MEMORYからデータのコピー中はサーバースペックも低いのでメモリー+SWAPが最大限に利用されている。
時間も上記のように12分もかかってしまいました。

メモ:再集計する時に、TRUNCATEするのでTEMPORARYのままでもいいけど、念のためInnoDB間のみでデータコピー速度を確認してみた。
こちらは、1分半程度で終わっています。


root@localhost [confirm]> CREATE TABLE `FTS_WORD_TABLE` (
    ->   `WORD` varchar(337) NOT NULL DEFAULT '',
    ->   `FIRST_DOC_ID` bigint unsigned NOT NULL DEFAULT '0',
    ->   `LAST_DOC_ID` bigint unsigned NOT NULL DEFAULT '0',
    ->   `DOC_COUNT` bigint unsigned NOT NULL DEFAULT '0',
    ->   `DOC_ID` bigint unsigned NOT NULL DEFAULT '0',
    ->   `POSITION` bigint unsigned NOT NULL DEFAULT '0'
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected (0.01 sec)

root@localhost [confirm]> insert into FTS_WORD_TABLE select * from FTS_INDEX_TABLE;
Query OK, 11642045 rows affected (1 min 29.70 sec)
Records: 11642045  Duplicates: 0  Warnings: 0

TWEETワードランキング
以下、直近のTweet集計結果です。コロナの影響もあり、殆どがコロナ関連の単語が上位にきている事が分かります。


root@localhost [confirm]> select rank() OVER(ORDER BY count(*) desc) ranking,WORD,count(*) 
    -> from FTS_WORD_TABLE where length(WORD) > 4 group by WORD having count(*) >= 10000 order by ranking;
+---------+-----------------+----------+
| ranking | WORD            | count(*) |
+---------+-----------------+----------+
|       1 | ウイルス        |   282891 |
|       2 | コロナ          |   232527 |
|       3 | 新型            |   173684 |
|       4 | 感染            |   157965 |
|       5 | https           |   137958 |
|       6 | ます            |   101664 |
|       7 | ない            |    97355 |
|       8 | から            |    81599 |
|       9 | する            |    70057 |
|      10 | こと            |    66332 |
|      11 | まし            |    65643 |
|      12 | いる            |    64802 |
|      13 | です            |    62606 |
|      14 | 拡大            |    43248 |
|      15 | バス            |    40119 |
|      16 | 日本            |    31022 |
|      17 | ある            |    29622 |
|      18 | 対策            |    29344 |
|      19 | ため            |    28480 |
|      20 | この            |    25914 |
|      21 | 中国            |    24729 |
|      22 | てる            |    24267 |
|      23 | など            |    23112 |
|      24 | まで            |    22573 |
|      25 | という          |    22429 |
|      26 | よう            |    22123 |
|      27 | 検査            |    21856 |
|      28 | なっ            |    20436 |
|      29 | 医療            |    20188 |
|      30 | 東京            |    19908 |
|      31 | これ            |    18426 |
|      32 | 影響            |    18350 |
|      33 | 確認            |    18141 |
|      34 | ので            |    17266 |
|      35 | あり            |    17175 |
|      36 | さん            |    16897 |
|      37 | について        |    16705 |
|      38 | ませ            |    16701 |
|      39 | たら            |    16575 |
|      40 | マスク          |    16337 |
|      41 | なり            |    16270 |
|      42 | 緊急            |    16173 |
|      43 | より            |    15770 |
|      44 | なく            |    15662 |
|      45 | 防止            |    15512 |
|      46 | 受け            |    15471 |
|      47 | 世界            |    15462 |
|      48 | って            |    15407 |
|      49 | けど            |    15108 |
|      50 | 発表            |    14998 |
|      51 | として          |    14969 |
|      52 | 政府            |    14914 |
|      53 | れる            |    14863 |
|      54 | yahoonewstopics |    14258 |
|      55 | なる            |    14207 |
|      56 | 自粛            |    12808 |
|      57 | その            |    12730 |
|      58 | 情報            |    12621 |
|      59 | 事態            |    12430 |
|      60 | だけ            |    12010 |
|      61 | 武漢            |    11872 |
|      62 | お知らせ        |    11751 |
|      63 | そう            |    11453 |
|      64 | できる          |    11284 |
|      65 | による          |    11218 |
|      66 | でき            |    11120 |
|      67 | 開催            |    11085 |
|      68 | たい            |    10899 |
|      69 | 宣言            |    10855 |
|      70 | でも            |    10801 |
|      71 | ニュース        |    10720 |
|      72 | 状況            |    10663 |
|      73 | 中止            |    10641 |
|      74 | 新た            |    10626 |
|      75 | おり            |    10507 |
|      76 | 患者            |    10391 |
|      77 | だっ            |    10352 |
|      78 | なら            |    10304 |
|      79 | 時間            |    10096 |
|      80 | 対応            |    10093 |
|      81 | 病院            |    10092 |
+---------+-----------------+----------+
81 rows in set (26.52 sec)

root@localhost [confirm]> 

参考: Windows関数 on MySQL


最近、MySQL5.7の形態素解析エンジンのmecabに関して辞書をカスタマイズ出来るかどうか
聞かれる事が増えた為、mecabの辞書をカスタマイズしてきちんと動作確認してみました。
結論としては、問題無くカスタマイズした辞書も利用出来るようです。
但し、MySQLのマニュアルページを見る限り、MySQL Binaryから提供されているmecab辞書の利用を推奨しているようです。

【以下、抜粋】
Installing MeCab From Source (Optional)
https://dev.mysql.com/doc/refman/5.7/en/fulltext-search-mecab.html
The mecab and mecab-ipadic packages distributed with the MySQL binary are recommended but
if you want to build mecab and mecab-ipadic from source, basic installation steps are provided below.
For additional information, refer to the MeCab documentation.

前回のmecab基本検証
http://variable.jp/2015/04/10/creating-index-with-utf8mb4-on-mecab-with-5-7-7/

基本的には、MySQLのmecab辞書は特に手を加えていないようです
MySQLのコンパイル済みTarからインストールした場合のファイル

 
[root@misc02 admin]# ls -l /usr/local/mysql/lib/mecab/dic/ipadic_utf-8
合計 51828
-rw-r--r--. 1 root mysql   262496 11月  6 23:18 char.bin
-rw-r--r--. 1 root mysql      693 11月  6 23:18 dicrc
-rw-r--r--. 1 root mysql    55910 11月  6 23:18 left-id.def
-rw-r--r--. 1 root mysql  3463716 11月  6 23:18 matrix.bin
-rw-r--r--. 1 root mysql     1477 11月  6 23:18 pos-id.def
-rw-r--r--. 1 root mysql     6241 11月  6 23:18 rewrite.def
-rw-r--r--. 1 root mysql    55910 11月  6 23:18 right-id.def
-rw-r--r--. 1 root mysql 49199027 11月  6 23:18 sys.dic
-rw-r--r--. 1 root mysql     5690 11月  6 23:18 unk.dic

MecabサイトからIPA辞書をダウンロードしてインストールした場合(手を加えていない場合)

[root@misc02 admin]# ls -l /usr/local/lib/mecab/dic/ipadic
合計 51828
-rw-r--r--. 1 root root   262496  4月  4 11:36 char.bin
-rw-r--r--. 1 root root      693  4月  4 11:36 dicrc
-rw-r--r--. 1 root root    55910  4月  4 11:36 left-id.def
-rw-r--r--. 1 root root  3463716  4月  4 11:36 matrix.bin
-rw-r--r--. 1 root root     1477  4月  4 11:36 pos-id.def
-rw-r--r--. 1 root root     6241  4月  4 11:36 rewrite.def
-rw-r--r--. 1 root root    55910  4月  4 11:36 right-id.def
-rw-r--r--. 1 root root 49199027  4月  4 11:36 sys.dic
-rw-r--r--. 1 root root     5690  4月  4 11:36 unk.dic
[root@misc02 admin]# 

ここから、実際に辞書を登録して新規ワードが追加された辞書を登録しています。
※ 事前にnkf等で辞書をUTF-8に変換していますが、ここでは説明を割愛してあります。

【辞書の追加】2つの名詞のみを登録
今回は、”日本オラクル株式会社”と”mecabプラグイン”の二つのみ登録して確認

[root@misc02 mecab]# cat user_defined_dictionary_utf8.csv 
日本オラクル株式会社,1285,1285,5078,名詞,一般,*,*,*,*,日本オラクル株式会社,ニホンオラクルカブシキガイシャ,ニホンオラクルカブシキガイシャ
mecabプラグイン,1285,1285,5699,名詞,一般,*,*,*,*,mecabプラグイン,メカブプラグイン,メカブプラグイン,和布蕪プラグイン
[root@misc02 mecab]# cp -rp user_defined_dictionary_utf8.csv mecab-ipadic-2.7.0-20070801/
[root@misc02 mecab]#

user_defined_dictionary_utf8.csvが作成した追加の辞書ファイル
2文字のみ登録しているので、2文字インデックシングされた事が以下のアウトプットから確認出来る。

[root@misc02 mecab-ipadic-2.7.0-20070801]# /usr/local/libexec/mecab/mecab-dict-index -f utf-8 -t utf-8
reading ./unk.def ... 40
emitting double-array: 100% |###########################################| 
./model.def is not found. skipped.
reading ./Adj.csv ... 27210
reading ./Adnominal.csv ... 135
reading ./Adverb.csv ... 3032
reading ./Auxil.csv ... 199
reading ./Conjunction.csv ... 171
reading ./Filler.csv ... 19
reading ./Interjection.csv ... 252
reading ./Noun.adjv.csv ... 3328
reading ./Noun.adverbal.csv ... 795
reading ./Noun.csv ... 60477
reading ./Noun.demonst.csv ... 120
reading ./Noun.nai.csv ... 42
reading ./Noun.name.csv ... 34202
reading ./Noun.number.csv ... 42
reading ./Noun.org.csv ... 16668
reading ./Noun.others.csv ... 151
reading ./Noun.place.csv ... 72999
reading ./Noun.proper.csv ... 27327
reading ./Noun.verbal.csv ... 12146
reading ./Others.csv ... 2
reading ./Postp-col.csv ... 91
reading ./Postp.csv ... 146
reading ./Prefix.csv ... 221
reading ./Suffix.csv ... 1393
reading ./Symbol.csv ... 208
reading ./Verb.csv ... 130750
reading ./user_defined_dictionary_utf8.csv ... 2
emitting double-array: 100% |###########################################| 
reading ./matrix.def ... 1316x1316
emitting matrix      : 100% |###########################################| 

done!
[root@misc02 mecab-ipadic-2.7.0-20070801]# make install
make[1]: ディレクトリ `/home/admin/mecab/mecab-ipadic-2.7.0-20070801' に入ります
make[1]: `install-exec-am' に対して行うべき事はありません.
/bin/sh ./mkinstalldirs /usr/local/lib/mecab/dic/ipadic
 /bin/install -c -m 644 ./matrix.bin /usr/local/lib/mecab/dic/ipadic/matrix.bin
 /bin/install -c -m 644 ./char.bin /usr/local/lib/mecab/dic/ipadic/char.bin
 /bin/install -c -m 644 ./sys.dic /usr/local/lib/mecab/dic/ipadic/sys.dic
 /bin/install -c -m 644 ./unk.dic /usr/local/lib/mecab/dic/ipadic/unk.dic
 /bin/install -c -m 644 ./left-id.def /usr/local/lib/mecab/dic/ipadic/left-id.def
 /bin/install -c -m 644 ./right-id.def /usr/local/lib/mecab/dic/ipadic/right-id.def
 /bin/install -c -m 644 ./rewrite.def /usr/local/lib/mecab/dic/ipadic/rewrite.def
 /bin/install -c -m 644 ./pos-id.def /usr/local/lib/mecab/dic/ipadic/pos-id.def
 /bin/install -c -m 644 ./dicrc /usr/local/lib/mecab/dic/ipadic/dicrc
make[1]: ディレクトリ `/home/admin/mecab/mecab-ipadic-2.7.0-20070801' から出ます
[root@misc02 mecab-ipadic-2.7.0-20070801]# 

mecab辞書を追加前
辞書追加前は、文字が分割されて辞書登録されている

[root@misc02 mecab-ipadic-2.7.0-20070801]# echo '日本オラクル株式会社' | /usr/local/bin/mecab
日本    名詞,固有名詞,地域,国,*,*,日本,ニッポン,ニッポン
オラクル        名詞,一般,*,*,*,*,*
株式会社        名詞,一般,*,*,*,*,株式会社,カブシキガイシャ,カブシキガイシャ
EOS
[root@misc02 mecab-ipadic-2.7.0-20070801]# 

[root@misc02 mecab-ipadic-2.7.0-20070801]# echo 'mecabプラグイン' | /usr/local/bin/mecab
mecab   名詞,固有名詞,組織,*,*,*,*
プラグ  名詞,一般,*,*,*,*,プラグ,プラグ,プラグ
イン    名詞,一般,*,*,*,*,イン,イン,イン
EOS
[root@misc02 mecab-ipadic-2.7.0-20070801]# 

mecab辞書を追加後
きちんと追加したWORDが1つの単語として認識されている事が分かる

[root@misc02 mecab]# echo '日本オラクル株式会社' | /usr/local/bin/mecab
日本オラクル株式会社    名詞,一般,*,*,*,*,日本オラクル株式会社,ニホンオラクルカブシキガイシャ,ニホンオラクルカブシキガイシャ
EOS
[root@misc02 mecab]# echo 'mecabプラグイン' | /usr/local/bin/mecab
mecabプラグイン 名詞,一般,*,*,*,*,mecabプラグイン,メカブプラグイン,メカブプラグイン,和布蕪プラグイン
EOS
[root@misc02 mecab]# 

検索対象文字列
Server1とServer2で同じデータを登録してIndexingしてあります。
また、mecab辞書はmy.cnfで新規作成したmecab辞書を参照するように設定済み。

root@localhost [mecab]> select description from articles where description like '%mecab%';
+-------------------------------------------------------------------------+
| description                                                             |
+-------------------------------------------------------------------------+
| MySQL mecabプラグインの辞書を追加した場合の動作確認                     |
| MySQL mecab                                                             |
+-------------------------------------------------------------------------+
2 rows in set (0.00 sec)

root@localhost [mecab]> select description from articles where description like '%日本%';
+---------------------------------------------------------------------------+
| description                                                               |
+---------------------------------------------------------------------------+
| 日本オラクル株式会社 辞書を追加した場合の動作確認                         |
| 日本オラクル                                                              |
+---------------------------------------------------------------------------+
2 rows in set (0.00 sec)

root@localhost [mecab]> 

オリジナルのmecab辞書
新規登録した単語では認識されていない。オリジナル辞書にあるmecabや日本と言った辞書で確認出来ている。

root@localhost [mecab]> OPTIMIZE TABLE articles;
+----------------+----------+----------+----------+
| Table          | Op       | Msg_type | Msg_text |
+----------------+----------+----------+----------+
| mecab.articles | optimize | status   | OK       |
+----------------+----------+----------+----------+
1 row in set (0.01 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like 'meca%';
+-------+-----------+--------+----------+
| word  | doc_count | doc_id | position |
+-------+-----------+--------+----------+
| mecab |         1 |     33 |        5 |
| mecab |         1 |     35 |        5 |
+-------+-----------+--------+----------+
2 rows in set (0.00 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like 'mecabプラグイン';
Empty set (0.01 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like '日本%';
+--------+-----------+--------+----------+
| word   | doc_count | doc_id | position |
+--------+-----------+--------+----------+
| 日本   |         1 |     34 |        0 |
| 日本   |         1 |     36 |        0 |
+--------+-----------+--------+----------+
2 rows in set (0.00 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like '日本オラクル%';
Empty set (0.01 sec)

root@localhost [mecab]> 
 

WORDを追加したmecab辞書
追加で単語が登録されているので、追加登録した辞書で文字列が検索出来ている。
サービスのニーズや流行りの言葉を登録させておく事により、ビジネスのニーズに柔軟に対応出来そうです。
大規模なサービスはSolr等の方が良いかもしれませんが、小規模~中規模のサービスには使えそうです。

root@localhost [mecab]> OPTIMIZE TABLE articles;
+----------------+----------+----------+----------+
| Table          | Op       | Msg_type | Msg_text |
+----------------+----------+----------+----------+
| mecab.articles | optimize | status   | OK       |
+----------------+----------+----------+----------+
1 row in set (0.01 sec)

root@localhost [mecab]>  SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like 'meca%';
+----------------------+-----------+--------+----------+
| word                 | doc_count | doc_id | position |
+----------------------+-----------+--------+----------+
| mecab                |         1 |     20 |        5 |
| mecabプラグイン      |         1 |     18 |        5 |
+----------------------+-----------+--------+----------+
2 rows in set (0.01 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like 'mecabプラグイン';
+----------------------+-----------+--------+----------+
| word                 | doc_count | doc_id | position |
+----------------------+-----------+--------+----------+
| mecabプラグイン      |         1 |     18 |        5 |
+----------------------+-----------+--------+----------+
1 row in set (0.00 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like '日本%';
+--------------------------------+-----------+--------+----------+
| word                           | doc_count | doc_id | position |
+--------------------------------+-----------+--------+----------+
| 日本                           |         1 |     21 |        0 |
| 日本オラクル株式会社           |         1 |     19 |        0 |
+--------------------------------+-----------+--------+----------+
2 rows in set (0.01 sec)

root@localhost [mecab]> SELECT word, doc_count, doc_id, position FROM information_schema.INNODB_FT_INDEX_TABLE where word like '日本オラクル%';
+--------------------------------+-----------+--------+----------+
| word                           | doc_count | doc_id | position |
+--------------------------------+-----------+--------+----------+
| 日本オラクル株式会社           |         1 |     19 |        0 |
+--------------------------------+-----------+--------+----------+
1 row in set (0.01 sec)

root@localhost [mecab]> 

search_output

参考:
12.9.9 MeCab Full-Text Parser Plugin
MeCab: Yet Another Part-of-Speech and Morphological Analyzer
単語の追加方法