43
textsearch_ja で 三国志を読み解く ぬこ@横浜 (@nuko_yokohama)

textsearch jaで吉川三国志を読み解く

Embed Size (px)

DESCRIPTION

textsearch_jaを使って青空文庫の吉川三国志を分析してみたという、誰得な資料。

Citation preview

Page 1: textsearch jaで吉川三国志を読み解く

textsearch_ja で三国志を読み解く

ぬこ@横浜 (@nuko_yokohama)

Page 2: textsearch jaで吉川三国志を読み解く

まず・・・今回の話の前提

Page 3: textsearch jaで吉川三国志を読み解く

三国志が嫌いな男子なんていません!!!!!

最近は腐女子にも人気があるようだが

Page 4: textsearch jaで吉川三国志を読み解く

三国志の本は山ほどある陳寿「三国志」

羅漢中「三国志演義」吉川英治「三国志」

柴田錬三郎「柴錬三国志」北方謙三「三国志」

陳舜臣「秘本三国志」「曹操 魏の曹一族」宮城谷昌光「三国志」伴野朗「呉・三国志」

酒見賢一「泣き虫弱虫諸葛孔明」横山光輝「三国志」王欣太「蒼天航路」

武論尊 / 池上遼一「覇 – Load 」etc ...

未読

読書中

正史

基本

呂布贔屓

八百長

パロディ

ジャーンジャーン

トンデモ

呉ファン向け

時代劇

元祖

曹操主役 うちには多分100冊以上は転がっている・・・

Page 5: textsearch jaで吉川三国志を読み解く

さて

Page 6: textsearch jaで吉川三国志を読み解く

昨年の秋くらいに吉川英治「三国志」が

青空文庫化されました。

実に素晴らしい!

Page 7: textsearch jaで吉川三国志を読み解く

吉川英治「三国志」

吉川英治が1939 年から 1943 年まで

連載していた小説

三国志が日本に定着した要因には、この本の影響が大きい

Page 8: textsearch jaで吉川三国志を読み解く

青空文庫とは⇒Wikipedia 見て

要するに著作権が切れた文学作品をテキスト化してオープンにしたもの

Page 9: textsearch jaで吉川三国志を読み解く

実は青空文庫は長大な日本語テキストのサンプルとしても使える

⇒textsearch_ja の検証とか

青空文庫は昭和の頃の格調高い日本語のサンプルとしても重要。

また、形態素解析方式は、「壊れていない」日本語向き。ネットスラングとか、ギャル語とかはかなり苦手・・・

Page 10: textsearch jaで吉川三国志を読み解く

今日は、 PostgreSQL の日本語形態素解析全文検索textsearch_ja を使って

「吉川三国志」を分析した結果を話します。

Page 11: textsearch jaで吉川三国志を読み解く

textsearch_ja

PostgreSQL の形態素解析全文検索形態素解析には Mecab を利用

Page 12: textsearch jaで吉川三国志を読み解く

青空文庫版「三国志」をtextsearch_ja で使うための準備

(なお、今回は「序」は対象外)

Page 13: textsearch jaで吉川三国志を読み解く

青空文庫のサイトから DL10 個のテキストファイルSJIS なので UTF8 化する

先頭・末尾部分の削除COPY 文形式への置換

章単位で行分割ファイルのマージ

Page 14: textsearch jaで吉川三国志を読み解く

実行環境

CentOS 6.3PostgreSQL 9.3.2

textsearch_ja(patched)Mecab 0.994 9.3 上で動かすためには、

少しだけソースの修正が必要 ( 補足参照 )

Page 15: textsearch jaで吉川三国志を読み解く

テーブル構成sangokushi=# \d List of relations Schema | Name | Type | Owner --------+-------------------+----------+-------- public | sangokushi | table | harada public | sangokushi_id_seq | sequence | harada(2 rows)

sangokushi=# \d sangokushi Table "public.sangokushi" Column | Type | Modifiers ---------+---------+--------------------------------------------------------- id | integer | not null default nextval('sangokushi_id_seq'::regclass) vol | text | chapter | text | body | text | Indexes: "idx" gin (to_tsvector('japanese'::regconfig, body)

