Chienomi

Mozcdict-Ext進捗: ByHand辞書

開発::application

Mozcの拡張システム辞書Mozcdict-Extが、新たな辞書としてbyhandが追加された。

これはその名の通り、何らかの収集や変換によって作られたものではなく、手作業で追加された辞書である。

Mozcシステム辞書の形式で手書きするのは大変なので、YAMLファイルから生成する形を取っている。

手書き辞書が追加された主な理由は、問題へのアプローチについて考え直したことにある。

まず前提の確認であるが、Mozcは仮名漢字変換エンジンである。 仮名漢字変換エンジンとしての出来・不出来は軽さ、安定性といった問題もあるが、そうした当然の部分1を置いておけば、目的の語句を変換できるかどうかにある。

コンテキストに従って「相応しい語」が一発で出れば理想的だが、現実的にはその「相応しさ」は主観的要素に決定することができない。 つまり、一般的に頻出する語句が比較的上位で変換できれば合格、そうでなくても変換できるならよし、変換できないのは問題であると考えることができるだろう。

分野や関心、言葉遣いも異なる様々な人が使い、変換できるかどうかが重要になる以上、「語彙の数」は絶対的な正義であり、語彙さえ増えれば変換エンジンは良いものになる、というのが一般的な考え方だ。 Mozc-UTもまた、そういう考え方であると言える。

そして、言葉が「速い」昨今、言葉を追いかけるためにwebをソースとするのは当然の考え方だ。

なお、MozcとGoogle日本語入力はともにMecabの辞書をベースとしているが、違いとして、Google日本語入力にはweb辞書が入っていることと、コスト計算の方法が違うということがある。

Mozcdict-ExtはもともとはGoogle日本語入力相当の快適性を目指して開発していたが、様々な検証を重ねた結果、それはデメリットのほうが大きいという結論に達した。

これはMS-IMEが予測変換で意味不明な語を羅列するのを見たことがある人も多いだろう。

はるかな作業

実はByHand辞書自体は2023年5月に追加されており、developブランチにいた。 それから1年以上に渡って塩漬けにしてきた。

ここには色々なハードルがあった。

まず登録方法だ。 この辞書は単純に私がメンテナンスするのではなく、人々の集合知によって成り立つ辞書にしようとしている。 そのため参加しやすい枠組みを作ろうとしていたのだが、結局Mozcの辞書に変換するための作業なども考えると結構大変で、今回もこの部分は諦めてissue式にした。

そしてMozcの品詞分類の理解。 Sudachiからの変換に苦労していることからも明らかだが、Mozcの品詞分類が実際どう使うものなのかが分かっていないと、結局増やせるのが名詞だけみたいなことになってしまう。

諦めてユーザー辞書にすると大幅に取り回しが良くなるのだが、人々が望んでいるのはそうではないだろうから、がんばった。

さらに「収録されていない」の確認。 Archlinuxのfcitx5-mozcは全然更新されていないので、確認が大変なのだ。

こうした作業があることと、いまいちユーザーからのリアクションがないことも相まって放置されてきた。

Web辞書のデメリット

間違い

webベースの辞書を使っているとよく遭遇するのが、言葉の間違いである。

特に「間違った読みで登録されており、正しい読みで変換できない」というのが結構ある。 その中でも、濁音や音便に関する間違いがかなり多い。

web上の語彙は「正しさ」に対する検証は限定的だから、この問題が修正されることはあまりない。

「増える」ことのメリットの少なさ

ソースを増やせば語彙が増えて、語彙が増えれば変換精度が上がる、というのが今の一般的な考え方だが、これは割と幻想である。

採用するソースはだいたい決まっており、それはwebの範囲を広げても割と限られたソースが下地になっていて、結局語彙はあまり増加していかないという現実がある。 そして、前述の「間違い」問題も解消しない。

そして、より特殊な語彙を追加していくと、変換が妨げられることが増え、必ずしも語彙の増加は体験の向上にならない。 ちなみに、現行のWindows 10のMS-IMEは「てて」と入力すると「手手手手手手手手手」に変換しようとする、みたいなのがあったりする。

