WorksApplications / SudachiPy

Python version of Sudachi, a Japanese tokenizer.
Apache License 2.0
391 stars 50 forks source link

数詞を含む分割情報を定義した単語があるとユーザー辞書をビルドできない #155

Closed po3rin closed 3 years ago

po3rin commented 3 years ago

sudachiのユーザー辞書に分割情報を入れようとしているのですが、数詞を含む分割情報をもつ単語でエラーが出ます。理由や対処法がわかれば教えていただきたいです。

詳細

例えば下記のようなユーザー辞書を作成したい場合

グレード1,5146,5146,5000,グレード1,名詞,普通名詞,一般,*,*,*,,グレード1,*,C,"グレード,名詞,普通名詞,一般,*,*,*,グレード/1,名詞,数詞,*,*,*,*,イチ","グレード,名詞,普通名詞,一般,*,*,*,グレード/1,名詞,数詞,*,*,*,*,イチ",*

下記のようなエラーが出ます。(エラーがわかりづらかったので最近出したPR( https://github.com/WorksApplications/SudachiPy/pull/154 )が入ったもので出力しています。)

sudachipy ubuild src/test_dict.txt -o sudachi/test.dic -s sudachi/system_core.dic
reading the source file...81 words
writing the POS table...2 bytes
writing the connection matrix...4 bytes

// 省略...

writing the word_infos...Traceback (most recent call last):
  File "/---/.pyenv/versions/3.9.0/bin/sudachipy", line 33, in <module>
    sys.exit(load_entry_point('SudachiPy==0.5.3.dev6+g7e5b501', 'console_scripts', 'sudachipy')())
  File "/---/.pyenv/versions/3.9.0/lib/python3.9/site-packages/sudachipy/command_line.py", line 220, in main
    args.handler(args, args.print_usage)
  File "/---/.pyenv/versions/3.9.0/lib/python3.9/site-packages/sudachipy/command_line.py", line 114, in _command_user_build
    builder.build(args.in_files, None, wf)
  File "/---/.pyenv/versions/3.9.0/lib/python3.9/site-packages/sudachipy/dictionarylib/userdictionarybuilder.py", line 40, in build
    self.write_lexicon(out_stream)
  File "/---/.pyenv/versions/3.9.0/lib/python3.9/site-packages/sudachipy/dictionarylib/dictionarybuilder.py", line 268, in write_lexicon
    self.write_wordinfo(io_out)
  File "/---/.pyenv/versions/3.9.0/lib/python3.9/site-packages/sudachipy/dictionarylib/dictionarybuilder.py", line 292, in write_wordinfo
    self.write_intarray(self.parse_splitinfo(entry.aunit_split_string))
  File "/---/.pyenv/versions/3.9.0/lib/python3.9/site-packages/sudachipy/dictionarylib/dictionarybuilder.py", line 328, in parse_splitinfo
    ids.append(self.parse_id(word))
  File "/---/.pyenv/versions/3.9.0/lib/python3.9/site-packages/sudachipy/dictionarylib/dictionarybuilder.py", line 345, in parse_id
    id_ = int(text)
  File "/---/.pyenv/versions/3.9.0/lib/python3.9/site-packages/sudachipy/dictionarylib/dictionarybuilder.py", line 345, in parse_id
    id_ = int(text)
ValueError: invalid literal for int() with base 10: '1,名詞,数詞,*,*,*,*,イチ'

ここでエラーになる際には今までシステム辞書に含まれない単語だった場合に発生していたのですが、今回「1」はシステム辞書にはあるのでビルドに失敗している理由がわかりません。

echo "ステージ1" | poetry run sudachipy -m C -a                                                                                                  

ステージ        名詞,普通名詞,一般,*,*,*        ステージ        ステージ        ステージ        0       [385]
1       名詞,数詞,*,*,*,*       1       1       イチ    0       [17619]
EOS

この問題の対処法を教えていただけますと幸いです。よろしくお願いします。

sorami commented 3 years ago

(私は今はSudachiの中の人ではないのですが、参考までです)

原因

「見出しとしての 1 」が「行番号1」に誤認されている、ということなのかと思います。

公式ドキュメント: Sudachi/user_dict.md at develop · WorksApplications/Sudachi

15 A単位分割情報 ... 構成語のIDまたは構成語情報を "/" (半角スラッシュ) で区切って記述します。 構成語のIDはその語が記述されている行番号 (0始まり) か、その先頭に "U" を加えた文字列です。ユーザー辞書内の語を参照するときに "U" をつけます。 構成語情報は語の見出し (解析結果表示用)、品詞1-4、品詞 (活用型)、品詞 (活用形)、読みを "," (カンマ) で区切った文字列です。

コード該当箇所↓ https://github.com/WorksApplications/SudachiPy/blob/develop/sudachipy/dictionarylib/dictionarybuilder.py#L327

def __is_id(text):
    return re.match(r'U?\d+', text)

@kazuma-t @t-yamamura 間違っていたらご指摘ください。

対処

見出しの 1 を、「構成語情報」として記述するのではなく、「構成語のID」として記述(システム辞書の行番号を特定するか、 別途ユーザー辞書に掲載)すると、コード変更なしに動かせるのかなと思います。

前提: システム辞書のみでの解析結果

$ echo "グレード1" | sudachipy -a -m C
グレード        名詞,普通名詞,一般,*,*,*        グレード        グレード        グレード        0       [241]
1       名詞,数詞,*,*,*,*       1       1       イチ    0       [17619]
EOS

$ echo "グレード1" | sudachipy -a -m A
グレード        名詞,普通名詞,一般,*,*,*        グレード        グレード        グレード        0       [241]
1       名詞,数詞,*,*,*,*       1       1       イチ    0       [17619]
EOS

対処例 1. システム辞書の行番号を指定

行番号の特定

$ cd SudachiDict/src/main/text

$ grep -n "^グレード," small_lex.csv
198573:グレード,5144,5144,2399,グレード,名詞,普通名詞,一般,*,*,*,グレード,グレード,*,A,*,*,*,000241

$ grep -n "^1," small_lex.csv
17:1,4796,4796,2478,1,名詞,数詞,*,*,*,*,イチ,1,*,A,*,*,*,017619
18:1,5073,5073,3081,1,名詞,数詞,*,*,*,*,イチ,1,*,A,*,*,*,017619
19:1,4796,4796,4120,1,名詞,数詞,*,*,*,*,イッ,1,*,A,*,*,*,017619
20:1,5073,5073,4723,1,名詞,数詞,*,*,*,*,イッ,1,*,A,*,*,*,017619
21:1,5072,5072,6464,1,名詞,数詞,*,*,*,*,ヒト,1,*,A,*,*,*,017619
22:1,5072,5072,9720,1,名詞,数詞,*,*,*,*,ビト,1,*,A,*,*,*,017619
23:1,-1,-1,0,1,名詞,普通名詞,一般,*,*,*,ワン,ワン,*,A,*,*,*,017619
6227:1,-1,-1,0,¹,補助記号,一般,*,*,*,*,キゴウ,¹,*,A,*,*,*,*
6506:1,-1,-1,0,①,名詞,数詞,*,*,*,*,イチ,1,*,A,*,*,*,017619
6507:1,-1,-1,0,①,名詞,数詞,*,*,*,*,イッ,1,*,A,*,*,*,017619
6508:1,-1,-1,0,①,補助記号,一般,*,*,*,*,キゴウ,①,*,A,*,*,*,*
1,4796,4796,2478,1,名詞,数詞,*,*,*,*,イチ,1,*,A,*,*,*,017619

ユーザー辞書ファイル

$ cat test_dict.txt
グレード1,5146,5146,5000,グレード1,名詞,普通名詞,一般,*,*,*,,グレード1,*,C,"グレード,名詞,普通名詞,一般,*,*,*,グレード/16","グレード,名詞,普通名詞,一般,*,*,*,グレード/16",*

# もしくは
$ cat test_dict.txt
グレード1,5146,5146,5000,グレード1,名詞,普通名詞,一般,*,*,*,,グレード1,*,C,198572/16,198572/16,*

$ sudachipy ubuild test_dict.txt
reading the source file...1 words
writing the POS table...2 bytes
writing the connection matrix...4 bytes
building the trie...done
writing the trie...1028 bytes
writing the word-ID table...9 bytes
writing the word parameters...10 bytes
writing the word_infos...40 bytes
writing word_info offsets...4 bytes

解析結果

$ echo "グレード1" | sudachipy -a -m C -r sudachi.json
グレード1       名詞,普通名詞,一般,*,*,*        グレード1       グレード1       グレード1       1       []
EOS

$ echo "グレード1" | sudachipy -a -m A -r sudachi.json
グレード        名詞,普通名詞,一般,*,*,*        グレード        グレード        グレード        0       [241]
1       名詞,数詞,*,*,*,*       1       1       イチ    0       [17619]
EOS

対処例 2. ユーザー辞書に別途追加

ユーザー辞書ファイル

$ cat test_dict.txt
グレード1,5146,5146,5000,グレード1,名詞,普通名詞,一般,*,*,*,,グレード1,*,C,U1/U2,U1/U2,*
グレード,5146,5146,5000,グレード,名詞,普通名詞,一般,*,*,*,,グレード,*,A,*,*,*
1,5146,5146,5000,1,名詞,数詞,*,*,*,*,,イチ,*,A,*,*,*

$ sudachipy ubuild test_dict.txt
reading the source file...3 words
writing the POS table...2 bytes
writing the connection matrix...4 bytes
building the trie...done
writing the trie...1028 bytes
writing the word-ID table...19 bytes
writing the word parameters...22 bytes
writing the word_infos...82 bytes
writing word_info offsets...12 bytes

解析結果

$ echo "グレード1" | sudachipy -a -m C -r sudachi.json
グレード1       名詞,普通名詞,一般,*,*,*        グレード1       グレード1       グレード1       1       []
EOS

$ echo "グレード1" | sudachipy -a -m A -r sudachi.json
グレード        名詞,普通名詞,一般,*,*,*        グレード        グレード        グレード        1       []
1       名詞,数詞,*,*,*,*       イチ    1       1       1       []
EOS
sorami commented 3 years ago

@kazuma-t @t-yamamura こうすると、ちゃんとIDかを判定して適切にビルドできるんじゃないかと思います → #156

(当Issueの例で動作することは確認しましたが、他部分への影響等がよくわかっていません)

po3rin commented 3 years ago

「見出しとしての 1 」が「行番号1」に誤認されている、ということなのかと思います。

ありがとうございます。原因が理解できました。

156 で動きそうなので一旦そちらの修正を前のめりで利用するか、頂いた対処法を利用するかを社内で検討します。

sorami commented 3 years ago

ちなみに、数値始まり見出し以外にも U2,名詞,固有名詞,人名,一般,*,*,ユーツー とかでも落ちるなーと思いました。

(システム辞書には U2 は入ってなかったですけど)

kazuma-t commented 3 years ago

ご指摘ありがとうございます。Java 版の方からきた不具合ですね。さきに Java 版の方をなおしてからこちらにも反映します。

kazuma-t commented 3 years ago

よくよく見たら Java 版の方は対応済みでした。