Page 16: textsearch jaで吉川三国志を読み解く

テーブル構成(補足)vol : 巻名

chapter : 章名body : 本文

本文を to_tsvector 型に変換する関数 GIN インデックスを設定

Page 17: textsearch jaで吉川三国志を読み解く

巻数: 10総文字数:約 20 万字

章数: 3141 章の平均字数:約 6200 文字

⇒ だいたい TOAST 対象

Page 18: textsearch jaで吉川三国志を読み解く

動作確認sangokushi=# EXPLAIN ANALYZE SELECT id FROM sangokushi WHERE to_tsvector('japanese', body) @@ to_tsquery('japanese', ' 孔明 ');

QUERY PLAN ----------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on sangokushi (cost=16.01..137.36 rows=2 width=4) (actual time=0.048..0.072 rows=134 loops=1) Recheck Cond: (to_tsvector('japanese'::regconfig, body) @@ ''' 孔明 '''::tsquery)

-> Bitmap Index Scan on idx (cost=0.00..16.01 rows=2 width=0) (actual time=0.039..0.039 rows=134 loops=1) Index Cond: (to_tsvector('japanese'::regconfig, body) @@ ''' 孔明 '''::tsquery)

Total runtime: 0.103 ms(5 rows)

sangokushi=# EXPLAIN ANALYZE SELECT count(id) FROM sangokushi WHERE body LIKE '% 孔明 %';

QUERY PLAN ---------------------------------------------------------------------------------------------------------------- Aggregate (cost=773.93..773.94 rows=1 width=4) (actual time=34.806..34.806 rows=1 loops=1) -> Seq Scan on sangokushi (cost=0.00..773.92 rows=1 width=4) (actual time=13.361..34.763 rows=134 loops=1) Filter: (body ~~ '%孔明 %'::text)

Rows Removed by Filter: 180 Total runtime: 34.834 ms(5 rows)

textsearch_ja を使った検索ではきちんとインデックスが使用されている。

このくらいのデータ量でも、 LIKE との性能差は明らか。

Page 19: textsearch jaで吉川三国志を読み解く

今回の検証

Page 20: textsearch jaで吉川三国志を読み解く

textsearch_ja の検索ランク取得関数

ts_rank_cd() を使って主要登場人物の出現頻度を

カウントしてグラフ化します

Page 21: textsearch jaで吉川三国志を読み解く

検証を阻害する意外な (?) 障壁

Page 22: textsearch jaで吉川三国志を読み解く

障壁 1

Page 23: textsearch jaで吉川三国志を読み解く

中国の人名が意外と厄介

Mecab 辞書に登録されてない登場人物名が多い

Page 24: textsearch jaで吉川三国志を読み解く

「劉備」は Mecab 辞書に登録されていないのか、

「劉」と「備」で解析されてしまう。

しかも中国に「劉」姓は多い!「劉備」「劉禅」「劉表」「劉虞」・・・

「孔明」は登録されてるのだが

諸葛亮 劉備わし、一応…主役なのに

Page 25: textsearch jaで吉川三国志を読み解く

ということで、三国志検索用にMecab 辞書を登録してかつ、検索されるような

チューニングが必要になる

Page 26: textsearch jaで吉川三国志を読み解く

さすがに三国志に登場する全キャラクターを登録すると1000 人を超えちゃうのでホントに主要なキャラのみ

登録することに

Page 27: textsearch jaで吉川三国志を読み解く

こんな感じでMecab ユーザ辞書を追加する

