• 作成:

dic-nico-intersection-pixivをニコニコ大百科のデータを自前でスクレイピングするように変更しました

ncaq/dic-nico-intersection-pixiv: ニコニコ大百科とピクシブ百科事典の共通部分の辞書

https://cdn.ncaq.net/dic-nico-intersection-pixiv.txt

でnicoimeのデータを使わず自前でスクレイピングするようにしました.

何故自前でスクレイピングするようにしたのか

これまでのdic-nico-intersection-pixivはニコニコ大百科の辞書データとしてニコニコ大百科IME辞書 神は細部に宿り給うのものを使わせて貰っていました.

しかし2018/12/14の更新で括弧部分が削除されて単語が1つだけに統一されるという処理が行われるようになった結果,霧雨魔理沙も霧雨魔理沙(20)も同じ「きりさめまりさ」なので(今は修正されてますがそれは私による編集),「きりさめまりさ」と入力すると「霧雨魔理沙(20)」に変換されてしまう状態になっていました.本来の「霧雨魔理沙」には変換できません.単語は1つだけに統一されているので.

これはこちら側の処理では改善不能です.元データから「霧雨魔理沙」が統一された結果排除されてしまっているのですから.

とりあえずしばらく辞書を更新しないという手段でごまかしていましたが,いつか新しい単語を大量に入れなくてはいけないことになると思い,自前でニコニコ大百科のデータを取得することにしました.

実は2019年6月27日頃には出来てました

実は2019年6月27日頃にはその実装は概ね完成していましたが,実際使って問題ないか試したかったのと記事を書く時間と気力が無かったのでmasterにはマージせず自分だけで使っていました.

しかし東方鬼形獣も発売されたので,そろそろmasterにマージして更新したと通告しておくべきだと思ったのでここに記しておきます.

以下実装の時気をつけたことでも書いておきます.

スクレイピング方法

ニコニコ大百科IME辞書 神は細部に宿り給うの記述を大いに参考にさせてもらって,50音順単語記事一覧 - ニコニコ大百科から記事を全取得しました.

キャッシュ

nicoimeをスクレイピングしてからルールを変更してフィルタリングし直すことが多く,これまでと違ってスクレイピングの負担が段違いなのでスクレイピングのキャッシュをちゃんと設定しておきました.

その際にデータを適当にshow, readでシリアライズしていたら当然遅かったので,store :: Stackage Serverを使うことにしました.

シリアライズライブラリには型情報を保存するものと保存しないものがあり,当然保存しないものの方が互換性を保てない代わりにデータ量が少なく,今回どうせ更新する時はキャッシュは削除するので一時的に手元で保存できればそれで良いので,型情報を保存しないものを選択しました.

エラー時再取得

ニコニコ大百科のサーバは再現性なく通信に失敗します.仕方がないので2回通信を試みて最初の通信に失敗したら1秒スリープを挟んでもう一度取得を試みてみることにしました.そうすると概ねうまくいきました.

icuでカタカナひらがな変換

ニコニコ大百科の読みがなはカタカナです.でもIME辞書の読みに使うのはひらがなです.変換が必要ですね.

50音ぐらいパターンマッチで変換してやっても問題ないのですが,流石にスマートではないのでICUを使いました.

text-icu-translit: ICU transliterationを使えばicuの難解なAPIに悩まされることなく変換だけをスムーズに出来ます.

-- icuで変換
-- 長音記号が変換されてしまうのでカタカナには使われない文字を使って誤魔化す
hiraganaYomi = T.replace "!" "ー" $ transliterate (trans "Katakana-Hiragana") $
  T.replace "ー" "!" $ toTextStrict yomi

長音記号も変換されてしまうのを回避する手段がスマートじゃないですね…

並列処理があまり効かない(未解決)

dictionarySorted = sortOn entryYomi (dictionaryFilter (H.toList dicNico)) `using` parList rseq

のようにフィルタリング処理を並列に行っているのですが,せいぜい300%ぐらいしかCPUを使ってくれなくて,並列処理があまり効いていません.

それともあまりにもフィルタリング処理の内容が軽すぎるから有効に働いてない?と思ってある程度大きいチャンクに分けて並列評価するストラテジーなども試してみたのですが効果はありませんでした.

やっぱりリストだと分割とかに限界があるんですかね…?

まあそこまで異様に時間がかかる処理をやっているわけではないので,諦めてこんなものかと割り切ることにしました.