この記事は Go アドベントカレンダー 12/19 の記事です.

たぶん誰も使ってないと思いますが, kagome にはユーザー辞書があります.形式は kuromoji のユーザー辞書と同じです.なので,「関西国際空港」を登録して search モードで「関西/国際/空港」という風に分割することが出来ます.

といってもあんまり伝わらないだろうな,と思って特に説明を書いてなかったのですが,いい機会なのでもし誰かのお役に立てばと思い,kagome のユーザー辞書について少し説明したいと思います.

TL;DR

  • ユーザー辞書に登録された語彙は最優先で使われます.
  • ユーザー辞書への登録の仕方は3つの方法があります.
    • ユーザー辞書ファイルを用意して作成する
    • JSON で読み込んで作成する
    • 任意のデータから kagome のユーザー辞書構造体にコピーして作成する

ユーザー辞書ファイルを用意する

これは kuromoji のユーザー辞書と同じ形式です.

ここにサンプルがあります.
https://github.com/ikawaha/kagome/blob/master/_sample/userdic.txt

# コメントは # 始まりで書けます
# 1行1レコードとして形態素を登録できます
# 最初に見出し,そのあとに分割形式(分割は半角スペースで),あとは対応するヨミと品詞です

日本経済新聞,日本 経済 新聞,ニホン ケイザイ シンブン,カスタム名詞
関西国際空港,関西 国際 空港,カンサイ コクサイ クウコウ,カスタム地名
朝青龍,朝青龍,アサショウリュウ,カスタム人名

これをファイルから読んでユーザー辞書を生成します.

        udic, err := tokenizer.NewUserDicRecords(user_dic_path)

同じ形態素が辞書にあったとしても,ユーザー辞書に登録されたものが最優先で利用されます.

JSON から読み込む

JSON にユーザー辞書を記録しておいて,それを読み込んでユーザー辞書を作成する方法もあります.
JSON の形式は以下のサンプルを見てもらえればわかると思います.ユーザー辞書ファイルと同じです.

一旦,UserDicRecord という構造体に読み込んでから,NewUserDic() すればユーザー辞書が生成されます.

        var rec tokenizer.UserDicRecords
        json.Unmarshal([]byte(`[
        {
            "text":"日本経済新聞",
            "tokens":["日本","経済","新聞"],
            "yomi":["ニホン","ケイザイ","シンブン"],
            "pos":"カスタム名詞"
        },
        {
            "text":"朝青龍",
            "tokens":["朝青龍"],
            "yomi":["アサショウリュウ"],
            "pos":"カスタム人名"
        }]`), &rec)
        udic, err := rec.NewUserDic()

独自のデーターをユーザー辞書として使いたいとき

独自に持ってるデータを使ってユーザー辞書を用意したいときは,UserDicRecords に形態素情報を詰め込んで,NewUserDic() してください.

        r := UserDicRecords{
                {
                        Text:   "日本経済新聞",
                        Tokens: []string{"日本", "経済", "新聞"},
                        Yomi:   []string{"ニホン", "ケイザイ", "シンブン"},
                        Pos:    "カスタム名詞",
                },
                {
                        Text:   "朝青龍",
                        Tokens: []string{"朝青龍"},
                        Yomi:   []string{"アサショウリュウ"},
                        Pos:    "カスタム人名",
                },
        }
        udic, err := r.NewUserDic()

ユーザー辞書の設定方法

上で用意したユーザー辞書を実際に使うサンプルです.

package main

import (
    "fmt"
    "strings"

    "github.com/ikawaha/kagome/tokenizer"
)

func main() {
    // ユーザー辞書を用意
    udic, err := tokenizer.NewUserDic(user_dic_path)
    if err != nil {
        panic(err)
    }

    t := tokenizer.New()

    t.SetUserDic(udic)  // ← 使う前にセットしてください

    tokens := t.Analyze("寿司が食べたい。", tokenizer.Search)
    for _, token := range tokens {
        if token.Class == tokenizer.DUMMY {
            // BOS: Begin Of Sentence, EOS: End Of Sentence.
            fmt.Printf("%s\n", token.Surface)
            continue
        }
        features := strings.Join(token.Features(), ",")
        fmt.Printf("%s\t%v\n", token.Surface, features)
    }
}

おわりに

形態素解析結果についてもっと細かな調整をしたい!という要望もあるかなと思うのですが,これまで特に要望をもらったこともなかったのでユーザー辞書についてはそのままにしてきました.新しい形態素を拾いたいとか,辞書に載ってない形態素があって解析がいつもうまくいかない,とかそういったときにお役に立てば幸いです.

とはいえ,ユーザー辞書の形態素はコストを設定できないので,やはりご不満もあるかと思います.コストの設定までやってもいい気もするのですが,とりあえず単純なわかりやすい動作にしておく方がいいかなと思ってこうしてます.

最近話題の形態素解析器 Sudachi では,前処理や未知語処理,構築したラティスの最終調整についてそれぞれプラグインが書けるようになっているので,そういった細かなことがしたい場合にはこちらを使っていただくのがいいかもしれません.

実はアドベントカレンダー用に Sudachi の go 移植をしていたのですが,いろいろあって基本的な移植で止まっています.とりあえず動くところまではもってきたのですが,これはまたお正月とかに時間があれば進めたいと思います.

開発を阻むいろいろ→

Happy hacking!