劉備,,,6000,名詞,固有名詞,人名,名,*,*,りゅうび,リュウビ,リュービ玄徳,,,6000,名詞,固有名詞,人名,名,*,*,げんとく,ゲントク,ゲントク諸葛亮,,,6000,名詞,固有名詞,人名,名,*,*,しょかつりょう,ショカツリョウ,ショカツリョー関羽,,,6000,名詞,固有名詞,人名,名,*,*,かんう,カンウ,カンウ雲長,,,6000,名詞,固有名詞,人名,名,*,*,うんちょう,ウンチョウ,ウンチョー張飛,,,6000,名詞,固有名詞,人名,名,*,*,ちょうひ,チョウヒ,チョーヒ翼徳,,,6000,名詞,固有名詞,人名,名,*,*,よくとく,ヨクトク,ヨクトク(省略)呂布,,,6000,名詞,固有名詞,人名,名,*,*,りょふ,リョフ,リョフ奉先,,,6000,名詞,固有名詞,人名,名,*,*,ほうせん,ホウセン,ホーセン張遼,,,6000,名詞,固有名詞,人名,名,*,*,ちょうりょう,チョウリョウ,チョーリョー文遠,,,6000,名詞,固有名詞,人名,名,*,*,ぶんえん,ブンエン,ブンエン袁紹,,,6000,名詞,固有名詞,人名,名,*,*,えんしょう,エンショウ,エンショー本初,,,6000,名詞,固有名詞,人名,名,*,*,ほんしょ,ホンショ,ホンショ貂蝉,,,6000,名詞,固有名詞,人名,名,*,*,ちょうせん,チョウセン,チョーセン赤兎馬,,,6000,名詞,固有名詞,人名,名,*,*,せきとば,セキトバ,セキトバ

これをMecab 機能でコンパイル&

登録する

今回は数十人の主要人物名の「姓名」「姓字名」を登録した。(ついでに赤兎馬も)

Page 28: textsearch jaで吉川三国志を読み解く

障壁 2

Page 29: textsearch jaで吉川三国志を読み解く

呼称のぶれ

「姓・名」「姓・字名」「姓・官職」

「諱」の表記が混在している

Page 30: textsearch jaで吉川三国志を読み解く

「劉備」「劉玄徳」「劉皇叔」

とりあえず「姓名」「姓字名」のみ対応することにした

⇒ to_tsquery で OR 指定

Page 31: textsearch jaで吉川三国志を読み解く

こんな感じのクエリになる

sangokushi=# SELECT id, left(substr(chapter,8),10) AS chapter, left(ts_headline('japanese',body, to_tsquery('japanese', ' 司馬懿 | 仲達 ')),30) AS body

FROM sangokushi WHERE to_tsvector('japanese', body) @@ to_tsquery('japanese', ' 司馬懿 | 仲達 ') LIMIT 10;