「多いは正しい」の怪しさ

仮名漢字変換に限らないが、今の一般的なデータ取り扱いに関する指標は、「数が多いことは正義」である。

だから変換順序も「より多くweb上に登場する語」が優先されるし、「多く登場するのであれば正しい」とみなされる。

が、現実はそうではない。 webのデータは偏りが生じる2し、間違っている人の方が多いということも多々ある。

今はコスト計算を放棄しているので良くはないが、それはそれとして「webから多くを収集することで可能な判断」はあまり有用ではないと考えている。

domain specific問題

日常語やスラングは他の言葉と比べて圧倒的に数が多く、web辞書の採用はこれらに強いというのがメリットとされている。

ところが、これは実際のところメリットよりデメリットのほうが大きい。 例えば、あなたがよく使う分野の言葉が500追加されて、一発で変換できるようになったとする。 それ自体は嬉しいだろうが、あらゆる日常語やスラングが1億追加されたとすると、「変換できる嬉しさ」よりも「変換を邪魔される体験」のほうが圧倒的にまさる結果になるだろう。

「語彙が過剰」という理由で、Sudachi辞書を含まずにコンパイルするのもそう悪くないというのが現実だ。 私は固有名詞が変換できないのは嬉しくないと考えるので、(Mozc-UTと違い)Mozcdict-Extは固有名詞を含めてビルドするが、それでさえも邪魔だというケースがある。

そして、変換精度と優先度も考えると、domain specificな語はシステム辞書よりもユーザー辞書のほうがずっと適しているし、ユーザー辞書は作るのも配布するのも簡単だ。

だから私は「domain specificな語彙は自分が使う領域のユーザー辞書をインストールすべき」と考えるし、実際に私のプロジェクトとしても崩壊スターレイル辞書なんてものがあったりする。

このことから、Mozcdict-extとしてdomain specificな語彙の増強を目指すのはあまり得策ではないと考えた。 ただ、ある程度偏ったソース(例えばニコニコ大百科など)は文化圏にいるユーザーにとってはまるっと追加されても嬉しいということもあったりするだろうから、こうした辞書の追加に対して否定的なわけではない。 Mozcdict-Extとしては使いたいものだけを含めてビルドすることが可能なのだし、やってもいいが、優先的にやる動機はない。contributeに関しては考えるだろう。

どうあるべきか

理想は国語辞典の追加

まず前提として、Mecabの基本的な語彙と、NEologdのようなweb辞書による実用的な現代語の語彙があるという状態を考えて欲しい。

そんなMozcdict-Extを使っていて「ムッ」となるのは、「変換できて当然の語が出てこない」ときではないだろうか。 それが自分の間違い(読みが間違っている)ならまだしも、収録されていなかったり、間違った読みで登録されていたりするととても腹立たしいだろう。

この問題に対する正しい対処法は、明らかに「よりたくさんのwebサイトを収集する」ことではない。 「一般的な語彙の正しい読みを追加する」ことである。

それはなにか? 言うまでもない。国語辞典である。

理屈の上ではこれは可能なことだ。ATOKなんかは国語辞典を内包していたりするし、電子辞書化が進んでいる現在、やろうと思えばできるはずだ。

だが、国語辞典というのは出版社にとってのいわば「至宝」である。 見出し語と読みだけとはいえ、「使わせてください」という話が通ろうはずもない。 電子辞書ですらも検索に結構縛りがあったりするくらいだ。

余談だが、私は小辞典を5冊、中辞典を3冊所有しており、特に明鏡国語辞典と岩波国語辞典を愛用している。 現代的な語と使われ方をカバーする明鏡国語辞典と、保守的な日本語である岩波国語辞典の2冊があれば言葉に悩むことは少ない。 この2冊を取り込めたら……ととても思う。

さて、国語辞典をそのまま取り込むのが無理とするならばどうすればいいか。