id | chapter | body -----+----------------------+------------------------------------------------------- 138 | 臨戦《りんせん》第一 | <b> 司馬懿 </b> 《しばい》、字を <b> 仲達 </b> 《ちゅ 208 | 剣《けん》と戟《ほこ | <b> 司馬懿 </b> 《しばい》 <b> 仲達 </b> 《ちゅうたつ 215 | 正月十五夜[#「正月 | <b> 司馬懿 </b><b> 仲達 </b>が、側で眉をひそめた。 225 | 漢中王《かんちゅうお | <b> 司馬懿 </b> 《しばい》、字《あざな》は <b> 仲達 </

231 | 建業会議《けんぎょう | <b> 司馬懿 </b> 《しばい》 <b> 仲達 </b> 《ちゅうたつ 239 | 国葬[#「国葬」は大 | <b> 司馬懿 </b> 《しばい》、字《あざな》は <b> 仲達 </

242 | 曹操《そうそう》死《 | <b> 司馬懿 </b> 《しばい》 <b> 仲達 </b>がそっと、枕 246 | 改元[#「改元」は大 | <b> 司馬懿 </b> 《しばい》 <b> 仲達 </b>があわてて、 259 | 魚紋[#「魚紋」は大 | <b> 司馬懿 </b> 《しばい》、字は <b> 仲達 </b> 《ちゅ 261 | 建艦総力[#「建艦総 | <b> 仲達 </b>は、「呉の守りは、長江を生命としています。

しばちゅうさん(司馬懿)の例

Page 32: textsearch jaで吉川三国志を読み解く

障壁 3

Page 33: textsearch jaで吉川三国志を読み解く

ついつい本文を読み耽ってしまうw

気づくと数巻分、数時間くらい

経過することも屡々検証中、結局全巻読み直したよ・・・

Page 34: textsearch jaで吉川三国志を読み解く

検証結果

全巻スコア総計章ごとの登場比率

Page 35: textsearch jaで吉川三国志を読み解く

全巻スコア総計名前 スコア総計

劉備 269.7

諸葛亮 209.4

関羽 142.5

曹操 285.1

司馬懿 48.7

張遼 23.6

(孫家三代) 98.7

周瑜 48.5

魯粛 25.8

呂蒙 25.5

陸遜 25.5

呂布 88.0

董卓 33.9

劉備

諸葛亮

関羽

曹操

司馬懿

張遼

(孫家三代)

周瑜

魯粛

呂蒙

陸遜

呂布

董卓

0.0 50.0 100.0 150.0 200.0 250.0 300.0

ランク総計

Page 36: textsearch jaで吉川三国志を読み解く

●劉備・諸葛亮をおさえて、なんと曹操がトップに●曹操を単なる悪者にしていないのもポイント。●とはいえ、劉備・諸葛亮もさすがは主役級のスコア●武将の中でも関羽は別格だね・・・●呂布は前半で消えちゃったから・・・●中盤の好敵手・周瑜、終盤の好敵手・司馬懿も高めのスコア●でも全般に呉はあまり書かれていない・・・●劉備・曹操、諸葛亮の物語だからなのかな。●呉家三代の総計でも関羽に及ばない。●呉にも良い武将・軍師も多いけどリリーフ的だから・・・

全巻スコア総計

Page 37: textsearch jaで吉川三国志を読み解く

章ごとの登場比率

1 21 41 61 81 10161116 26

3136 46

5156 66

7176 86

9196 106

111116121126131136141146151156161166171176181186191196201206211216221226231236241246251256261266271276281286291296301306311

0%

10%

20%

30%

40%

50%

60%

70%

80%

90%

100%

吉川三国志 主要人物 /章別 ランク比率

董卓

呂布

周瑜

孫家

司馬懿

曹操

孔明

関羽

劉備

Page 38: textsearch jaで吉川三国志を読み解く

ストーリーと比較するとこんな感じに

1 21 41 61 81 10161116 26

3136 46

5156 66

7176 86

9196 106

111116121126131136141146151156161166171176181186191196201206211216221226231236241246251256261266271276281286291296301306311

0%

10%

20%

30%

40%

50%

60%

70%

80%

90%

100%

吉川三国志 主要人物 /章別 ランク比率

董卓

呂布

周瑜

孫家

司馬懿

曹操

孔明

関羽

劉備

虎牢関

桃園の誓い

小覇王

連環の計 関羽千里行

赤壁

関羽の最期 曹操の最期

周瑜の最期 出師の表夷陵呂布の最期

南蛮行 五丈原

Page 39: textsearch jaで吉川三国志を読み解く

●冒頭の主役は劉備と関羽 ( と張飛 )●曹操も出てくるけど、そこまで目立たない●序盤での呂布の暴れっぷり●中盤の主役は実は曹操なのだな●終盤の主役は勿論、諸葛亮と司馬懿●呉(笑)●小覇王の時代や赤壁など見せ場はあるけどさ

章ごとの登場比率

Page 40: textsearch jaで吉川三国志を読み解く

ということで、textsearch_ja を使って

誰得な分析をしてみました。

Page 41: textsearch jaで吉川三国志を読み解く

そして三国志は

やっぱり面白い

Page 42: textsearch jaで吉川三国志を読み解く

おしまい

Page 43: textsearch jaで吉川三国志を読み解く

●textsearch_ja は 9.0 以降、正式な対応が止まっている。●現状は EXTENSION に対応していない。●9.2以降だと、 DL したファイルそのままだと、インストール

時に失敗するので、 LANGUAGE='C' を LANGUAGE=c などに変更する必要がある。

●9.3 上で動かす場合、 textsearch_ja.c に#include "access/htup_details.h"の行を追加しないとビルド時に警告がでる。

●また、上記の対処をしないと、 ja_analyze() で異常終了することがある。

補足