国語辞典が優れているのは、専門家によって監修・執筆された語彙であることだ。 もちろん、語義・語釈こそが国語辞典の核と言えるが、語彙自体も専門家によるものであるからこそ間違いない。

であれば、「欠けているものを、きちんと監修した上で追加する」が答ではないだろうか。 となれば辞書の編纂同様に「手作り」にならざるをえない。

だが、これは辞書の編纂と比べればはるかに容易なことだ。 辞書の編纂は、イチから、真似をせずに語彙を選別し、他とはかぶらないように語義・語釈を記す。 対して、仮名漢字変換辞書は表記と読みが必要であるに過ぎない。国語辞典よりずっと複雑な品詞確定には苦労するかもしれないが、語彙は「不足している」ことがすでに分かっている語であるし、その読みについては国語辞典で確認して構わないのだから。

contribute容易な構造

Mozcやkkc本体にも言えることだが、「日本語入力を一人でメンテナンスする」というのは非常にいびつな話だ。 そんなことできるわけがないのだ。

Mozcdict-extにしても、半ば放置すれば私ひとりでメンテナンスすることはできなくもないが、より良いものにしていこうと考えれば無理な話であり、多くの人が簡単にcontributeすることができ、それを品質に反映させられるものである必要がある。

しかし、簡単にcontributeできるようにして、ユーザーが多くても実際は全然されないというのが現実だ。 そういう流れができない限り、人は他者が自分のいいようにすべてやってくれることを望み続ける。

もともと機械的に生成されているMozc辞書に手動で組み込むための労力は非常に大きく、膨大なサンプルを機械的に処理していることを人が頭で考えることで実現するというのはなかなか大変なことだ。 その膨大な労力を担ってくれる人は、募集したことで未来永劫現れないだろう。

そのため、ごく一部であっても容易にcontributeできるようにして、流れとして「みんなで作る」が生まれてくるようにしないと成立しないのだ。 そのため、簡単に投稿できるサービスを作ろうとしていた。 残念ながら今回は間に合わなかったが、反響次第では諦めていない。

ちなみに、Mozcのユーザー辞書は教科書的な品詞体系になっており、変換精度は劣るが手作業で登録するのが非常に楽。 簡単に追加できることに焦点を充てたユーザー辞書としてMozc Common User Dictも別途用意した。 インポートすることで簡単に使えるし、差分も同じ辞書にインポートすれば良い。

Mozc辞書の難しさ

ことばは常に流動的であり正しい言葉など存在しない、という前提を了解できていないと根本的に話が通じないため、そのあたりは理解しているものとして話を進める。

日本語は自然と語法が変化し、規則に例外が増えていく。 やがてその例外に規則性が見られるようになり、新たな規則が追加される。 という流れなのだが、今その言葉を使っている人間が使うために変換するためには、結局「この語はこのようには用いられるが、このようには用いられない」というのがある以上、その後が用いられる形をすべて登録する以外にない。

これが非常に現れているのが次の例である。

ばえる 映える 動詞,非自立,*,*,一段,基本形,える
ばえ  映え  動詞,非自立,*,*,一段,仮定形,える
ばえ  映え  動詞,非自立,*,*,一段,仮定縮約1,える
ばえ  映え  動詞,非自立,*,*,一段,未然形,える
ばえ  映え  動詞,非自立,*,*,一段,連用形,える
ばえ  映え  動詞,非自立,*,*,一段,体言接続特殊,える
ばえ  映え  名詞サ変

「映える」はもともと「はえる」で変換可能である。 が、Mozcではこれを「ばえる」単体で変換できない。 「映える」を「ばえる」と読むことが新規ではないが、濁点付きで読むことは多くはなかった。

「映える」は「映える」「映えない」「映えづらい」などという形で用いられ、「はえる」同様一段動詞であると考えて良さそうである。

Mozcの場合は非自立動詞一段は

  • 仮定形
  • 仮定縮約1
  • 基本形
  • 体言接続特殊
  • 命令ro
  • 命令yo
  • 未然ウ接続
  • 未然形
  • 連用形

がある。

しかし、未然ウ接続の「映えよう」はあまり使わないように思われる。 命令yo「映えよ」も普通の言い方ではないだろう。

仮定形/仮定縮約は結構微妙。 「映えればなんでもいい」「映えりゃOK」みたいな言い方は、する気がする。

いずれにせよ、ユーザー辞書なら1項目で良さそうな動詞一段が、システム辞書の場合は9項目必要になっている。 だが、これは「その語はこの形でしか出てこない」のためのものでもあるため、実際10項目になるとは限らない。

そもそも動詞一段にも接尾、自立、非自立があるし、非自立動詞一段基本形に限ったとしても

1078 動詞,非自立,*,*,一段,基本形,あげる
1079 動詞,非自立,*,*,一段,基本形,いける
1080 動詞,非自立,*,*,一段,基本形,いる
1081 動詞,非自立,*,*,一段,基本形,える
1082 動詞,非自立,*,*,一段,基本形,かえる
1083 動詞,非自立,*,*,一段,基本形,かける
1084 動詞,非自立,*,*,一段,基本形,かねる
1085 動詞,非自立,*,*,一段,基本形,きれる
1086 動詞,非自立,*,*,一段,基本形,すぎる
1087 動詞,非自立,*,*,一段,基本形,そこねる
1088 動詞,非自立,*,*,一段,基本形,そびれる
1089 動詞,非自立,*,*,一段,基本形,たげる
1090 動詞,非自立,*,*,一段,基本形,つける
1091 動詞,非自立,*,*,一段,基本形,つづける
1092 動詞,非自立,*,*,一段,基本形,づける
1093 動詞,非自立,*,*,一段,基本形,てる
1094 動詞,非自立,*,*,一段,基本形,できる
1095 動詞,非自立,*,*,一段,基本形,でる
1096 動詞,非自立,*,*,一段,基本形,のける
1097 動詞,非自立,*,*,一段,基本形,はじめる
1098 動詞,非自立,*,*,一段,基本形,みせる
1099 動詞,非自立,*,*,一段,基本形,みる
1100 動詞,非自立,*,*,一段,基本形,もらえる
1101 動詞,非自立,*,*,一段,基本形,る
1102 動詞,非自立,*,*,一段,基本形,上げる
1103 動詞,非自立,*,*,一段,基本形,代える
1104 動詞,非自立,*,*,一段,基本形,切れる
1105 動詞,非自立,*,*,一段,基本形,変える
1106 動詞,非自立,*,*,一段,基本形,始める
1107 動詞,非自立,*,*,一段,基本形,得る
1108 動詞,非自立,*,*,一段,基本形,忘れる
1109 動詞,非自立,*,*,一段,基本形,惚れる
1110 動詞,非自立,*,*,一段,基本形,振れる
1111 動詞,非自立,*,*,一段,基本形,換える
1112 動詞,非自立,*,*,一段,基本形,替える
1113 動詞,非自立,*,*,一段,基本形,枯れる
1114 動詞,非自立,*,*,一段,基本形,染みる
1115 動詞,非自立,*,*,一段,基本形,終える
1116 動詞,非自立,*,*,一段,基本形,続ける
1117 動詞,非自立,*,*,一段,基本形,過ぎる
1118 動詞,非自立,*,*,一段,基本形,願える

と大変盛りだくさん。

現状の形ではByHand辞書をユーザー辞書のような形式で書くことが困難すぎるため、個別のケースに対応するコードを追加する必要があるのだが、全部に対応するとものすごい量になる。

とりあえず「映える」のために変換を行うことにした。 もし、カスタム品詞を複数の品詞に展開する機能だけを用意すると、「映える」は未然ウ接続(「映えよう」)は明らかに使わないためその機能が使えないことになる。 そこで、「品詞群Aに展開するが、その中でこの活用形には展開しない」を指定できるようにした。 その結果、「映える」は

ばえる 映える サ変一段動詞える/未然ウ接続,命令yo

となった。

さらに、「ばえる」は「インスタ映えする」のようにサ変動詞になることがあるし、「インスタ映え」でちゃんと名詞になっている。

このあたりが日本語の面白いところだ。

「ばえる」は「映える」を濁点付きで読むことで現代的な用法として使い分けている、というのが注目となったわけだが、私の意見は少し異なる。

もともと「〜映え」というサ変接続名詞がある。 これ自体、接尾でしか使われずサ変接続するという、Mozcの体系では表現しづらいもの(名詞,サ変接続,*,*,*,*,講座か?)だが、これは基本的に「ばえ」と読む。

「写真映え」「広告映え」のような言葉は結構古いが、これは業界スラングであると考えることもできる。「写真映えがいい」のように名詞として用いることも、「写真映えする」のようにサ変動詞として用いることもある。

写真映えのような語は語の構成から見ても「見栄え」に由来し、「見栄え」が「見+栄え」よりは「見栄え」で1単語とされることが多いのを、語を分解して一般化した経緯に見える。 が、興味深いのは「はえる」は「映える」が普通で「栄える」とはしづらく、「みばえ」は「見栄え」が普通で「見映え」とはしづらい(どちらもそのように書きはする)のだが、「写真栄え」ではなく「写真映え」となったことだろうか。

これの一般化として「インスタ映え」があると考えられ、このサ変動詞「インスタ映えする」を一段動詞化して「インスタ映える」からの「映える」であると思われ、「はえる」から直接の変化ではないのではないか。 実際、「ばえる」は「バえる」よりは「バエる」と書かれることのほうが多く、このことからも動詞ではなく名詞に由来しているように見える。 現代日本語ではこのように他の活用をより広く一般化して用いられる例は非常によく見られる。

この「映える」議論は今年の新語2018の選評が詳しく、興味深い。

ちなみに、今回「映える」を入れたのは、そのような観点からどのように収録するか、ということをメモしておくのに実例が1つ欲しくて、このソースで目についたからだ。

品詞展開のコード

BYHAND_CLSMAP = {
  "一段動詞える" => ->(wp) {
    wp.w "動詞,非自立,*,*,一段,仮定形,える", "る"
    wp.w "動詞,非自立,*,*,一段,仮定縮約1,える", "る"
    wp.w "動詞,非自立,*,*,一段,体言接続特殊,える", "る"
    wp.w "動詞,非自立,*,*,一段,命令ro,える", "る"
    wp.w "動詞,非自立,*,*,一段,命令yo,える", "る"
    wp.w "動詞,非自立,*,*,一段,基本形,える"
    wp.w "動詞,非自立,*,*,一段,未然ウ接続,える", "る"
    wp.w "動詞,非自立,*,*,一段,未然形,える", "る"
    wp.w "動詞,非自立,*,*,一段,連用形,える", "る"
  },
  "サ変一段動詞える" => ->(wp) {
    wp.w "名詞,サ変接続,*,*,*,*,*", "る"
    wp.dg "一段動詞える"
  },
}

class WordProcessor
  def initialize(base, yomi, cls)
    @base = base
    @yomi = yomi
    if cls.include?("/")
      @spec_cls = cls.sub(%r:/.*:, "")
      @excludes = cls.sub(%r:.*/:, "").split(",")
    else
      @spec_cls = cls
      @excludes = []
    end
  end

  def wordout(c, remove = "", add = "")
    conjugation = c.split(",")[5]
    return if @excludes.include? conjugation
    puts [@yomi.delete_suffix(remove) + add, ID_DEF[c], ID_DEF[c], COST, @base.delete_suffix(remove) + add].join("\t")
  end

  def dg(cls)
    BYHAND_CLSMAP[cls].call(self)
  end  

  alias  
end

展開部分をWordProcessorの中に組み込んでしまうと判定がやりづらくなるため、オブジェクトを受け渡す形にした。

色々工夫はあるが、説明するポイントはそれほどないため、興味ある人は各自読んでもらう方向で。

参考資料

[形態素解析] 「仮定縮約1」とは?MeCab・IPADICの品詞分類を理解しようが大変参考になり、助かった。