Lindera

License: MIT Crates.io

Rust製の形態素解析ライブラリです。Linderaは kuromoji-rs からフォークされ、複数言語のテキストトークナイズに対して、簡単なインストールと簡潔なAPIの提供を目指しています。

主な機能

機能説明
形態素解析Viterbiベースの分割と品詞タグ付け
多言語サポート日本語(IPADIC、IPADIC NEologd、UniDic)、韓国語(ko-dic)、中国語(CC-CEDICT、Jieba)
辞書システムビルド済み辞書、ユーザー辞書、カスタム辞書学習
テキスト処理パイプライン柔軟なテキスト正規化のための組み合わせ可能なキャラクターフィルターとトークンフィルター
CRF学習辞書コスト推定のためのカスタムCRFモデルの学習
PythonバインディングPyO3を介してPythonからLinderaを利用可能
WebAssemblywasm-bindgenを介してブラウザでLinderaを実行可能
Pure RustC/C++依存なし。Rustがサポートするあらゆるプラットフォームで動作

トークナイズの流れ

graph LR
    subgraph Your Application
        T["Text"]
    end
    subgraph Lindera
        CF["Character Filters"]
        SEG["Segmenter\n(Dictionary + Viterbi)"]
        TF["Token Filters"]
    end
    T --> CF --> SEG --> TF --> R["Tokens"]

ドキュメントマップ

セクション説明
はじめにインストール、クイックスタート、サンプル
辞書利用可能な辞書とその使い方
設定YAMLベースのトークナイザー設定
応用的な使い方ユーザー辞書、フィルター、CRF学習
CLIコマンドラインインターフェースリファレンス
アーキテクチャクレート構成と設計の概要
APIリファレンスRust APIドキュメント
コントリビュートLinderaへの貢献方法

クイック例

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://ipadic")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let text = "関西国際空港限定トートバッグ";
    let mut tokens = tokenizer.tokenize(text)?;
    println!("text:\t{}", text);
    for token in tokens.iter_mut() {
        let details = token.details().join(",");
        println!("token:\t{}\t{}", token.surface.as_ref(), details);
    }

    Ok(())
}

上記の例は以下のように実行できます:

cargo run --features=embed-ipadic --example=tokenize

実行結果は以下のようになります:

text:   関西国際空港限定トートバッグ
token:  関西国際空港    名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
token:  限定    名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
token:  トートバッグ    名詞,一般,*,*,*,*,*,*,*

ライセンス

Linderaは MITライセンス の下で公開されています。

アーキテクチャ

Linderaは複数のクレートで構成されるCargo workspaceとして構成されています。各クレートは、低レベルのCRF計算から高レベルのCLIや言語バインディングまで、それぞれ明確な責務を持っています。

クレート依存関係図

graph TB
    CRF["lindera-crf\n(CRF Engine)"]
    DICT["lindera-dictionary\n(Dictionary Base)"]
    IPADIC["lindera-ipadic"]
    UNIDIC["lindera-unidic"]
    KODIC["lindera-ko-dic"]
    CCCEDICT["lindera-cc-cedict"]
    JIEBA["lindera-jieba"]
    NEOLOGD["lindera-ipadic-neologd"]
    LIB["lindera\n(Core Library)"]
    CLI["lindera-cli\n(CLI)"]
    PY["lindera-python\n(Python)"]
    WASM["lindera-wasm\n(WebAssembly)"]

    CRF --> DICT
    DICT --> IPADIC
    DICT --> UNIDIC
    DICT --> KODIC
    DICT --> CCCEDICT
    DICT --> JIEBA
    DICT --> NEOLOGD
    DICT --> LIB
    IPADIC --> LIB
    UNIDIC --> LIB
    KODIC --> LIB
    CCCEDICT --> LIB
    JIEBA --> LIB
    NEOLOGD --> LIB
    LIB --> CLI
    LIB --> PY
    LIB --> WASM

クレート一覧

クレート種類説明
lindera-crfコアPure RustによるCRF(条件付き確率場)実装。no_stdサポート。シリアライゼーションにrkyvを使用。
lindera-dictionaryコア辞書ベースライブラリ。辞書の読み込み、ビルド、学習機能(train featureで有効化)を提供。
linderaコアメインの形態素解析ライブラリ。辞書、セグメンター、キャラクターフィルター、トークンフィルターを統合。
lindera-cliアプリケーショントークナイズ、辞書ビルド、CRF学習のためのコマンドラインインターフェース。
lindera-ipadic辞書IPADICベースの日本語辞書。
lindera-ipadic-neologd辞書IPADIC NEologdベースの日本語辞書(新語対応)。
lindera-unidic辞書UniDicベースの日本語辞書。
lindera-ko-dic辞書ko-dicベースの韓国語辞書。
lindera-cc-cedict辞書CC-CEDICTベースの中国語辞書。
lindera-jieba辞書Jiebaベースの中国語辞書。
lindera-pythonバインディングPyO3を利用したPythonバインディング。
lindera-wasmバインディングwasm-bindgenを利用したWebAssemblyバインディング。

トークナイズパイプライン

Linderaは複数段階のパイプラインでテキストを処理します:

Input Text
  |
  v
Character Filters    -- Normalize characters (e.g., Unicode normalization, mapping)
  |
  v
Segmenter            -- Segment text into tokens using a dictionary and the Viterbi algorithm
  |
  v
Token Filters        -- Transform tokens (e.g., POS filtering, stop words, stemming)
  |
  v
Output Tokens

Segmenterがコアコンポーネントです。辞書から候補トークンのラティスを構築し、Viterbiアルゴリズムを適用して最小コストのパスを見つけ、最も適切な分割結果を生成します。

Featureフラグ

Feature説明デフォルト
mmap辞書読み込みのためのメモリマップドファイルサポート有効
trainCRFベースの辞書学習機能(lindera-crfに依存)CLIのみ
embed-ipadicIPADIC辞書をバイナリに埋め込み無効
embed-cjkIPADIC + ko-dic + Jieba辞書を埋め込み無効
embed-cjk2UniDic + ko-dic + Jieba辞書を埋め込み無効
embed-cjk3IPADIC NEologd + ko-dic + Jieba辞書を埋め込み無効

詳細

はじめに

このセクションでは、Linderaのインストールから最初の形態素解析の実行までをガイドします。

  • インストール -- プロジェクトへのLinderaの追加と環境変数の設定
  • クイックスタート -- わずか数行のコードで最初のテキストをトークナイズ
  • サンプル -- 一般的なユースケースのサンプルプログラムを探索

インストール

Cargo.tomlに以下を追加してください:

[dependencies]
lindera = "3.0.0"

辞書のセットアップ

Linderaの実行にはビルド済み辞書が必要です。GitHub Releases から辞書をダウンロードし、読み込み時にそのパスを指定してください:

#![allow(unused)]
fn main() {
let dictionary = load_dictionary("/path/to/ipadic")?;
}

[!TIP] 辞書をバイナリに直接埋め込みたい場合(上級者向け)は、対応する embed-* feature フラグを有効にしてビルドし、embedded:// スキームでロードしてください:

#![allow(unused)]
fn main() {
// Cargo.toml: lindera = { version = "3.0.0", features = ["embed-ipadic"] }
let dictionary = load_dictionary("embedded://ipadic")?;
}

詳細は Feature フラグ を参照してください。

環境変数

LINDERA_DICTIONARIES_PATH

LINDERA_DICTIONARIES_PATH 環境変数は、辞書ソースファイルをキャッシュするディレクトリを指定します。これにより以下のメリットがあります:

  • オフラインビルド: 一度ダウンロードすれば、将来のビルドのために辞書ソースファイルが保存されます
  • ビルドの高速化: 有効なキャッシュファイルが存在する場合、次回のビルドではダウンロードがスキップされます
  • 再現可能なビルド: ビルド間での辞書バージョンの一貫性を保ちます

使用方法:

export LINDERA_DICTIONARIES_PATH=/path/to/dicts
cargo build --features=ipadic

設定された場合、辞書ソースファイルは $LINDERA_DICTIONARIES_PATH/<version>/<version> は lindera-dictionary クレートのバージョン)に保存されます。キャッシュはMD5チェックサムを使用してファイルを検証し、無効なファイルは自動的に再ダウンロードされます。

[!NOTE] LINDERA_CACHE は非推奨ですが、後方互換性のために引き続きサポートされています。LINDERA_DICTIONARIES_PATH が設定されていない場合に使用されます。

LINDERA_CONFIG_PATH

LINDERA_CONFIG_PATH 環境変数は、トークナイザーの設定ファイル(YAML形式)へのパスを指定します。これにより、Rustコードを変更せずにトークナイザーの動作を設定できます。

export LINDERA_CONFIG_PATH=./resources/config/lindera.yml

設定フォーマットの詳細は 設定 セクションを参照してください。

DOCS_RS

DOCS_RS 環境変数は、docs.rsでドキュメントをビルドする際に自動的に設定されます。この変数が検出されると、Linderaは実際の辞書データをダウンロードする代わりにダミーの辞書ファイルを作成します。これにより、ネットワークアクセスや大容量ファイルのダウンロードなしでドキュメントをビルドできます。

これは主にdocs.rs内部で使用されるものであり、通常ユーザーが設定する必要はありません。

LINDERA_WORKDIR

LINDERA_WORKDIR 環境変数は、ビルドプロセス中に lindera-dictionary クレートによって自動的に設定されます。これはビルドされた辞書データファイルを含むディレクトリを指し、辞書クレートがデータファイルの場所を特定するために内部で使用されます。

この変数は自動的に設定されるため、ユーザーが変更する必要はありません。

クイックスタート

この例では、Linderaの基本的な使い方を説明します。

以下の処理を行います:

  • Normalモードでトークナイザーを作成
  • 入力テキストをトークナイズ(形態素解析)
  • トークンを出力

まず、GitHub Releases からビルド済みIPADIC辞書をダウンロードし、ローカルディレクトリ(例: /path/to/ipadic)に展開してください。

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("/path/to/ipadic")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let text = "関西国際空港限定トートバッグ";
    let mut tokens = tokenizer.tokenize(text)?;
    println!("text:\t{}", text);
    for token in tokens.iter_mut() {
        let details = token.details().join(",");
        println!("token:\t{}\t{}", token.surface.as_ref(), details);
    }

    Ok(())
}

上記の例は以下のように実行できます:

% cargo run --example=tokenize

[!TIP] embed-ipadic feature を使って辞書をバイナリに埋め込む場合(上級者向け)は、ファイルパスの代わりに load_dictionary("embedded://ipadic") を使用できます。詳細は Feature フラグ を参照してください。

実行結果は以下のようになります:

text:   関西国際空港限定トートバッグ
token:  関西国際空港    名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
token:  限定    名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
token:  トートバッグ    名詞,一般,*,*,*,*,*,*,*

サンプル

Linderaには、一般的なユースケースを示すいくつかのサンプルプログラムが含まれています。ソースコードはGitHubの examplesディレクトリ で確認できます。

サンプルを実行する前に、GitHub Releases からビルド済みIPADIC辞書をダウンロードし、ローカルディレクトリに展開してください。

利用可能なサンプル

tokenize

外部IPADIC辞書を使用した基本的なトークナイズです。入力テキストを分割し、各トークンの品詞情報を表示します。

cargo run --example=tokenize

tokenize_with_user_dict

ユーザー辞書を使用したトークナイズです。ドメイン固有の用語のために、辞書をカスタムエントリで補完する方法を示します。

cargo run --example=tokenize_with_user_dict

tokenize_with_filters

キャラクターフィルターとトークンフィルターを使用したトークナイズです。Unicode正規化、品詞フィルタリングなどの変換を含むテキスト処理パイプラインを実演します。

cargo run --example=tokenize_with_filters

tokenize_with_config

YAML設定ファイルを使用したトークナイズです。プログラムではなく宣言的にトークナイザーを設定する方法を示します。

cargo run --example=tokenize_with_config

基本概念

このセクションでは、Linderaの形態素解析システムの基本的な概念について説明します。

形態素解析

形態素解析とは

形態素解析とは、テキストを最小の意味単位(形態素)に分割し、その文法的特性を同定する処理です。日本語、中国語、韓国語のように単語がスペースで区切られない言語では、形態素解析は検索インデックス作成、テキスト分類、機械翻訳などの自然言語処理タスクにおいて不可欠な最初のステップです。

Linderaの仕組み

Linderaは辞書ベースの形態素解析器です。既知の単語とそのコストを含む事前コンパイル済みのシステム辞書を使用し、Viterbiアルゴリズムを適用して入力テキストの最適な分割を見つけます。

解析処理は以下のように動作します:

  1. ラティス構築: Linderaは入力テキストをスキャンし、各位置で辞書内のすべての候補単語を検索して、候補分割の有向非巡回グラフ(ラティス)を構築します。
  2. コスト割り当て: 各候補単語には(辞書からの)単語コストが関連付けられており、隣接する単語のペアには(連接コスト行列からの)連接コストが関連付けられています。
  3. 最適パス探索: Viterbiアルゴリズムがラティスを通る最小総コストのパスを見つけ、最適な分割結果を生成します。

主な用語

用語説明
表層形入力テキストに実際に現れるテキスト(例:"食べ")。
品詞(POS)単語の文法的カテゴリ(例:名詞、動詞、助詞)。Linderaの辞書は最大4階層のサブカテゴリを持つ階層的な品詞タグを提供します。
読み単語の発音。日本語辞書では通常カタカナで表記されます。
原形単語の非活用形(辞書形)(例:表層形"食べ"に対して"食べる")。
活用活用する単語の語形変化情報。活用型と活用形で構成されます。

コストベースの分割

Viterbiアルゴリズムは総コストが最小となる分割パスを選択します。パスの総コストは以下の合計です:

  • 単語コスト: 辞書内の各単語に関連付けられたコスト。コストが低いほど、その単語が出現する可能性が高いことを意味します。一般的な単語はコストが低く、まれな単語はコストが高い傾向があります。
  • 連接コスト: 隣接する2つの単語を接続するコスト。左側の単語の右文脈IDと右側の単語の左文脈IDによって決定されます。

アルゴリズムは以下を計算します:

Total cost = sum of word costs + sum of connection costs

この総コストを最小化することで、Linderaは入力テキストの最も自然な分割を見つけます。

連接コスト行列

連接コスト行列は、ある単語から別の単語への遷移コストを格納します。以下でインデックスされる2次元行列です:

  • 先行する単語の右文脈ID
  • 後続する単語の左文脈ID

これらの文脈IDは、単語境界に関する文法的情報をエンコードしています。例えば、名詞と助詞の間の連接コストは通常低く(自然な並び)、2つの動詞の基本形の間の連接コストは高くなります(不自然な並び)。

連接コスト行列は辞書ビルドプロセスの一部としてバイナリ形式にコンパイルされ、実行時に効率的な参照のために読み込まれます。

辞書

Linderaは、日本語・韓国語・中国語の形態素解析のための様々な辞書をサポートしています。各辞書は個別のクレートとして提供されます。

辞書言語クレート説明
IPADIC日本語lindera-ipadic日本語で最も一般的な辞書
IPADIC NEologd日本語lindera-ipadic-neologd新語に対応したIPADIC
UniDic日本語lindera-unidic均一な単語単位定義を持つ辞書
ko-dic韓国語lindera-ko-dic韓国語の形態素解析
CC-CEDICT中国語lindera-cc-cedict中英辞書
Jieba中国語lindera-jiebaJiebaベースの中国語辞書

辞書の入手方法

ビルド済み辞書は GitHub Releases からダウンロードできます。対象言語の辞書アーカイブをダウンロードし、ローカルディレクトリに展開してください。

#![allow(unused)]
fn main() {
// ローカルパスから外部辞書を読み込む
let dictionary = load_dictionary("/path/to/ipadic")?;
}

[!TIP] 外部辞書ファイルなしの自己完結型バイナリが必要な場合は、embed-* feature フラグを使って辞書を埋め込み、embedded:// スキームでロードできます:

#![allow(unused)]
fn main() {
let dictionary = load_dictionary("embedded://ipadic")?;
}

詳細は Feature フラグ を参照してください。

各辞書クレートのドキュメントで、フォーマット詳細、ビルド手順、使用例を参照してください。

トークナイズ

Linderaは複数のトークナイズモードを提供し、代替の分割候補を列挙するためのN-Best解析をサポートしています。

トークナイズモード

Normalモード

Normalモードは辞書エントリに基づく標準的なトークナイズを実行します。辞書に単一エントリとして存在する複合語はそのまま保持されます。

-- "関西国際空港限定トートバッグ" をNormalモードでトークナイズ:

関西国際空港 | 限定 | トートバッグ

複合名詞 "関西国際空港"(Kansai International Airport)は辞書に1つのエントリとして存在するため、単一トークンとして保持されます。

Decomposeモード

Decomposeモードは、複合語が辞書エントリとして存在する場合でも、さらに構成要素に分解します。

-- "関西国際空港限定トートバッグ" をDecomposeモードでトークナイズ:

関西 | 国際 | 空港 | 限定 | トートバッグ

複合語 "関西国際空港" は "関西"、"国際"、"空港" に分解されます。

モードの選択

Rustでは、Segmenterの作成時にモードを指定します:

#![allow(unused)]
fn main() {
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::dictionary::load_dictionary;

let dictionary = load_dictionary("embedded://ipadic")?;

// Normal mode
let segmenter = Segmenter::new(Mode::Normal, dictionary, None);

// Decompose mode
let segmenter = Segmenter::new(Mode::Decompose(Default::default()), dictionary, None);
}

CLIでは、--modeフラグを使用します:

echo "関西国際空港限定トートバッグ" | lindera tokenize --dict embedded://ipadic --mode normal
echo "関西国際空港限定トートバッグ" | lindera tokenize --dict embedded://ipadic --mode decompose

N-Bestトークナイズ

N-Bestトークナイズは、総パスコスト順(低コスト = より良い分割)に上位N件のトークナイズ候補を列挙します。最良の結果が曖昧な場合や、入力テキストの代替解釈を探索したい場合に有用です。

アルゴリズム

N-Bestトークナイズは**Forward-DP Backward-A***アルゴリズムに基づいており、MeCabのN-Best実装と互換性があります。フォワードパスは動的計画法で最適コストを計算し、バックワードパスはA*探索を使用して総コストの昇順にパスを列挙します。

パラメータ

tokenize_nbestメソッドは以下のパラメータを受け付けます:

パラメータ説明
text&strトークナイズするテキスト。
nusize返すN-best結果の数。
uniquebooltrueの場合、同じ単語境界位置を生成する結果を重複排除します。
cost_thresholdOption<i64>Some(threshold)の場合、best_cost + threshold以内のコストのパスのみを返します。

Rust APIの例

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://ipadic")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let text = "すもももももももものうち";

    // Get top 3 tokenization results
    let results = tokenizer.tokenize_nbest(text, 3, false, None)?;

    for (rank, (tokens, cost)) in results.iter().enumerate() {
        println!("--- NBEST {} (cost={}) ---", rank + 1, cost);
        for token in tokens {
            let details = token.details().join(",");
            println!("{}\t{}", token.surface.as_ref(), details);
        }
    }

    Ok(())
}

実行結果は以下のようになります:

--- NBEST 1 (cost=7546) ---
すもも  名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
うち    名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
--- NBEST 2 (cost=7914) ---
...

CLIの例

echo "すもももももももものうち" | lindera tokenize --dict embedded://ipadic -N 3

Latticeの再利用

繰り返しトークナイズを行う場合、Latticeを再利用してメモリ割り当てを削減できます:

#![allow(unused)]
fn main() {
use lindera_dictionary::viterbi::Lattice;

let mut lattice = Lattice::default();
let results = tokenizer.tokenize_nbest_with_lattice(text, &mut lattice, 3, false, None)?;
}

ユーザー辞書

ユーザー辞書は、システム辞書と併用してカスタム単語を登録できる補助辞書です。ドメイン固有の用語、ブランド名、固有名詞、またはデフォルトのシステム辞書に含まれていない単語を登録する場合に有用です。

CSVフォーマット

最もシンプルなユーザー辞書フォーマットは、3つのカラムを持つCSVファイルです:

<surface>,<part_of_speech>,<reading>

CSV内容の例

東京スカイツリー,カスタム名詞,トウキョウスカイツリー
東武スカイツリーライン,カスタム名詞,トウブスカイツリーライン
とうきょうスカイツリー駅,カスタム名詞,トウキョウスカイツリーエキ

各辞書タイプ(IPADIC、UniDic、ko-dicなど)は、文脈ID、コスト、すべての素性フィールドを完全に制御できる詳細CSVフォーマットもサポートしています。各辞書タイプの詳細フォーマットについては 辞書 セクションを参照してください。

Rust APIの例

use std::fs::File;
use std::path::PathBuf;

use lindera::dictionary::{Metadata, load_dictionary, load_user_dictionary};
use lindera::error::LinderaErrorKind;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let user_dict_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../resources")
        .join("user_dict")
        .join("ipadic_simple_userdic.csv");

    let metadata_file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../lindera-ipadic")
        .join("metadata.json");
    let metadata: Metadata = serde_json::from_reader(
        File::open(metadata_file)
            .map_err(|err| LinderaErrorKind::Io.with_error(anyhow::anyhow!(err)))
            .unwrap(),
    )
    .map_err(|err| LinderaErrorKind::Io.with_error(anyhow::anyhow!(err)))
    .unwrap();

    let dictionary = load_dictionary("embedded://ipadic")?;
    let user_dictionary = load_user_dictionary(user_dict_path.to_str().unwrap(), &metadata)?;
    let segmenter = Segmenter::new(
        Mode::Normal,
        dictionary,
        Some(user_dictionary), // Using the loaded user dictionary
    );

    // Create a tokenizer.
    let tokenizer = Tokenizer::new(segmenter);

    // Tokenize a text.
    let text = "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です";
    let mut tokens = tokenizer.tokenize(text)?;

    // Print the text and tokens.
    println!("text:\t{}", text);
    for token in tokens.iter_mut() {
        let details = token.details().join(",");
        println!("token:\t{}\t{}", token.surface.as_ref(), details);
    }

    Ok(())
}

実行結果は以下のようになります:

text:   東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です
token:  東京スカイツリー        カスタム名詞,*,*,*,*,*,東京スカイツリー,トウキョウスカイツリー,*
token:  の      助詞,連体化,*,*,*,*,の,ノ,ノ
token:  最寄り駅        名詞,一般,*,*,*,*,最寄り駅,モヨリエキ,モヨリエキ
token:  は      助詞,係助詞,*,*,*,*,は,ハ,ワ
token:  とうきょうスカイツリー駅        カスタム名詞,*,*,*,*,*,とうきょうスカイツリー駅,トウキョウスカイツリーエキ,*
token:  です    助動詞,*,*,*,特殊・デス,基本形,です,デス,デス

CLIでのユーザー辞書ビルド

CLIを使用して、CSVからバイナリ形式のユーザー辞書をビルドできます:

lindera build --src <source_dir> --dest <dest_dir> --metadata <metadata.json> --user

バイナリとCSVのユーザー辞書

  • CSVフォーマット: 実行時に読み込み・パースされます。開発時や小規模な辞書に便利です。
  • バイナリフォーマット: 高速な読み込みのために事前コンパイルされます。大規模なユーザー辞書を本番環境で使用する場合に推奨されます。

どちらのフォーマットもSegmenterの作成時に指定できます。バイナリフォーマットはCSVのパースステップをスキップするため、起動時間が短縮されます。

キャラクターフィルター

キャラクターフィルターは、トークナイズ前に入力テキストに適用される前処理ステップです。文字を正規化または変換して、トークナイズの品質と一貫性を向上させます。

利用可能なキャラクターフィルター

unicode_normalize

入力テキストにUnicode正規化を適用します。全角文字を半角に変換したり、等価なUnicode表現を正規化する場合に有用です。

サポートされている正規化形式:

形式説明
NFKC互換分解の後に正準合成を行います。全角英数字を半角に変換し、カタカナのバリエーションを正規化します。
NFC正準分解の後に正準合成を行います。
NFD正準分解を行います。
NFKD互換分解を行います。

japanese_iteration_mark

日本語の踊り字(繰り返し記号)を展開形に正規化します。踊り字は直前の文字の繰り返しを示す特殊な文字です。

記号名前
漢字の踊り字人々 (hitobito)
ゝ / ゞひらがなの踊り字いすゞ (isuzu)
ヽ / ヾカタカナの踊り字バナナヽ

このフィルターは2つのブール値パラメータを受け付けます:ひらがなの踊り字を正規化するかどうか、およびカタカナの踊り字を正規化するかどうかです。

mapping

ユーザー定義のマッピングテーブルに基づいて、文字レベルの文字列置換を実行します。カスタム正規化ルールに使用できます。

例えば、"リンデラ" を "Lindera" にマッピングします。

YAML設定の例

YAML設定ファイルでLinderaを使用する場合、キャラクターフィルターはcharacter_filtersセクションで指定できます:

segmenter:
  mode: normal
  dictionary: "embedded://ipadic"

character_filters:
  - kind: unicode_normalize
    args:
      kind: nfkc
  - kind: japanese_iteration_mark
    args:
      normalize_kanji: true
      normalize_kana: true
  - kind: mapping
    args:
      mapping:
        リンデラ: Lindera

Rust APIの例

キャラクターフィルターはプログラムから作成してTokenizerに追加できます:

use lindera::character_filter::BoxCharacterFilter;
use lindera::character_filter::unicode_normalize::{
    UnicodeNormalizeCharacterFilter, UnicodeNormalizeKind,
};
use lindera::character_filter::japanese_iteration_mark::JapaneseIterationMarkCharacterFilter;
use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://ipadic")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);

    // Create character filters.
    let unicode_normalize_char_filter =
        UnicodeNormalizeCharacterFilter::new(UnicodeNormalizeKind::NFKC);

    let japanese_iteration_mark_char_filter =
        JapaneseIterationMarkCharacterFilter::new(true, true);

    // Create a tokenizer and append character filters.
    let mut tokenizer = Tokenizer::new(segmenter);

    tokenizer
        .append_character_filter(BoxCharacterFilter::from(unicode_normalize_char_filter))
        .append_character_filter(BoxCharacterFilter::from(
            japanese_iteration_mark_char_filter,
        ));

    // Tokenize text -- full-width "Lindera" will be normalized to "Lindera".
    let text = "Linderaは形態素解析エンジンです。";
    let tokens = tokenizer.tokenize(text)?;

    for token in tokens {
        println!(
            "token: {:?}, details: {:?}",
            token.surface, token.details
        );
    }

    Ok(())
}

実行結果は以下のようになります(NFKC正規化適用後):

token: "Lindera", details: Some(["名詞", "固有名詞", "組織", "*", "*", "*", "*", "*", "*"])
token: "は", details: Some(["助詞", "係助詞", "*", "*", "*", "*", "は", "ハ", "ワ"])
token: "形態素", details: Some(["名詞", "一般", "*", "*", "*", "*", "形態素", "ケイタイソ", "ケイタイソ"])
token: "解析", details: Some(["名詞", "サ変接続", "*", "*", "*", "*", "解析", "カイセキ", "カイセキ"])
token: "エンジン", details: Some(["名詞", "一般", "*", "*", "*", "*", "エンジン", "エンジン", "エンジン"])
token: "です", details: Some(["助動詞", "*", "*", "*", "特殊・デス", "基本形", "です", "デス", "デス"])
token: "。", details: Some(["記号", "句点", "*", "*", "*", "*", "。", "。", "。"])

Lindera CRF

Lindera CRFは、rucrfからフォークされたConditional Random Fields(CRF)のpure Rust実装です。ラティス構造をサポートしたCRFの学習器と推定器を提供します。

主な特徴

  • 可変長エッジを持つラティス構造
  • L1、L2、およびElastic Net正則化
  • マルチスレッド学習
  • rkyvによるゼロコピーデシリアライゼーション
  • no_stdサポート(train featureなしの場合)

目次

rucrfからの変更点

  • シリアライゼーションバックエンド: ゼロコピーデシリアライゼーションのため、bincodeからrkyvに変更
  • Elastic Net正則化: L1とL2のペナルティを組み合わせたRegularization::ElasticNetを追加
  • Rust 2024 edition: Rust 2024 editionに更新
  • 依存クレートの更新: argminargmin-mathhashbrownなどを更新

アーキテクチャ

モジュール構成

lindera-crf/src/
├── lib.rs                # パブリックAPIの再エクスポート
├── feature.rs            # FeatureSet, FeatureProvider
├── lattice.rs            # Edge, Node, Lattice
├── model.rs              # RawModel, MergedModel, Model trait
├── trainer.rs            # Trainer, Regularization enum
├── errors.rs             # エラー型
├── forward_backward.rs   # 前向き・後向きアルゴリズム
├── math.rs               # 数学ユーティリティ (logsumexp)
├── optimizers/
│   └── lbfgs.rs          # L-BFGS最適化
└── utils.rs              # ユーティリティtrait

主要コンポーネント

FeatureProvider / FeatureSet

ラベルごとの素性セットを管理します。各FeatureSetは、指定されたラベルのユニグラム素性と左右のバイグラム素性を保持します。FeatureProviderFeatureSetインスタンスを集約し、素性IDから重みへのマッピングを行います。

Lattice / Edge / Node

系列ラベリングのための可変長エッジを持つラティス構造です。Edgeはラベル付きの候補スパンを表し、Nodeは特定の位置にあるエッジを集約します。Latticeは入力データから構築され、モデルが最適パスを探索するために使用されます。

Trainer

設定可能な正則化を用いたL-BFGS最適化によりCRFモデルを学習します。Trainerはラベル付きラティスの例を受け取り、前向き・後向きアルゴリズムで勾配を計算し、反復的にモデルの重みを更新します。

Regularization

設定可能な正則化戦略:

  • L1: L1ペナルティによるスパースモデル
  • L2: L2ペナルティによる滑らかなモデル
  • ElasticNet: L1とL2を設定可能なl1_ratioで組み合わせ

Model (trait)

ラティスを通じて最適パスを探索するためのインターフェースです。2つの実装が提供されています:

  • RawModel: 素性IDでインデックスされたフラットベクトルに重みを格納
  • MergedModel: 推論に最適化され、素性の重みをrkyvでシリアライズ可能なコンパクトな表現にマージ

前向き・後向きアルゴリズム

ラティス上でアルファ(前向き)とベータ(後向き)の値を計算します。学習時に期待素性カウントと勾配の計算に使用されます。

Feature フラグ

Feature説明デフォルト
allocno_std向けのallocサポートNo
std標準ライブラリサポート(allocを含む)No
train学習機能(L-BFGS、マルチスレッド、ログ出力)Yes

APIリファレンス

APIリファレンスは以下で公開されています:

Lindera Dictionary

Lindera Dictionaryは、形態素解析辞書のベースライブラリです。辞書の読み込み、ビルド、Viterbiベースのセグメンテーション、およびCRFベースの学習機能を提供します。

主な特徴

  • ファイルシステムまたは埋め込みデータからの辞書読み込み
  • MeCab形式のCSVソースファイルからの辞書ビルド
  • 最適なセグメンテーションのためのViterbiアルゴリズム
  • N-bestパス生成(Forward-DP Backward-A*)
  • メモリマップドファイルサポート
  • CRFベースの辞書学習(train feature使用時)

目次

アーキテクチャ

モジュール構成

lindera-dictionary/src/
├── lib.rs               # パブリックAPI
├── dictionary.rs        # Dictionary, UserDictionary
├── builder.rs           # DictionaryBuilder
├── loader.rs            # DictionaryLoader trait, FSDictionaryLoader
├── viterbi.rs           # Lattice, Edge, Viterbiセグメンテーション
├── nbest.rs             # NBestGenerator (Forward-DP Backward-A*)
├── mode.rs              # Mode (Normal/Decompose), Penalty
├── error.rs             # LinderaError, LinderaErrorKind
├── assets.rs            # ダウンロードとファイル管理
├── dictionary/
│   ├── character_definition.rs    # 文字種定義
│   ├── connection_cost_matrix.rs  # 連接コスト行列
│   ├── prefix_dictionary.rs       # ダブル配列トライ辞書
│   ├── unknown_dictionary.rs      # 未知語処理
│   ├── metadata.rs                # 辞書メタデータ
│   └── schema.rs                  # スキーマ定義
└── trainer/             # (train feature)
    ├── config.rs        # TrainerConfig
    ├── corpus.rs        # Corpus, Example, Word
    ├── feature_extractor.rs  # 素性テンプレート解析
    ├── feature_rewriter.rs   # MeCab互換リライトルール
    └── model.rs         # 学習済みモデル, tocost()

主要コンポーネント

Dictionary / UserDictionary

コンパイル済み辞書データを保持する主要データ構造です。Dictionaryは文字種定義、連接コスト行列、前方一致辞書(ダブル配列トライ)、および未知語辞書を含みます。UserDictionaryを使用すると、システム辞書の上にカスタム語彙を追加できます。

DictionaryBuilder

ソースCSVファイルから辞書をビルドするためのFluent APIです。MeCab形式の辞書ソースを、実行時に使用されるバイナリ形式にコンパイルします。

DictionaryLoader / FSDictionaryLoader

DictionaryLoaderはコンパイル済み辞書を読み込むためのtraitです。FSDictionaryLoaderはファイルシステムベースの実装で、ディレクトリから辞書ファイルを読み込みます。オプションでメモリマップドファイルをサポートします。

Viterbi (Lattice, Edge)

入力テキストから候補トークンのラティスを構築し、Viterbiアルゴリズムを使用して最適なセグメンテーションパスを探索します。ラティス内の各Edgeは、関連するコスト(単語コスト + 連接コスト)を持つ候補トークンを表します。

NBestGenerator

Forward-DP Backward-A*アルゴリズムを使用してN-bestセグメンテーションパスを生成します。これにより、アプリケーションは単一の最適パスを超えた代替セグメンテーションを検討できます。

Mode

トークナイゼーションの動作を制御します:

  • Normal: 最適なViterbiパスを使用した標準的なトークナイゼーション
  • Decompose: 設定可能なPenalty閾値に基づいて複合名詞をさらに分割

Trainer (train feature)

lindera-crfを使用したCRFベースの辞書学習パイプラインです。学習ワークフローには以下が含まれます:

  1. TrainerConfig: 種辞書、char.deffeature.defrewrite.defを解析
  2. Corpus: ラベル付き例として学習データを管理
  3. FeatureExtractor: 素性テンプレートを解析し、素性IDを割り当て
  4. DictionaryRewriter: MeCab互換の3セクションリライトルールを適用
  5. Model: 学習結果を保持し、tocost(weight, cost_factor)によるコスト変換で辞書ファイルを出力

Featureフラグ

Feature説明デフォルト
mmapメモリマップドファイルサポートYes
build_rs辞書ソースのHTTPダウンロードNo
trainCRFベースの学習(lindera-crfに依存)No

APIリファレンス

APIリファレンスは以下で公開されています:

Lindera ライブラリ

lindera クレートは形態素解析のコアライブラリです。このセクションでは、設定、セグメンテーション、Token Filter、エラーハンドリング、APIリファレンスについて説明します。

設定

LinderaはYAML形式の設定ファイルを読み込むことができます。 環境変数 LINDERA_CONFIG_PATH にファイルのパスを指定してください。Rustコードでトークナイザーの動作をコーディングすることなく、簡単に利用できます。

segmenter:
  mode: "normal"
  dictionary: "embedded://ipadic"
  # user_dictionary: "./resources/user_dict/ipadic_simple_userdic.csv"

character_filters:
  - kind: "unicode_normalize"
    args:
      kind: "nfkc"
  - kind: "japanese_iteration_mark"
    args:
      normalize_kanji: true
      normalize_kana: true
  - kind: mapping
    args:
       mapping:
         リンデラ: Lindera

token_filters:
  - kind: "japanese_compound_word"
    args:
      tags:
        - "名詞,数"
        - "名詞,接尾,助数詞"
      new_tag: "名詞,数"
  - kind: "japanese_number"
    args:
      tags:
        - "名詞,数"
  - kind: "japanese_stop_tags"
    args:
      tags:
        - "接続詞"
        - "助詞"
        - "助詞,格助詞"
        - "助詞,格助詞,一般"
        - "助詞,格助詞,引用"
        - "助詞,格助詞,連語"
        - "助詞,係助詞"
        - "助詞,副助詞"
        - "助詞,間投助詞"
        - "助詞,並立助詞"
        - "助詞,終助詞"
        - "助詞,副助詞/並立助詞/終助詞"
        - "助詞,連体化"
        - "助詞,副詞化"
        - "助詞,特殊"
        - "助動詞"
        - "記号"
        - "記号,一般"
        - "記号,読点"
        - "記号,句点"
        - "記号,空白"
        - "記号,括弧閉"
        - "その他,間投"
        - "フィラー"
        - "非言語音"
  - kind: "japanese_katakana_stem"
    args:
      min: 3
  - kind: "remove_diacritical_mark"
    args:
      japanese: false
% export LINDERA_CONFIG_PATH=./resources/config/lindera.yml
use std::path::PathBuf;

use lindera::tokenizer::TokenizerBuilder;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    // 設定ファイルからトークナイザーの設定を読み込む
    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../resources")
        .join("config")
        .join("lindera.yml");

    let builder = TokenizerBuilder::from_file(&path)?;

    let tokenizer = builder.build()?;

    let text = "Linderaは形態素解析エンジンです。ユーザー辞書も利用可能です。".to_string();
    println!("text: {text}");

    let tokens = tokenizer.tokenize(&text)?;

    for token in tokens {
        println!(
            "token: {:?}, start: {:?}, end: {:?}, details: {:?}",
            token.surface, token.byte_start, token.byte_end, token.details
        );
    }

    Ok(())
}

Segmenter

Segmenter は形態素解析を実行するコアコンポーネントです。辞書とコストモデルに基づいて、入力テキストの最適な分割を Viterbi アルゴリズムで探索します。

Segmenter の作成

Segmenter には以下の3つのコンポーネントが必要です:

  • Mode - トークナイズ戦略(Normal または Decompose
  • Dictionary - 形態素解析用のシステム辞書
  • UserDictionary(オプション) - カスタム単語用の補助辞書
#![allow(unused)]
fn main() {
use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;

let dictionary = load_dictionary("embedded://ipadic")?;
let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
}

トークナイズモード

Mode::Normal

辞書に登録されたエントリに基づく標準的なトークナイズです。辞書に登録された単語に忠実に分割します。

#![allow(unused)]
fn main() {
use lindera::mode::Mode;

let mode = Mode::Normal;
}

Mode::Decompose

複合名詞を構成要素に分解します。このモードでは、長い複合語にペナルティを適用し、Segmenter がより短い構成要素に分割するよう促します。

例えば、Mode::Normal では複合語「関西国際空港」は1つのトークンのままですが、Mode::Decompose では「関西」「国際」「空港」に分割されます。

#![allow(unused)]
fn main() {
use lindera::mode::Mode;

let mode = Mode::Decompose(Default::default());
}

辞書の読み込み

Lindera は様々なソースから辞書を読み込むための load_dictionary 関数を提供しています。

埋め込み辞書

適切な Feature フラグ(例: embed-ipadic)を指定してビルドすると、バイナリから直接辞書を読み込むことができます:

#![allow(unused)]
fn main() {
use lindera::dictionary::load_dictionary;

let dictionary = load_dictionary("embedded://ipadic")?;
}

利用可能な埋め込み辞書URI:

  • embedded://ipadic - IPADIC(日本語)
  • embedded://ipadic-neologd - IPADIC NEologd(日本語)
  • embedded://unidic - UniDic(日本語)
  • embedded://ko-dic - ko-dic(韓国語)
  • embedded://cc-cedict - CC-CEDICT(中国語)
  • embedded://jieba - Jieba(中国語)

外部辞書

ビルド済みの辞書ディレクトリをファイルシステムから読み込むことができます:

#![allow(unused)]
fn main() {
use lindera::dictionary::load_dictionary;

let dictionary = load_dictionary("/path/to/dictionary")?;
}

Tokenizer との連携

Segmenter は通常、Character Filter と Token Filter のサポートを追加する Tokenizer を通じて使用されます:

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://ipadic")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let text = "日本語の形態素解析を行うことができます。";
    let tokens = tokenizer.tokenize(text)?;

    for token in tokens {
        let details = token.details().join(",");
        println!("{}\t{}", token.surface.as_ref(), details);
    }

    Ok(())
}

Token Filter

Token Filter はセグメンテーション後のトークンに適用される後処理コンポーネントです。検索インデックス作成、テキスト正規化、言語解析などの用途に合わせて、トークンの変更、削除、変換を行うことができます。

利用可能な Token Filter

日本語

Filter説明
japanese_compound_word指定した品詞タグに一致する連続トークンを複合語に結合
japanese_number日本語の数値表現を正規化(例: 漢数字の変換)
japanese_stop_tags指定した品詞タグを持つトークンを除去
japanese_katakana_stemカタカナ語の末尾の長音記号を除去してステミング
japanese_base_formトークンを原形(辞書形)に正規化
japanese_keep_tags指定した品詞タグに一致するトークンのみを保持し、それ以外を除去
japanese_reading_formトークンテキストを読み形式(カタカナ)に変換
japanese_kanaひらがなとカタカナを相互変換

韓国語

Filter説明
korean_stop_tags指定した品詞タグを持つ韓国語トークンを除去
korean_keep_tags指定した品詞タグに一致する韓国語トークンのみを保持
korean_reading_form韓国語トークンを読み形式に変換

汎用

Filter説明
lowercaseトークンテキストを小文字に変換
uppercaseトークンテキストを大文字に変換
mappingユーザー定義のマッピングテーブルに従ってトークンテキストを変換
lengthテキスト長(最小値および/または最大値)でトークンをフィルタリング
stop_wordsストップワードリストに一致するトークンを除去
keep_words指定した単語リストに一致するトークンのみを保持
remove_diacritical_markトークンテキストからダイアクリティカルマーク(アクセント記号)を除去

YAML設定

Token Filter はYAML設定ファイルの token_filters キーで設定できます:

token_filters:
  - kind: "japanese_stop_tags"
    args:
      tags:
        - "助詞"
        - "助動詞"
        - "記号"
  - kind: "japanese_katakana_stem"
    args:
      min: 3
  - kind: "lowercase"
  - kind: "length"
    args:
      min: 2

Rust API

Token Filter はプログラムから作成・適用することもできます:

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::token_filter::BoxTokenFilter;
use lindera::token_filter::japanese_stop_tags::JapaneseStopTagsTokenFilter;
use lindera::token_filter::japanese_katakana_stem::JapaneseKatakanaStemTokenFilter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://ipadic")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);

    let mut tokenizer = Tokenizer::new(segmenter);

    // Token Filter を追加
    let stop_tags_filter = JapaneseStopTagsTokenFilter::new(
        vec![
            "助詞".to_string(),
            "助動詞".to_string(),
            "記号".to_string(),
        ]
        .into_iter()
        .collect(),
    );
    tokenizer.append_token_filter(BoxTokenFilter::from(stop_tags_filter));

    let katakana_stem_filter = JapaneseKatakanaStemTokenFilter::new(3);
    tokenizer.append_token_filter(BoxTokenFilter::from(katakana_stem_filter));

    // フィルタを適用してトークナイズ
    let tokens = tokenizer.tokenize("Linderaは形態素解析エンジンです。")?;

    for token in tokens {
        println!(
            "token: {:?}, details: {:?}",
            token.surface, token.details
        );
    }

    Ok(())
}

append_token_filter メソッドはフィルタを順番に追加します。フィルタはセグメンテーション後のトークンリストに対して順次適用されます。

エラーハンドリング

Lindera はライブラリ全体で使いやすいエラーハンドリングを実現するため、anyhowthiserror に基づく構造化されたエラーシステムを使用しています。

LinderaResult

LinderaResult<T> 型エイリアスは、Lindera における失敗する可能性のある操作の標準的な戻り値型です:

#![allow(unused)]
fn main() {
pub type LinderaResult<T> = Result<T, LinderaError>;
}

LinderaError

LinderaError はメインのエラー型で、エラー種別と完全なコンテキストを持つソースエラーを含みます:

#![allow(unused)]
fn main() {
pub struct LinderaError {
    pub kind: LinderaErrorKind,
    source: anyhow::Error,
}
}

add_context メソッドを使用して、エラーに追加のコンテキストを付与できます:

#![allow(unused)]
fn main() {
let error = error.add_context("failed to load dictionary from /path/to/dict");
}

LinderaErrorKind

LinderaErrorKind はエラーを分類する列挙型です:

Kind説明
IoI/Oエラー(ファイルの読み書き、ネットワーク)
Parseパースエラー(無効な入力形式)
Serializeシリアライズエラー
Deserializeデシリアライズエラー
Content無効なコンテンツまたはデータのエラー
Args無効な引数のエラー
Decodeデコードエラー
Compression圧縮・解凍エラー
NotFoundリソースが見つからない(例: 辞書ファイルの欠落)
Build辞書ビルドエラー
Dictionary辞書関連のエラー
Mode無効なトークナイズモードのエラー
Algorithmアルゴリズムエラー(例: Viterbi の失敗)
FeatureDisabled有効化されていない機能を使用しようとした

エラーの作成

LinderaErrorKind::with_error を使用して、種別とソースからエラーを作成します:

#![allow(unused)]
fn main() {
use lindera::error::LinderaErrorKind;

let error = LinderaErrorKind::Io.with_error(anyhow::anyhow!("file not found: config.yml"));
}

? 演算子の使用

Lindera の関数は LinderaResult を返すため、? 演算子で自然にエラーを伝播できます:

#![allow(unused)]
fn main() {
use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn analyze(text: &str) -> LinderaResult<Vec<String>> {
    let dictionary = load_dictionary("embedded://ipadic")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let tokens = tokenizer.tokenize(text)?;
    Ok(tokens.iter().map(|t| t.surface.as_ref().to_string()).collect())
}
}

エラーハンドリングパターン

エラー種別によるマッチング

#![allow(unused)]
fn main() {
use lindera::dictionary::load_dictionary;
use lindera::error::LinderaErrorKind;

match load_dictionary("/path/to/dictionary") {
    Ok(dict) => { /* 辞書を使用 */ }
    Err(e) if e.kind() == LinderaErrorKind::NotFound => {
        eprintln!("Dictionary not found: {}", e);
    }
    Err(e) if e.kind() == LinderaErrorKind::Io => {
        eprintln!("I/O error loading dictionary: {}", e);
    }
    Err(e) => {
        eprintln!("Unexpected error: {}", e);
    }
}
}

外部エラーからの変換

#![allow(unused)]
fn main() {
use lindera::error::LinderaErrorKind;

let content = std::fs::read_to_string("config.yml")
    .map_err(|err| LinderaErrorKind::Io.with_error(anyhow::anyhow!(err)))?;
}

APIリファレンス

APIリファレンスは以下で公開されています:

Lindera CLI

Lindera のための形態素解析コマンドラインインターフェースです。

インストール

cargo経由でインストール

cargo経由でバイナリをインストールできます:

% cargo install lindera-cli

GitHub Releasesからダウンロード

または、以下のリリースページからビルド済みバイナリをダウンロードすることもできます:

辞書の入手

Lindera はバイナリに辞書を同梱していません。GitHub Releases ページからビルド済み辞書を別途ダウンロードする必要があります:

# 例: IPADIC 辞書のダウンロードと展開
% curl -LO https://github.com/lindera/lindera/releases/download/<version>/lindera-ipadic-<version>.zip
% unzip lindera-ipadic-<version>.zip -d /path/to/ipadic

CLI 使用時に辞書パスを指定します:

% lindera tokenize --dictionary /path/to/ipadic "関西国際空港限定トートバッグ"

ソースからビルド

辞書なしでビルド(デフォルト)

辞書を埋め込まず、トークナイザーとトレーナーのみを含むバイナリをビルドします:

% cargo build --release

全機能を含めてビルド

% cargo build --release --all-features

辞書埋め込みビルド(上級者向け)

辞書をバイナリに直接埋め込みたい上級者向けに、embed-* feature フラグを使用できます。実行時の外部辞書ファイルが不要になりますが、バイナリサイズが増加します。

IPADIC(日本語辞書)

% cargo build --release --features=embed-ipadic

IPADIC NEologd(日本語辞書)

% cargo build --release --features=embed-ipadic-neologd

UniDic(日本語辞書)

% cargo build --release --features=embed-unidic

ko-dic(韓国語辞書)

% cargo build --release --features=embed-ko-dic

CC-CEDICT(中国語辞書)

% cargo build --release --features=embed-cc-cedict

Jieba(中国語辞書)

% cargo build --release --features=embed-jieba

[!TIP] embed-* feature フラグ付きでビルドした後、embedded:// スキームで埋め込み辞書をロードできます:

% lindera tokenize --dictionary embedded://ipadic "関西国際空港限定トートバッグ"

詳細は Feature フラグ を参照してください。

コマンド

Lindera CLI は4つのメインコマンドを提供します:

  • tokenize - テキストに対して形態素解析を実行
  • build - ソースCSVファイルから辞書をビルド
  • train - 注釈付きコーパスデータからCRFモデルを学習
  • export - 学習済みモデルを辞書フォーマットにエクスポート

tokenize

様々な辞書を使用して、日本語、中国語、または韓国語のテキストに対して形態素解析(トークナイズ)を行います。

パラメータ

  • --dict / -d: 辞書のパスまたはURI(必須)
    • ファイルパス: /path/to/dictionary
    • 埋め込み: embedded://ipadic, embedded://unidic, etc.
  • --output / -o: 出力形式 (デフォルト: mecab)
    • mecab: 品詞情報を含むMeCab互換形式
    • wakati: スペース区切りのトークンのみ
    • json: すべてのトークン情報を含む詳細なJSON形式
  • --user-dict / -u: ユーザー辞書のパス(オプション)
  • --mode / -m: トークナイズモード (デフォルト: normal)
    • normal: 標準的なトークナイズ
    • decompose: 複合語を分解する
  • --char-filter / -c: 文字フィルタ設定 (JSON)
  • --token-filter / -t: トークンフィルタ設定 (JSON)
  • --nbest / -N: 返す N-best 結果の数(デフォルト: 1)。2以上に設定すると N-best 出力が有効になります。
  • --nbest-unique: 同じ分割を生成するパスの重複を排除します。
  • --nbest-cost-threshold: 最良パスからの最大コスト差。best_cost + threshold 以内のコストを持つパスのみが返されます。
  • 入力ファイル: オプションのファイルパス (デフォルト: 標準入力)

基本的な使用方法

# 辞書ディレクトリを指定してトークナイズ
echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict /path/to/dictionary

# 埋め込み辞書を指定してトークナイズ
echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict embedded://ipadic

# 出力形式を指定してトークナイズ
echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict embedded://ipadic \
  --output json

# ファイルからテキストを読み込んでトークナイズ
lindera tokenize \
  --dict /path/to/dictionary \
  --output wakati \
  input.txt

外部辞書を使用した例

外部IPADIC(日本語辞書)を使用したトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict /tmp/lindera-ipadic-2.7.0-20250920
日本語  名詞,一般,*,*,*,*,日本語,ニホンゴ,ニホンゴ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
行う    動詞,自立,*,*,五段・ワ行促音便,基本形,行う,オコナウ,オコナウ
こと    名詞,非自立,一般,*,*,*,こと,コト,コト
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
でき    動詞,自立,*,*,一段,連用形,できる,デキ,デキ
ます    助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。      記号,句点,*,*,*,*,。,。,。
EOS

外部IPADIC NEologd(日本語辞書)を使用したトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict /tmp/lindera-ipadic-neologd-0.0.7-20200820
日本語  名詞,一般,*,*,*,*,日本語,ニホンゴ,ニホンゴ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
形態素解析      名詞,固有名詞,一般,*,*,*,形態素解析,ケイタイソカイセキ,ケイタイソカイセキ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
行う    動詞,自立,*,*,五段・ワ行促音便,基本形,行う,オコナウ,オコナウ
こと    名詞,非自立,一般,*,*,*,こと,コト,コト
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
でき    動詞,自立,*,*,一段,連用形,できる,デキ,デキ
ます    助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。      記号,句点,*,*,*,*,。,。,。
EOS

外部UniDic(日本語辞書)を使用したトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict /tmp/lindera-unidic-2.1.2
日本    名詞,固有名詞,地名,国,*,*,ニッポン,日本,日本,ニッポン,日本,ニッポン,固,*,*,*,*
語      名詞,普通名詞,一般,*,*,*,ゴ,語,語,ゴ,語,ゴ,漢,*,*,*,*
の      助詞,格助詞,*,*,*,*,ノ,の,の,ノ,の,ノ,和,*,*,*,*
形態    名詞,普通名詞,一般,*,*,*,ケイタイ,形態,形態,ケータイ,形態,ケータイ,漢,*,*,*,*
素      接尾辞,名詞的,一般,*,*,*,ソ,素,素,ソ,素,ソ,漢,*,*,*,*
解析    名詞,普通名詞,サ変可能,*,*,*,カイセキ,解析,解析,カイセキ,解析,カイセキ,漢,*,*,*,*
を      助詞,格助詞,*,*,*,*,ヲ,を,を,オ,を,オ,和,*,*,*,*
行う    動詞,一般,*,*,五段-ワア行,連体形-一般,オコナウ,行う,行う,オコナウ,行う,オコナウ,和,*,*,*,*
こと    名詞,普通名詞,一般,*,*,*,コト,事,こと,コト,こと,コト,和,コ濁,基本形,*,*
が      助詞,格助詞,*,*,*,*,ガ,が,が,ガ,が,ガ,和,*,*,*,*
でき    動詞,非自立可能,*,*,上一段-カ行,連用形-一般,デキル,出来る,でき,デキ,できる,デキル,和,*,*,*,*
ます    助動詞,*,*,*,助動詞-マス,終止形-一般,マス,ます,ます,マス,ます,マス,和,*,*,*,*
。      補助記号,句点,*,*,*,*,,。,。,,。,,記号,*,*,*,*
EOS

外部ko-dic(韓国語辞書)を使用したトークナイズ

% echo "한국어의형태해석을실시할수있습니다." | lindera tokenize \
  --dict /tmp/lindera-ko-dic-2.1.1-20180720
한국어  NNG,*,F,한국어,Compound,*,*,한국/NNG/*+어/NNG/*
의      JKG,*,F,의,*,*,*,*
형태    NNG,*,F,형태,*,*,*,*
해석    NNG,행위,T,해석,*,*,*,*
을      JKO,*,T,을,*,*,*,*
실시    NNG,행위,F,실시,*,*,*,*
할      XSV+ETM,*,T,할,Inflect,XSV,ETM,하/XSV/*+ᆯ/ETM/*
수      NNB,*,F,수,*,*,*,*
있      VV,*,T,있,*,*,*,*
습니다  EF,*,F,습니다,*,*,*,*
.       SF,*,*,*,*,*,*,*
EOS

外部CC-CEDICT(中国語辞書)を使用したトークナイズ

% echo "可以进行中文形态学分析。" | lindera tokenize \
  --dict /tmp/lindera-cc-cedict-0.1.0-20200409
可以    *,*,*,*,ke3 yi3,可以,可以,can/may/possible/able to/not bad/pretty good/
进行    *,*,*,*,jin4 xing2,進行,进行,to advance/to conduct/underway/in progress/to do/to carry out/to carry on/to execute/
中文    *,*,*,*,Zhong1 wen2,中文,中文,Chinese language/
形态学  *,*,*,*,xing2 tai4 xue2,形態學,形态学,morphology (in biology or linguistics)/
分析    *,*,*,*,fen1 xi1,分析,分析,to analyze/analysis/CL:個|个[ge4]/
。      *,*,*,*,*,*,*,*
EOS

外部Jieba(中国語辞書)を使用したトークナイズ

% echo "可以进行中文形态学分析。" | lindera tokenize \
  --dict /tmp/lindera-jieba-0.1.1

埋め込み辞書を使用した例

Linderaは、特定の機能フラグを指定してビルドすることで、バイナリに辞書を直接含めることができます。これにより、外部辞書ファイルなしでトークナイズが可能になります。

埋め込みIPADIC(日本語辞書)を使用したトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict embedded://ipadic
日本語  名詞,一般,*,*,*,*,日本語,ニホンゴ,ニホンゴ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
行う    動詞,自立,*,*,五段・ワ行促音便,基本形,行う,オコナウ,オコナウ
こと    名詞,非自立,一般,*,*,*,こと,コト,コト
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
でき    動詞,自立,*,*,一段,連用形,できる,デキ,デキ
ます    助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。      記号,句点,*,*,*,*,。,。,。
EOS

注意: IPADIC辞書をバイナリに含めるには、--features=embed-ipadic オプションを使用してビルドする必要があります。

埋め込みUniDic(日本語辞書)を使用したトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict embedded://unidic
日本    名詞,固有名詞,地名,国,*,*,ニッポン,日本,日本,ニッポン,日本,ニッポン,固,*,*,*,*
語      名詞,普通名詞,一般,*,*,*,ゴ,語,語,ゴ,語,ゴ,漢,*,*,*,*
の      助詞,格助詞,*,*,*,*,ノ,の,の,ノ,の,ノ,和,*,*,*,*
形態    名詞,普通名詞,一般,*,*,*,ケイタイ,形態,形態,ケータイ,形態,ケータイ,漢,*,*,*,*
素      接尾辞,名詞的,一般,*,*,*,ソ,素,素,ソ,素,ソ,漢,*,*,*,*
解析    名詞,普通名詞,サ変可能,*,*,*,カイセキ,解析,解析,カイセキ,解析,カイセキ,漢,*,*,*,*
を      助詞,格助詞,*,*,*,*,ヲ,を,を,オ,を,オ,和,*,*,*,*
行う    動詞,一般,*,*,五段-ワア行,連体形-一般,オコナウ,行う,行う,オコナウ,行う,オコナウ,和,*,*,*,*
こと    名詞,普通名詞,一般,*,*,*,コト,事,こと,コト,こと,コト,和,コ濁,基本形,*,*
が      助詞,格助詞,*,*,*,*,ガ,が,が,ガ,が,ガ,和,*,*,*,*
でき    動詞,非自立可能,*,*,上一段-カ行,連用形-一般,デキル,出来る,でき,デキ,できる,デキル,和,*,*,*,*
ます    助動詞,*,*,*,助動詞-マス,終止形-一般,マス,ます,ます,マス,ます,マス,和,*,*,*,*
。      補助記号,句点,*,*,*,*,,。,。,,。,,記号,*,*,*,*
EOS

注意: UniDic辞書をバイナリに含めるには、--features=embed-unidic オプションを使用してビルドする必要があります。

埋め込みIPADIC NEologd(日本語辞書)を使用したトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict embedded://ipadic-neologd
日本語  名詞,一般,*,*,*,*,日本語,ニホンゴ,ニホンゴ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
形態素解析      名詞,固有名詞,一般,*,*,*,形態素解析,ケイタイソカイセキ,ケイタイソカイセキ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
行う    動詞,自立,*,*,五段・ワ行促音便,基本形,行う,オコナウ,オコナウ
こと    名詞,非自立,一般,*,*,*,こと,コト,コト
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
でき    動詞,自立,*,*,一段,連用形,できる,デキ,デキ
ます    助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。      記号,句点,*,*,*,*,。,。,。
EOS

注意: IPADIC NEologd辞書をバイナリに含めるには、--features=embed-ipadic-neologd オプションを使用してビルドする必要があります。

埋め込みko-dic(韓国語辞書)を使用したトークナイズ

% echo "한국어의형태해석을실시할수있습니다." | lindera tokenize \
  --dict embedded://ko-dic
한국어  NNG,*,F,한국어,Compound,*,*,한국/NNG/*+어/NNG/*
의      JKG,*,F,의,*,*,*,*
형태    NNG,*,F,형태,*,*,*,*
해석    NNG,행위,T,해석,*,*,*,*
을      JKO,*,T,을,*,*,*,*
실시    NNG,행위,F,실시,*,*,*,*
할      XSV+ETM,*,T,할,Inflect,XSV,ETM,하/XSV/*+ᆯ/ETM/*
수      NNB,*,F,수,*,*,*,*
있      VV,*,T,있,*,*,*,*
습니다  EF,*,F,습니다,*,*,*,*
.       SF,*,*,*,*,*,*,*
EOS

注意: ko-dic辞書をバイナリに含めるには、--features=embed-ko-dic オプションを使用してビルドする必要があります。

埋め込みCC-CEDICT(中国語辞書)を使用したトークナイズ

% echo "可以进行中文形态学分析。" | lindera tokenize \
  --dict embedded://cc-cedict
可以    *,*,*,*,ke3 yi3,可以,可以,can/may/possible/able to/not bad/pretty good/
进行    *,*,*,*,jin4 xing2,進行,进行,to advance/to conduct/underway/in progress/to do/to carry out/to carry on/to execute/
中文    *,*,*,*,Zhong1 wen2,中文,中文,Chinese language/
形态学  *,*,*,*,xing2 tai4 xue2,形態學,形态学,morphology (in biology or linguistics)/
分析    *,*,*,*,fen1 xi1,分析,分析,to analyze/analysis/CL:個|个[ge4]/
。      *,*,*,*,*,*,*,*
EOS

注意: CC-CEDICT辞書をバイナリに含めるには、--features=embed-cc-cedict オプションを使用してビルドする必要があります。

埋め込みJieba(中国語辞書)を使用したトークナイズ

% echo "可以进行中文形态学分析。" | lindera tokenize \
  --dict embedded://jieba

注意: Jieba辞書をバイナリに含めるには、--features=embed-jieba オプションを使用してビルドする必要があります。

ユーザー辞書の例

Linderaは、システム辞書と一緒にカスタム単語を追加するためのユーザー辞書をサポートしています。ユーザー辞書はCSVまたはバイナリ形式にすることができます。

ユーザー辞書の使用(CSV形式)

% echo "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です" | lindera tokenize \
  --dict embedded://ipadic \
  --user-dict ./resources/user_dict/ipadic_simple_userdic.csv
東京スカイツリー        カスタム名詞,*,*,*,*,*,東京スカイツリー,トウキョウスカイツリー,*
の      助詞,連体化,*,*,*,*,の,ノ,ノ
最寄り駅        名詞,一般,*,*,*,*,最寄り駅,モヨリエキ,モヨリエキ
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
とうきょうスカイツリー駅        カスタム名詞,*,*,*,*,*,とうきょうスカイツリー駅,トウキョウスカイツリーエキ,*
です    助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
EOS

ユーザー辞書の使用(バイナリ形式)

% echo "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です" | lindera tokenize \
  --dict /tmp/lindera-ipadic-2.7.0-20250920 \
  --user-dict ./resources/user_dict/ipadic_simple_userdic.bin
東京スカイツリー        カスタム名詞,*,*,*,*,*,東京スカイツリー,トウキョウスカイツリー,*
の      助詞,連体化,*,*,*,*,の,ノ,ノ
最寄り駅        名詞,一般,*,*,*,*,最寄り駅,モヨリエキ,モヨリエキ
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
とうきょうスカイツリー駅        カスタム名詞,*,*,*,*,*,とうきょうスカイツリー駅,トウキョウスカイツリーエキ,*
です    助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
EOS

トークナイズモード

Linderaは2つのトークナイズモードを提供します:normaldecompose です。

Normal モード(デフォルト)

辞書に登録された単語に基づいて忠実にトークナイズします:

% echo "関西国際空港限定トートバッグ" | lindera tokenize \
  --dict embedded://ipadic \
  --mode normal
関西国際空港    名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
限定    名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ    名詞,一般,*,*,*,*,*,*,*
EOS

Decompose モード

複合語をさらに分解してトークナイズします:

% echo "関西国際空港限定トートバッグ" | lindera tokenize \
  --dict embedded://ipadic \
  --mode decompose
関西    名詞,固有名詞,地域,一般,*,*,関西,カンサイ,カンサイ
国際    名詞,一般,*,*,*,*,国際,コクサイ,コクサイ
空港    名詞,一般,*,*,*,*,空港,クウコウ,クーコー
限定    名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ    名詞,一般,*,*,*,*,*,*,*
EOS

出力形式

Linderaは3つの出力形式を提供します:mecab, wakati, json

MeCab 形式(デフォルト)

品詞情報を含むMeCab互換形式で結果を出力します:

% echo "お待ちしております。" | lindera tokenize \
  --dict embedded://ipadic \
  --output mecab
お待ち  名詞,サ変接続,*,*,*,*,お待ち,オマチ,オマチ
し  動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
て  助詞,接続助詞,*,*,*,*,て,テ,テ
おり  動詞,非自立,*,*,五段・ラ行,連用形,おる,オリ,オリ
ます  助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。  記号,句点,*,*,*,*,。,。,。
EOS

Wakati 形式

トークンテキストのみをスペース区切りで出力します:

% echo "お待ちしております。" | lindera tokenize \
  --dict embedded://ipadic \
  --output wakati
お待ち し て おり ます 。

JSON 形式

すべてのトークン情報を含む詳細なJSON形式で出力します:

% echo "お待ちしております。" | lindera tokenize \
  --dict embedded://ipadic \
  --output json
[
  {
    "base_form": "お待ち",
    "byte_end": 9,
    "byte_start": 0,
    "conjugation_form": "*",
    "conjugation_type": "*",
    "part_of_speech": "名詞",
    "part_of_speech_subcategory_1": "サ変接続",
    "part_of_speech_subcategory_2": "*",
    "part_of_speech_subcategory_3": "*",
    "pronunciation": "オマチ",
    "reading": "オマチ",
    "surface": "お待ち",
    "word_id": 14698
  },
  ...
]

N-Best トークナイズ

Linderaは N-Best トークナイズをサポートしており、コスト順(低コスト=高精度)に上位 N 件のトークナイズ候補を返します。これは MeCab の N-Best 実装と互換性のある Forward-DP Backward-A* アルゴリズムに基づいています。

基本的な N-Best の例

% echo "すもももももももものうち" | lindera tokenize \
  --dict embedded://ipadic \
  -N 3
NBEST 1 (cost=7546)
すもも  名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
うち    名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
EOS
NBEST 2 (cost=7914)
すもも  名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
うち    名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
EOS
NBEST 3 (cost=10060)
すもも  名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
も      助詞,係助詞,*,*,*,*,も,モ,モ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
うち    名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
EOS

ユニーク結果を使用した N-Best

同じ分割が複数のパスに現れる場合(内部的な Viterbi 状態のみが異なる場合)、--nbest-unique を使用して重複を排除します:

% echo "営業部長谷川です" | lindera tokenize \
  --dict embedded://ipadic \
  -N 5 --nbest-unique -o wakati
NBEST 1 (cost=15760)
営業 部長 谷川 です
NBEST 2 (cost=17758)
営業 部長 谷 川 です
NBEST 3 (cost=18816)
営業 部 長谷川 です
NBEST 4 (cost=19320)
営業 部長 谷川 で す
NBEST 5 (cost=20814)
営業 部 長谷 川 です

コスト閾値を使用した N-Best

--nbest-cost-threshold を使用して、最良パスから一定のコスト範囲内の結果に制限します:

% echo "営業部長谷川です" | lindera tokenize \
  --dict embedded://ipadic \
  -N 10 --nbest-unique --nbest-cost-threshold 5000 -o wakati
NBEST 1 (cost=15760)
営業 部長 谷川 です
NBEST 2 (cost=17758)
営業 部長 谷 川 です
NBEST 3 (cost=18816)
営業 部 長谷川 です

残りの候補は 15760 + 5000 = 20760 を超えるため、3件の結果のみが返されます。

フィルタを使用した高度なトークナイズ

Linderaは、文字フィルタ、トークナイザー、トークンフィルタを組み合わせた分析フレームワークを提供します。フィルタはJSONを使用して構成します。

% echo "すもももももももものうち" | lindera tokenize \
  --dict embedded://ipadic \
  --char-filter 'unicode_normalize:{"kind":"nfkc"}' \
  --token-filter 'japanese_keep_tags:{"tags":["名詞,一般"]}'
すもも  名詞,一般,*,*,*,*,すもも,スモモ,スモモ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
EOS

build

Linderaで使用するための形態素解析辞書をCSVソースファイルからビルド(コンパイル)します。

ビルドパラメータ

  • --src / -s: 辞書CSVファイルを含むソースディレクトリ(ユーザー辞書の場合は単一CSVファイル)
  • --dest / -d: コンパイルされた辞書の出力先ディレクトリ
  • --metadata / -m: 辞書構造を定義するメタデータ設定ファイル (metadata.json)
  • --user / -u: システム辞書の代わりにユーザー辞書をビルドする(オプションフラグ)

辞書の種類

システム辞書 (System dictionary)

以下を含む完全な形態素解析辞書です:

  • 語彙エントリ(単語定義)
  • 接続コスト行列
  • 未知語処理ルール
  • 文字種定義

ユーザー辞書 (User dictionary)

システム辞書と一緒に動作する、カスタム単語のための補助辞書です。

IPADIC(日本語辞書)のビルド

# IPADICソースファイルのダウンロードと展開
% curl -L -o /tmp/mecab-ipadic-2.7.0-20250920.tar.gz "https://Lindera.dev/mecab-ipadic-2.7.0-20250920.tar.gz"
% tar zxvf /tmp/mecab-ipadic-2.7.0-20250920.tar.gz -C /tmp

# 辞書のビルド
% lindera build \
  --src /tmp/mecab-ipadic-2.7.0-20250920 \
  --dest /tmp/lindera-ipadic-2.7.0-20250920 \
  --metadata ./lindera-ipadic/metadata.json

IPADIC NEologd(日本語辞書)のビルド

% curl -L -o /tmp/mecab-ipadic-neologd-0.0.7-20200820.tar.gz "https://lindera.dev/mecab-ipadic-neologd-0.0.7-20200820.tar.gz"
% tar zxvf /tmp/mecab-ipadic-neologd-0.0.7-20200820.tar.gz -C /tmp

% lindera build \
  --src /tmp/mecab-ipadic-neologd-0.0.7-20200820 \
  --dest /tmp/lindera-ipadic-neologd-0.0.7-20200820 \
  --metadata ./lindera-ipadic-neologd/metadata.json

UniDic(日本語辞書)のビルド

% curl -L -o /tmp/unidic-mecab-2.1.2.tar.gz "https://Lindera.dev/unidic-mecab-2.1.2.tar.gz"
% tar zxvf /tmp/unidic-mecab-2.1.2.tar.gz -C /tmp

% lindera build \
  --src /tmp/unidic-mecab-2.1.2 \
  --dest /tmp/lindera-unidic-2.1.2 \
  --metadata ./lindera-unidic/metadata.json

CC-CEDICT(中国語辞書)のビルド

% curl -L -o /tmp/CC-CEDICT-MeCab-0.1.0-20200409.tar.gz "https://lindera.dev/CC-CEDICT-MeCab-0.1.0-20200409.tar.gz"
% tar zxvf /tmp/CC-CEDICT-MeCab-0.1.0-20200409.tar.gz -C /tmp

% lindera build \
  --src /tmp/CC-CEDICT-MeCab-0.1.0-20200409 \
  --dest /tmp/lindera-cc-cedict-0.1.0-20200409 \
  --metadata ./lindera-cc-cedict/metadata.json

Jieba(中国語辞書)のビルド

% curl -L -o /tmp/mecab-jieba-0.1.1.tar.gz "https://lindera.dev/mecab-jieba-0.1.1.tar.gz"
% tar zxvf /tmp/mecab-jieba-0.1.1.tar.gz -C /tmp

% lindera build \
  --src /tmp/mecab-jieba-0.1.1/dict-src \
  --dest /tmp/lindera-jieba-0.1.1 \
  --metadata ./lindera-jieba/metadata.json

ko-dic(韓国語辞書)のビルド

% curl -L -o /tmp/mecab-ko-dic-2.1.1-20180720.tar.gz "https://Lindera.dev/mecab-ko-dic-2.1.1-20180720.tar.gz"
% tar zxvf /tmp/mecab-ko-dic-2.1.1-20180720.tar.gz -C /tmp

% lindera build \
  --src /tmp/mecab-ko-dic-2.1.1-20180720 \
  --dest /tmp/lindera-ko-dic-2.1.1-20180720 \
  --metadata ./lindera-ko-dic/metadata.json

ユーザー辞書のビルド

IPADICユーザー辞書(日本語)のビルド

ユーザー辞書フォーマットの詳細については、以下のURLを参照してください:

% lindera build \
  --src ./resources/user_dict/ipadic_simple_userdic.csv \
  --dest ./resources/user_dict \
  --metadata ./lindera-ipadic/metadata.json \
  --user

UniDicユーザー辞書(日本語)のビルド

ユーザー辞書フォーマットの詳細については、以下のURLを参照してください:

% lindera build \
  --src ./resources/user_dict/unidic_simple_userdic.csv \
  --dest ./resources/user_dict \
  --metadata ./lindera-unidic/metadata.json \
  --user

CC-CEDICTユーザー辞書(中国語)のビルド

ユーザー辞書フォーマットの詳細については、以下のURLを参照してください:

% lindera build \
  --src ./resources/user_dict/cc-cedict_simple_userdic.csv \
  --dest ./resources/user_dict \
  --metadata ./lindera-cc-cedict/metadata.json \
  --user

Jiebaユーザー辞書(中国語)のビルド

ユーザー辞書フォーマットの詳細については、以下のURLを参照してください:

% lindera build \
  --src ./resources/user_dict/jieba_simple_userdic.csv \
  --dest ./resources/user_dict \
  --metadata ./lindera-jieba/metadata.json \
  --user

ko-dicユーザー辞書(韓国語)のビルド

ユーザー辞書フォーマットの詳細については、以下のURLを参照してください:

% lindera build \
  --src ./resources/user_dict/ko-dic_simple_userdic.csv \
  --dest ./resources/user_dict \
  --metadata ./lindera-ko-dic/metadata.json \
  --user

train

注釈付きコーパスデータから新しい形態素解析モデルを学習します。この機能を使用するには、train 機能フラグを有効にしてビルドする必要があります。(train 機能フラグはデフォルトで有効になっています。)

学習パラメータ

  • --seed / -s: 重み付けを行うシード語彙ファイル(CSV形式)
  • --corpus / -c: 学習用コーパス(注釈付きテキスト)
  • --char-def / -C: 文字定義ファイル (char.def)
  • --unk-def / -u: 未知語定義ファイル (unk.def) - 重み付けの対象
  • --feature-def / -f: 素性定義ファイル (feature.def)
  • --rewrite-def / -r: 書換えルール定義ファイル (rewrite.def)
  • --output / -o: 出力モデルファイル
  • --lambda / -l: L1正則化 (0.0-1.0) (デフォルト: 0.01)
  • --max-iterations / -i: 学習の最大反復回数 (デフォルト: 100)
  • --max-threads / -t: 最大スレッド数 (デフォルトはCPUコア数、データセットサイズに基づいて自動調整)

基本的なワークフロー

1. 学習用ファイルの準備

シード語彙ファイル (seed.csv):

シード語彙ファイルは、CRFモデルの学習に使用される初期辞書エントリを含みます。各行はカンマ区切りのフィールドを持つ単語エントリを表します:

  • 表層形
  • 左文脈ID
  • 右文脈ID
  • 単語コスト
  • 品詞タグ(複数のフィールド)
  • 原形
  • 読み(カタカナ)
  • 発音

注意: 正確なフィールド定義は辞書フォーマット(IPADIC, UniDic, ko-dic, CC-CEDICT)によって異なります。詳細は各辞書のフォーマット仕様を参照してください。

外国,0,0,0,名詞,一般,*,*,*,*,外国,ガイコク,ガイコク
人,0,0,0,名詞,接尾,一般,*,*,*,人,ジン,ジン

学習用コーパス (corpus.txt):

学習用コーパスファイルは、CRFモデルの学習に使用される注釈付きテキストデータを含みます。各行は以下で構成されます:

  • 表層形(単語)とそれに続くタブ文字
  • カンマ区切りの形態素素性(品詞タグ、原形、読み、発音)
  • 文は "EOS" (End Of Sentence) マーカーで区切られます
外国	名詞,一般,*,*,*,*,外国,ガイコク,ガイコク
人	名詞,接尾,一般,*,*,*,人,ジン,ジン
参政	名詞,サ変接続,*,*,*,*,参政,サンセイ,サンセイ
権	名詞,接尾,一般,*,*,*,権,ケン,ケン
EOS

ファイルフォーマットや高度な機能の詳細については、TRAINER_README.md を参照してください。

2. モデルの学習

lindera train \
  --seed ./resources/training/seed.csv \
  --corpus ./resources/training/corpus.txt \
  --unk-def ./resources/training/unk.def \
  --char-def ./resources/training/char.def \
  --feature-def ./resources/training/feature.def \
  --rewrite-def ./resources/training/rewrite.def \
  --output /tmp/lindera/training/model.dat \
  --lambda 0.01 \
  --max-iterations 100

3. 学習結果

学習済みモデルには以下が含まれます:

  • 既存単語: 新しく学習された重みを持つすべてのシード辞書レコード
  • 新語: シード辞書にはないがコーパスに含まれる単語(適切な重み付きで追加)

export

学習済みモデルファイルをLindera辞書フォーマットのファイルにエクスポートします。この機能を使用するには、train 機能フラグを有効にしてビルドする必要があります。

エクスポートパラメータ

  • --model / -m: 学習済みモデルファイル(.dat形式)のパス
  • --output / -o: 辞書ファイルの出力先ディレクトリ
  • --metadata: オプションの metadata.json ファイル(学習済みモデル情報で更新されます)
  • --cost-factor: 重みからコストへの変換係数を上書き(デフォルト: 学習済みモデルの値、通常は700)

出力ファイル

エクスポートコマンドは出力ディレクトリに以下の辞書ファイルを作成します:

  • lex.csv: 学習された重みを持つ語彙ファイル(MeCab互換の tocost() によるコスト変換)
  • matrix.def: 全 (right_id, left_id) ペアを網羅する密な接続コスト行列
  • unk.def: 未知語定義
  • char.def: 文字種定義
  • feature.def: 素性テンプレート定義(学習済みモデルからコピー)
  • rewrite.def: 素性リライトルール(学習済みモデルからコピー)
  • left-id.def: 左文脈IDから素性文字列へのマッピング
  • right-id.def: 右文脈IDから素性文字列へのマッピング
  • metadata.json: 更新されたメタデータファイル(--metadata オプションが指定された場合)

完全なワークフロー例

1. モデルの学習

lindera train \
  --seed ./resources/training/seed.csv \
  --corpus ./resources/training/corpus.txt \
  --unk-def ./resources/training/unk.def \
  --char-def ./resources/training/char.def \
  --feature-def ./resources/training/feature.def \
  --rewrite-def ./resources/training/rewrite.def \
  --output /tmp/lindera/training/model.dat \
  --lambda 0.01 \
  --max-iterations 100

2. 辞書フォーマットへのエクスポート

lindera export \
  --model /tmp/lindera/training/model.dat \
  --metadata ./resources/training/metadata.json \
  --output /tmp/lindera/training/dictionary

3. 辞書のビルド

lindera build \
  --src /tmp/lindera/training/dictionary \
  --dest /tmp/lindera/training/compiled_dictionary \
  --metadata /tmp/lindera/training/dictionary/metadata.json

4. 学習済み辞書の使用

echo "これは外国人参政権です。" | lindera tokenize \
  -d /tmp/lindera/training/compiled_dictionary

メタデータ更新機能

--metadata オプションが指定されると、エクスポートコマンドは以下の処理を行います:

  1. ベースとなる metadata.json ファイルを読み込み、既存の設定を保持します
  2. 特定のフィールドを学習済みモデルの値で更新します:
    • default_left_context_id: 学習済みモデルからの最大左文脈ID
    • default_right_context_id: 学習済みモデルからの最大右文脈ID
    • default_word_cost: 素性重みの中央値から計算された値
    • model_info: 素性数、ラベル数、行列サイズ、反復回数、正則化、バージョン、タイムスタンプを含む学習統計情報
  3. 既存の設定を保持します(辞書名、文字エンコード設定、スキーマ定義、その他のユーザー定義設定など)

チュートリアル

このチュートリアルでは、Lindera CLIの基本的な使い方を、インストールから高度なテキスト処理まで順を追って説明します。

1. CLIのインストール

埋め込みIPADIC辞書付きでLindera CLIをインストールします:

% cargo install lindera-cli --features=embed-ipadic

インストールの確認:

% lindera --help

2. 埋め込み辞書を使用した基本的なトークナイズ

埋め込みIPADIC辞書を使用して日本語テキストをトークナイズします:

% echo "東京は日本の首都です。" | lindera tokenize \
  --dict embedded://ipadic

期待される出力:

東京    名詞,固有名詞,地域,一般,*,*,東京,トウキョウ,トーキョー
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
日本    名詞,固有名詞,地域,国,*,*,日本,ニホン,ニホン
の      助詞,連体化,*,*,*,*,の,ノ,ノ
首都    名詞,一般,*,*,*,*,首都,シュト,シュト
です    助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
。      記号,句点,*,*,*,*,。,。,。
EOS

3. 異なる出力形式を試す

Wakati 形式(分かち書きのみ)

% echo "東京は日本の首都です。" | lindera tokenize \
  --dict embedded://ipadic \
  --output wakati

期待される出力:

東京 は 日本 の 首都 です 。

JSON 形式(詳細情報)

% echo "東京は日本の首都です。" | lindera tokenize \
  --dict embedded://ipadic \
  --output json

バイトオフセット、品詞タグ、読みなどの詳細なトークン情報を含むJSON配列が出力されます。

4. Decompose モードの使用

Decompose モードは複合名詞を構成要素に分解します:

% echo "関西国際空港限定トートバッグ" | lindera tokenize \
  --dict embedded://ipadic \
  --mode decompose

期待される出力:

関西    名詞,固有名詞,地域,一般,*,*,関西,カンサイ,カンサイ
国際    名詞,一般,*,*,*,*,国際,コクサイ,コクサイ
空港    名詞,一般,*,*,*,*,空港,クウコウ,クーコー
限定    名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ    名詞,一般,*,*,*,*,*,*,*
EOS

Normal モードと比較すると、「関西国際空港」が1つのトークンのままになる点が異なります。

5. 文字フィルタとトークンフィルタの適用

Unicode正規化を行い、一般名詞のみを保持します:

% echo "Linderaは形態素解析エンジンです。" | lindera tokenize \
  --dict embedded://ipadic \
  --char-filter 'unicode_normalize:{"kind":"nfkc"}' \
  --token-filter 'japanese_keep_tags:{"tags":["名詞,一般","名詞,固有名詞,組織"]}'

期待される出力:

Lindera 名詞,固有名詞,組織,*,*,*,*,*,*
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
エンジン        名詞,一般,*,*,*,*,エンジン,エンジン,エンジン
EOS

Unicode正規化により全角文字が半角に変換され、Token Filter により指定した品詞タグに一致するトークンのみが保持されます。

複数のフィルタを組み合わせることもできます:

% echo "すもももももももものうち" | lindera tokenize \
  --dict embedded://ipadic \
  --token-filter 'japanese_stop_tags:{"tags":["助詞","助詞,係助詞","助詞,連体化"]}'

6. ユーザー辞書の使用

カスタム単語エントリを含むCSVファイル(例: my_dict.csv)を作成します:

東京スカイツリー,カスタム名詞,トウキョウスカイツリー

ユーザー辞書を使用してトークナイズします:

% echo "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です" | lindera tokenize \
  --dict embedded://ipadic \
  --user-dict ./my_dict.csv

ユーザー辞書がない場合、「東京スカイツリー」は複数のトークンに分割されます。ユーザー辞書を使用すると、1つのトークンとして認識されます。

ビルド済みのユーザー辞書の例については、以下を参照してください:

% echo "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です" | lindera tokenize \
  --dict embedded://ipadic \
  --user-dict ./resources/user_dict/ipadic_simple_userdic.csv

期待される出力:

東京スカイツリー        カスタム名詞,*,*,*,*,*,東京スカイツリー,トウキョウスカイツリー,*
の      助詞,連体化,*,*,*,*,の,ノ,ノ
最寄り駅        名詞,一般,*,*,*,*,最寄り駅,モヨリエキ,モヨリエキ
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
とうきょうスカイツリー駅        カスタム名詞,*,*,*,*,*,とうきょうスカイツリー駅,トウキョウスカイツリーエキ,*
です    助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
EOS

Lindera Python

Lindera Python は、PyO3 を使用して構築された Lindera 形態素解析エンジンの Python バインディングです。Python 3.10 以降をサポートし、Lindera の高性能なトークナイズ機能を Python エコシステムに提供します。

特徴

  • 多言語対応: 日本語(IPADIC、IPADIC NEologd、UniDic)、韓国語(ko-dic)、中国語(CC-CEDICT、Jieba)のテキストをトークナイズ
  • テキスト処理パイプライン: 文字フィルタとトークンフィルタを組み合わせて、柔軟な前処理・後処理が可能
  • CRF ベースの辞書学習: アノテーション付きコーパスからカスタム形態素解析モデルを学習(train feature が必要)
  • 複数のトークナイズモード: 解析粒度に応じた Normal モードと Decompose モード
  • N-best トークナイズ: コスト順にランク付けされた複数のトークナイズ候補を取得
  • ユーザー辞書: システム辞書をカスタム語彙で拡張

ドキュメント

インストール

PyPI からのインストール

ビルド済みホイールが PyPI で公開されています:

pip install lindera-python

[!NOTE] PyPI パッケージには辞書が含まれていません。下記の辞書の入手を参照してください。

辞書の入手

Lindera はパッケージに辞書を同梱していません。ビルド済み辞書を別途入手する必要があります。

GitHub Releases からのダウンロード

ビルド済み辞書は GitHub Releases ページから入手できます。辞書アーカイブをダウンロードしてローカルディレクトリに展開してください:

# 例: IPADIC 辞書のダウンロードと展開
curl -LO https://github.com/lindera/lindera/releases/download/<version>/lindera-ipadic-<version>.zip
unzip lindera-ipadic-<version>.zip -d /path/to/ipadic

ソースからのビルド

特定の feature フラグを有効にする必要がある場合など、ソースからビルドするには以下の前提条件が必要です:

  • Python 3.10 以降(3.14 まで)
  • Rust ツールチェーン -- rustup 経由でインストール
  • maturin -- Rust ベースの Python 拡張をビルドするための Python パッケージ

maturin を pip でインストールします:

pip install maturin

開発ビルド

lindera-python を開発モードでビルドしてインストールします:

cd lindera-python
maturin develop

または、プロジェクトの Makefile を使用します:

make python-develop

学習機能付きビルド

train feature を有効にすると、CRF ベースの辞書学習機能が利用可能になります。デフォルトで有効になっています:

maturin develop --features train

Feature フラグ

Feature説明デフォルト
trainCRF 学習機能有効
embed-ipadic日本語辞書(IPADIC)をバイナリに埋め込み無効
embed-unidic日本語辞書(UniDic)をバイナリに埋め込み無効
embed-ipadic-neologd日本語辞書(IPADIC NEologd)をバイナリに埋め込み無効
embed-ko-dic韓国語辞書(ko-dic)をバイナリに埋め込み無効
embed-cc-cedict中国語辞書(CC-CEDICT)をバイナリに埋め込み無効
embed-jieba中国語辞書(Jieba)をバイナリに埋め込み無効
embed-cjk全 CJK 辞書をバイナリに埋め込み(IPADIC、ko-dic、Jieba)無効

複数の feature を組み合わせることができます:

maturin develop --features "train,embed-ipadic,embed-ko-dic"

[!TIP] 辞書をバイナリに直接埋め込みたい場合(上級者向け)は、対応する embed-* feature フラグを有効にしてビルドし、embedded:// スキームでロードしてください:

dictionary = load_dictionary("embedded://ipadic")

詳細は Feature フラグ を参照してください。

インストールの確認

インストール後、Python で lindera が利用可能であることを確認します:

import lindera

print(lindera.version())

クイックスタート

このガイドでは、lindera-python を使用してテキストをトークナイズする方法を紹介します。

基本的なトークナイズ

トークナイザーの作成には TokenizerBuilder の使用を推奨します:

from lindera import TokenizerBuilder

builder = TokenizerBuilder()
builder.set_mode("normal")
builder.set_dictionary("/path/to/ipadic")
tokenizer = builder.build()

tokens = tokenizer.tokenize("関西国際空港限定トートバッグ")
for token in tokens:
    print(f"{token.surface}\t{','.join(token.details)}")

注意: ビルド済み辞書を GitHub Releases からダウンロードし、展開したディレクトリのパスを指定してください。

期待される出力:

関西国際空港    名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
限定    名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ    UNK

メソッドチェーン

TokenizerBuilder は簡潔な設定のためにメソッドチェーンをサポートしています:

from lindera import TokenizerBuilder

tokenizer = (
    TokenizerBuilder()
    .set_mode("normal")
    .set_dictionary("/path/to/ipadic")
    .build()
)

tokens = tokenizer.tokenize("すもももももももものうち")
for token in tokens:
    print(f"{token.surface}\t{token.get_detail(0)}")

トークンプロパティへのアクセス

各トークンは以下のプロパティを公開しています:

from lindera import TokenizerBuilder

tokenizer = TokenizerBuilder().set_dictionary("/path/to/ipadic").build()
tokens = tokenizer.tokenize("東京タワー")

for token in tokens:
    print(f"Surface: {token.surface}")
    print(f"Byte range: {token.byte_start}..{token.byte_end}")
    print(f"Position: {token.position}")
    print(f"Word ID: {token.word_id}")
    print(f"Unknown: {token.is_unknown}")
    print(f"Details: {token.details}")
    print()

N-best トークナイズ

コスト順にランク付けされた複数のトークナイズ候補を取得します:

from lindera import TokenizerBuilder

tokenizer = TokenizerBuilder().set_dictionary("/path/to/ipadic").build()
results = tokenizer.tokenize_nbest("すもももももももものうち", n=3)

for tokens, cost in results:
    surfaces = [t.surface for t in tokens]
    print(f"Cost {cost}: {' / '.join(surfaces)}")

Tokenizer API

TokenizerBuilder

TokenizerBuilder はビルダーパターンを使用して Tokenizer インスタンスを設定・構築します。

コンストラクタ

TokenizerBuilder()

デフォルト設定で新しいビルダーを作成します。

from lindera import TokenizerBuilder

builder = TokenizerBuilder()

TokenizerBuilder().from_file(file_path)

JSON ファイルから設定を読み込み、新しいビルダーを返します。

builder = TokenizerBuilder().from_file("config.json")

設定メソッド

すべてのセッターメソッドはメソッドチェーンのために self を返します。

set_mode(mode)

トークナイズモードを設定します。

  • "normal" -- 標準的なトークナイズ(デフォルト)
  • "decompose" -- 複合語をより小さな単位に分解
builder.set_mode("normal")

set_dictionary(path)

システム辞書のパスまたは URI を設定します。

# 埋め込み辞書を使用
builder.set_dictionary("embedded://ipadic")

# 外部辞書を使用
builder.set_dictionary("/path/to/dictionary")

set_user_dictionary(uri)

ユーザー辞書の URI を設定します。

builder.set_user_dictionary("/path/to/user_dictionary")

set_keep_whitespace(keep)

出力に空白トークンを含めるかどうかを制御します。

builder.set_keep_whitespace(True)

append_character_filter(kind, args=None)

前処理パイプラインに文字フィルタを追加します。

builder.append_character_filter("unicode_normalize", {"kind": "nfkc"})

append_token_filter(kind, args=None)

後処理パイプラインにトークンフィルタを追加します。

builder.append_token_filter("lowercase", {})

ビルド

build()

設定された内容で Tokenizer をビルドして返します。

tokenizer = builder.build()

Tokenizer

Tokenizer はテキストに対して形態素解析を行います。

Tokenizer の作成

Tokenizer(dictionary, mode="normal", user_dictionary=None)

読み込み済みの辞書から直接トークナイザーを作成します。

from lindera import Tokenizer, load_dictionary

dictionary = load_dictionary("embedded://ipadic")
tokenizer = Tokenizer(dictionary, mode="normal")

Tokenizer メソッド

tokenize(text)

入力テキストをトークナイズし、Token オブジェクトのリストを返します。

tokens = tokenizer.tokenize("形態素解析")

パラメータ:

名前説明
textstrトークナイズするテキスト

戻り値: list[Token]

tokenize_nbest(text, n, unique=False, cost_threshold=None)

N-best トークナイズ結果を返します。各結果はトータルパスコストとペアになっています。

results = tokenizer.tokenize_nbest("すもももももももものうち", n=3)
for tokens, cost in results:
    print(cost, [t.surface for t in tokens])

パラメータ:

名前説明
textstrトークナイズするテキスト
nint返す結果の数
uniquebool結果の重複を排除(デフォルト: False
cost_thresholdint または None最良パスからの最大コスト差(デフォルト: None

戻り値: list[tuple[list[Token], int]]

Token

Token は単一の形態素トークンを表します。

プロパティ

プロパティ説明
surfacestrトークンの表層形
byte_startint元テキストでの開始バイト位置
byte_endint元テキストでの終了バイト位置
positionintトークンの位置インデックス
word_idint辞書の単語 ID
is_unknownbool辞書に登録されていない単語の場合 True
detailslist[str] または None形態素の詳細情報(品詞、読みなど)

Token メソッド

get_detail(index)

指定されたインデックスの詳細文字列を返します。インデックスが範囲外の場合は None を返します。

token = tokenizer.tokenize("東京")[0]
pos = token.get_detail(0)        # 例: "名詞"
subpos = token.get_detail(1)     # 例: "固有名詞"
reading = token.get_detail(7)    # 例: "トウキョウ"

パラメータ:

名前説明
indexintdetails リストへのゼロベースインデックス

戻り値: str または None

details の構造は辞書によって異なります:

  • IPADIC: [品詞, 品詞細分類1, 品詞細分類2, 品詞細分類3, 活用型, 活用形, 原形, 読み, 発音]
  • UniDic: UniDic 仕様に準拠した詳細な形態素情報
  • ko-dic / CC-CEDICT / Jieba: 各辞書固有の詳細フォーマット

辞書管理

Lindera Python は、形態素解析で使用する辞書の読み込み、ビルド、管理のための関数を提供します。

辞書の読み込み

システム辞書

load_dictionary(uri) を使用してシステム辞書を読み込みます。GitHub Releases からビルド済み辞書をダウンロードし、展開したディレクトリのパスを指定してください:

from lindera import load_dictionary

dictionary = load_dictionary("/path/to/ipadic")

埋め込み辞書(上級者向け) -- embed-* feature フラグ付きでビルドした場合、埋め込み辞書を使用できます:

dictionary = load_dictionary("embedded://ipadic")

ユーザー辞書

ユーザー辞書はシステム辞書にカスタム語彙を追加します。

from lindera import load_user_dictionary, Metadata

metadata = Metadata()
user_dict = load_user_dictionary("/path/to/user_dictionary", metadata)

トークナイザーのビルド時にユーザー辞書を渡します:

from lindera import Tokenizer, load_dictionary, load_user_dictionary, Metadata

dictionary = load_dictionary("/path/to/ipadic")
metadata = Metadata()
user_dict = load_user_dictionary("/path/to/user_dictionary", metadata)

tokenizer = Tokenizer(dictionary, mode="normal", user_dictionary=user_dict)

または、ビルダー経由で設定します:

from lindera import TokenizerBuilder

tokenizer = (
    TokenizerBuilder()
    .set_dictionary("/path/to/ipadic")
    .set_user_dictionary("/path/to/user_dictionary")
    .build()
)

辞書のビルド

システム辞書のビルド

ソースファイルからシステム辞書をビルドします:

from lindera import build_dictionary, Metadata

metadata = Metadata(name="custom", encoding="UTF-8")
build_dictionary("/path/to/input_dir", "/path/to/output_dir", metadata)

入力ディレクトリには辞書のソースファイル(CSV レキシコン、matrix.def など)が含まれている必要があります。

ユーザー辞書のビルド

CSV ファイルからユーザー辞書をビルドします:

from lindera import build_user_dictionary, Metadata

metadata = Metadata()
build_user_dictionary("ipadic", "user_words.csv", "/path/to/output_dir", metadata)

metadata パラメータは省略可能です。省略した場合はデフォルトのメタデータ値が使用されます:

build_user_dictionary("ipadic", "user_words.csv", "/path/to/output_dir")

Metadata

Metadata クラスは辞書のパラメータを設定します。

Metadata の作成

from lindera import Metadata

# デフォルトのメタデータ
metadata = Metadata()

# カスタムメタデータ
metadata = Metadata(
    name="my_dictionary",
    encoding="UTF-8",
    default_word_cost=-10000,
)

JSON からの読み込み

metadata = Metadata.from_json_file("metadata.json")

プロパティ

プロパティデフォルト説明
namestr"default"辞書名
encodingstr"UTF-8"文字エンコーディング
default_word_costint-10000未知語のデフォルトコスト
default_left_context_idint1288デフォルトの左文脈 ID
default_right_context_idint1288デフォルトの右文脈 ID
default_field_valuestr"*"欠損フィールドのデフォルト値
flexible_csvboolFalse柔軟な CSV パースを許可
skip_invalid_cost_or_idboolFalse無効なコストまたは ID のエントリーをスキップ
normalize_detailsboolFalse形態素の詳細情報を正規化
dictionary_schemaSchemaIPADIC スキーマメイン辞書のスキーマ
user_dictionary_schemaSchema最小スキーマユーザー辞書のスキーマ

すべてのプロパティは取得と設定の両方をサポートしています:

metadata = Metadata()
metadata.name = "custom_dict"
metadata.encoding = "EUC-JP"
print(metadata.name)  # "custom_dict"

to_dict()

メタデータの辞書表現を返します:

metadata = Metadata(name="test")
print(metadata.to_dict())

テキスト処理パイプライン

Lindera Python は、トークナイズ前に文字フィルタを適用し、トークナイズ後にトークンフィルタを適用する、組み合わせ可能なテキスト処理パイプラインをサポートしています。フィルタは TokenizerBuilder に追加され、追加された順序で実行されます。

Input Text
  --> Character Filters (preprocessing)
  --> Tokenization
  --> Token Filters (postprocessing)
  --> Output Tokens

文字フィルタ

文字フィルタはトークナイズ前に入力テキストを変換します。

unicode_normalize

入力テキストに Unicode 正規化を適用します。

from lindera import TokenizerBuilder

tokenizer = (
    TokenizerBuilder()
    .set_dictionary("embedded://ipadic")
    .append_character_filter("unicode_normalize", {"kind": "nfkc"})
    .build()
)

サポートされる正規化形式: "nfc""nfkc""nfd""nfkd"

mapping

マッピングテーブルに従って文字や文字列を置換します。

tokenizer = (
    TokenizerBuilder()
    .set_dictionary("embedded://ipadic")
    .append_character_filter("mapping", {
        "mapping": {
            "\u30fc": "-",
            "\uff5e": "~",
        }
    })
    .build()
)

japanese_iteration_mark

日本語の踊り字(繰り返し記号)を完全な形に展開します。

tokenizer = (
    TokenizerBuilder()
    .set_dictionary("embedded://ipadic")
    .append_character_filter("japanese_iteration_mark", {
        "normalize_kanji": True,
        "normalize_kana": True,
    })
    .build()
)

トークンフィルタ

トークンフィルタはトークナイズ後にトークンを変換または除去します。

lowercase

トークンの表層形を小文字に変換します。

tokenizer = (
    TokenizerBuilder()
    .set_dictionary("embedded://ipadic")
    .append_token_filter("lowercase", {})
    .build()
)

japanese_base_form

辞書の形態素情報を使用して、活用形を基本形(辞書形)に置換します。

tokenizer = (
    TokenizerBuilder()
    .set_dictionary("embedded://ipadic")
    .append_token_filter("japanese_base_form", {})
    .build()
)

japanese_stop_tags

指定されたタグに一致する品詞のトークンを除去します。

tokenizer = (
    TokenizerBuilder()
    .set_dictionary("embedded://ipadic")
    .append_token_filter("japanese_stop_tags", {
        "tags": ["助詞", "助動詞"],
    })
    .build()
)

japanese_keep_tags

指定されたタグに一致する品詞のトークンのみを保持します。その他のトークンはすべて除去されます。

tokenizer = (
    TokenizerBuilder()
    .set_dictionary("embedded://ipadic")
    .append_token_filter("japanese_keep_tags", {
        "tags": ["名詞"],
    })
    .build()
)

パイプラインの完全な例

以下の例では、複数の文字フィルタとトークンフィルタを1つのパイプラインに組み合わせています:

from lindera import TokenizerBuilder

tokenizer = (
    TokenizerBuilder()
    .set_mode("normal")
    .set_dictionary("embedded://ipadic")
    # Preprocessing
    .append_character_filter("unicode_normalize", {"kind": "nfkc"})
    .append_character_filter("japanese_iteration_mark", {
        "normalize_kanji": True,
        "normalize_kana": True,
    })
    # Postprocessing
    .append_token_filter("japanese_base_form", {})
    .append_token_filter("japanese_stop_tags", {
        "tags": ["助詞", "助動詞", "記号"],
    })
    .append_token_filter("lowercase", {})
    .build()
)

tokens = tokenizer.tokenize("Linderaは形態素解析を行うライブラリです。")
for token in tokens:
    print(f"{token.surface}\t{','.join(token.details)}")

このパイプラインでは:

  1. unicode_normalize が全角文字を半角に変換(NFKC 正規化)
  2. japanese_iteration_mark が踊り字を展開
  3. japanese_base_form が活用形のトークンを基本形に変換
  4. japanese_stop_tags が助詞、助動詞、記号を除去
  5. lowercase がアルファベットを小文字に正規化

学習

Lindera Python は、アノテーション付きコーパスからカスタム CRF ベースの形態素解析モデルを学習する機能をサポートしています。この機能には train feature が必要です。

前提条件

train feature を有効にして lindera-python をビルドします(デフォルトで有効):

maturin develop --features train

モデルの学習

lindera.train() を使用して、種辞書とアノテーション付きコーパスから CRF モデルを学習します:

import lindera

lindera.train(
    seed="resources/training/seed.csv",
    corpus="resources/training/corpus.txt",
    char_def="resources/training/char.def",
    unk_def="resources/training/unk.def",
    feature_def="resources/training/feature.def",
    rewrite_def="resources/training/rewrite.def",
    output="/tmp/model.dat",
    lambda_=0.01,
    max_iter=100,
    max_threads=4,
)

学習パラメータ

パラメータデフォルト説明
seedstr必須種辞書ファイルのパス(CSV 形式)
corpusstr必須アノテーション付き学習コーパスのパス
char_defstr必須文字定義ファイルのパス(char.def)
unk_defstr必須未知語定義ファイルのパス(unk.def)
feature_defstr必須素性定義ファイルのパス(feature.def)
rewrite_defstr必須書き換えルール定義ファイルのパス(rewrite.def)
outputstr必須学習済みモデルファイルの出力パス
lambda_float0.01L1 正則化コスト(0.0--1.0)
max_iterint100最大学習イテレーション数
max_threadsint または NoneNoneスレッド数(None = CPU コア数を自動検出)

学習済みモデルのエクスポート

学習後、lindera.export() を使用してモデルを辞書ソースファイルにエクスポートします:

import lindera

lindera.export(
    model="/tmp/model.dat",
    output="/tmp/dictionary_source",
    metadata="resources/training/metadata.json",
)

エクスポートパラメータ

パラメータデフォルト説明
modelstr必須学習済みモデルファイルのパス(.dat)
outputstr必須辞書ソースファイルの出力ディレクトリ
metadatastr または NoneNoneベースとなる metadata.json ファイルのパス

エクスポートにより、出力ディレクトリに以下のファイルが作成されます:

  • lex.csv -- 学習済みコスト付きのレキシコンエントリー
  • matrix.def -- 連接コスト行列
  • unk.def -- 未知語定義
  • char.def -- 文字カテゴリ定義
  • metadata.json -- 更新されたメタデータ(metadata パラメータ指定時)

完全なワークフロー

カスタム辞書の学習と使用の完全なワークフロー:

import lindera

# Step 1: Train the CRF model
lindera.train(
    seed="resources/training/seed.csv",
    corpus="resources/training/corpus.txt",
    char_def="resources/training/char.def",
    unk_def="resources/training/unk.def",
    feature_def="resources/training/feature.def",
    rewrite_def="resources/training/rewrite.def",
    output="/tmp/model.dat",
    lambda_=0.01,
    max_iter=100,
)

# Step 2: Export to dictionary source files
lindera.export(
    model="/tmp/model.dat",
    output="/tmp/dictionary_source",
    metadata="resources/training/metadata.json",
)

# Step 3: Build the dictionary from exported source files
metadata = lindera.Metadata.from_json_file("/tmp/dictionary_source/metadata.json")
lindera.build_dictionary("/tmp/dictionary_source", "/tmp/dictionary", metadata)

# Step 4: Use the trained dictionary
tokenizer = (
    lindera.TokenizerBuilder()
    .set_dictionary("/tmp/dictionary")
    .set_mode("normal")
    .build()
)

tokens = tokenizer.tokenize("形態素解析のテスト")
for token in tokens:
    print(f"{token.surface}\t{','.join(token.details)}")

Lindera Node.js

Lindera Node.js は、NAPI-RS を使用して構築された Lindera 形態素解析エンジンの Node.js バインディングです。Node.js 18 以降をサポートし、Lindera の高性能なトークナイズ機能を Node.js エコシステムに提供します。

特徴

  • 多言語対応: 日本語(IPADIC、IPADIC NEologd、UniDic)、韓国語(ko-dic)、中国語(CC-CEDICT、Jieba)のテキストをトークナイズ
  • テキスト処理パイプライン: 文字フィルタとトークンフィルタを組み合わせて、柔軟な前処理・後処理が可能
  • CRF ベースの辞書学習: アノテーション付きコーパスからカスタム形態素解析モデルを学習(train feature が必要)
  • 複数のトークナイズモード: 解析粒度に応じた Normal モードと Decompose モード
  • N-best トークナイズ: コスト順にランク付けされた複数のトークナイズ候補を取得
  • ユーザー辞書: システム辞書をカスタム語彙で拡張
  • TypeScript サポート: 完全な型定義を同梱

ドキュメント

インストール

npm からのインストール

ビルド済みパッケージが npm で公開予定です:

npm install lindera-nodejs

[!NOTE] npm パッケージには辞書が含まれていません。下記の辞書の入手を参照してください。 ブラウザ/WASM での利用には lindera-wasm を参照してください。

ソースからのビルド

前提条件

  • Node.js 18 以降(LTS バージョン推奨)
  • Rust ツールチェーン -- rustup 経由でインストール
  • NAPI-RS CLI -- Rust で Node.js ネイティブアドオンをビルドするための CLI ツール

NAPI-RS CLI をグローバルにインストールします:

npm install -g @napi-rs/cli

辞書の入手

Lindera はパッケージに辞書を同梱していません。ビルド済み辞書を別途入手する必要があります。

GitHub Releases からのダウンロード

ビルド済み辞書は GitHub Releases ページから入手できます。辞書アーカイブをダウンロードしてローカルディレクトリに展開してください:

# 例: IPADIC 辞書のダウンロードと展開
curl -LO https://github.com/lindera/lindera/releases/download/<version>/lindera-ipadic-<version>.zip
unzip lindera-ipadic-<version>.zip -d /path/to/ipadic

開発ビルド

lindera-nodejs を開発モードでビルドします:

cd lindera-nodejs
npm install
npm run build

または、プロジェクトの Makefile を使用します:

make nodejs-develop

学習機能付きビルド

train feature を有効にすると、CRF ベースの辞書学習機能が利用可能になります。デフォルトで有効になっています:

npm run build -- --features train

Feature フラグ

Feature説明デフォルト
trainCRF 学習機能有効
embed-ipadic日本語辞書(IPADIC)をバイナリに埋め込み無効
embed-unidic日本語辞書(UniDic)をバイナリに埋め込み無効
embed-ipadic-neologd日本語辞書(IPADIC NEologd)をバイナリに埋め込み無効
embed-ko-dic韓国語辞書(ko-dic)をバイナリに埋め込み無効
embed-cc-cedict中国語辞書(CC-CEDICT)をバイナリに埋め込み無効
embed-jieba中国語辞書(Jieba)をバイナリに埋め込み無効
embed-cjk全 CJK 辞書をバイナリに埋め込み(IPADIC、ko-dic、Jieba)無効

複数の feature を組み合わせることができます:

npm run build -- --features "train,embed-ipadic,embed-ko-dic"

[!TIP] 辞書をバイナリに直接埋め込みたい場合(上級者向け)は、対応する embed-* feature フラグを有効にしてビルドし、embedded:// スキームでロードしてください:

const dictionary = loadDictionary("embedded://ipadic");

詳細は Feature フラグ を参照してください。

インストールの確認

インストール後、Node.js で lindera が利用可能であることを確認します:

const lindera = require("lindera-nodejs");

console.log(lindera.version());

または ES modules を使用する場合:

import { version } from "lindera-nodejs";

console.log(version());

クイックスタート

このガイドでは、lindera-nodejs を使用してテキストをトークナイズする方法を紹介します。

基本的なトークナイズ

トークナイザーの作成には TokenizerBuilder の使用を推奨します:

const { TokenizerBuilder } = require("lindera-nodejs");

const builder = new TokenizerBuilder();
builder.setMode("normal");
builder.setDictionary("/path/to/ipadic");
const tokenizer = builder.build();

const tokens = tokenizer.tokenize("関西国際空港限定トートバッグ");
for (const token of tokens) {
  console.log(`${token.surface}\t${token.details.join(",")}`);
}

注意: ビルド済み辞書を GitHub Releases からダウンロードし、展開したディレクトリのパスを指定してください。

期待される出力:

関西国際空港    名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
限定    名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ    UNK

メソッドチェーン

TokenizerBuilder は簡潔な設定のためにメソッドチェーンをサポートしています:

const { TokenizerBuilder } = require("lindera-nodejs");

const tokenizer = new TokenizerBuilder()
  .setMode("normal")
  .setDictionary("/path/to/ipadic")
  .build();

const tokens = tokenizer.tokenize("すもももももももものうち");
for (const token of tokens) {
  console.log(`${token.surface}\t${token.getDetail(0)}`);
}

トークンプロパティへのアクセス

各トークンは以下のプロパティを公開しています:

const { TokenizerBuilder } = require("lindera-nodejs");

const tokenizer = new TokenizerBuilder()
  .setDictionary("/path/to/ipadic")
  .build();

const tokens = tokenizer.tokenize("東京タワー");
for (const token of tokens) {
  console.log(`Surface: ${token.surface}`);
  console.log(`Byte range: ${token.byteStart}..${token.byteEnd}`);
  console.log(`Position: ${token.position}`);
  console.log(`Word ID: ${token.wordId}`);
  console.log(`Unknown: ${token.isUnknown}`);
  console.log(`Details: ${token.details}`);
  console.log();
}

N-best トークナイズ

コスト順にランク付けされた複数のトークナイズ候補を取得します:

const { TokenizerBuilder } = require("lindera-nodejs");

const tokenizer = new TokenizerBuilder()
  .setDictionary("/path/to/ipadic")
  .build();

const results = tokenizer.tokenizeNbest("すもももももももものうち", 3);
for (const { tokens, cost } of results) {
  const surfaces = tokens.map((t) => t.surface);
  console.log(`Cost ${cost}: ${surfaces.join(" / ")}`);
}

TypeScript

Lindera Node.js には TypeScript の型定義が含まれています。すべてのクラスと関数に完全な型が付いています:

import { TokenizerBuilder, Token } from "lindera-nodejs";

const tokenizer = new TokenizerBuilder()
  .setMode("normal")
  .setDictionary("/path/to/ipadic")
  .build();

const tokens: Token[] = tokenizer.tokenize("形態素解析");
for (const token of tokens) {
  console.log(`${token.surface}: ${token.details?.join(",")}`);
}

Tokenizer API

TokenizerBuilder

TokenizerBuilder はビルダーパターンを使用して Tokenizer インスタンスを設定・構築します。

コンストラクタ

new TokenizerBuilder()

デフォルト設定で新しいビルダーを作成します。

const { TokenizerBuilder } = require("lindera-nodejs");

const builder = new TokenizerBuilder();

new TokenizerBuilder().fromFile(filePath)

JSON ファイルから設定を読み込み、新しいビルダーを返します。

const builder = new TokenizerBuilder().fromFile("config.json");

設定メソッド

すべてのセッターメソッドはメソッドチェーンのために this を返します。

setMode(mode)

トークナイズモードを設定します。

  • "normal" -- 標準的なトークナイズ(デフォルト)
  • "decompose" -- 複合語をより小さな単位に分解
builder.setMode("normal");

setDictionary(path)

システム辞書のパスまたは URI を設定します。

// 埋め込み辞書を使用
builder.setDictionary("embedded://ipadic");

// 外部辞書を使用
builder.setDictionary("/path/to/dictionary");

setUserDictionary(uri)

ユーザー辞書の URI を設定します。

builder.setUserDictionary("/path/to/user_dictionary");

setKeepWhitespace(keep)

出力に空白トークンを含めるかどうかを制御します。

builder.setKeepWhitespace(true);

appendCharacterFilter(kind, args?)

前処理パイプラインに文字フィルタを追加します。

builder.appendCharacterFilter("unicode_normalize", { kind: "nfkc" });

appendTokenFilter(kind, args?)

後処理パイプラインにトークンフィルタを追加します。

builder.appendTokenFilter("lowercase", {});

ビルド

build()

設定された内容で Tokenizer をビルドして返します。

const tokenizer = builder.build();

Tokenizer

Tokenizer はテキストに対して形態素解析を行います。

Tokenizer の作成

new Tokenizer(dictionary, mode?, userDictionary?)

読み込み済みの辞書から直接トークナイザーを作成します。

const { Tokenizer, loadDictionary } = require("lindera-nodejs");

const dictionary = loadDictionary("embedded://ipadic");
const tokenizer = new Tokenizer(dictionary, "normal");

Tokenizer メソッド

tokenize(text)

入力テキストをトークナイズし、Token オブジェクトの配列を返します。

const tokens = tokenizer.tokenize("形態素解析");

パラメータ:

名前説明
textstringトークナイズするテキスト

戻り値: Token[]

tokenizeNbest(text, n, unique?, costThreshold?)

N-best トークナイズ結果を返します。各結果はトークン配列とトータルパスコストを含みます。

const results = tokenizer.tokenizeNbest("すもももももももものうち", 3);
for (const { tokens, cost } of results) {
  console.log(cost, tokens.map((t) => t.surface));
}

パラメータ:

名前説明
textstringトークナイズするテキスト
nnumber返す結果の数
uniqueboolean結果の重複を排除(デフォルト: false
costThresholdnumber | undefined最良パスからの最大コスト差(デフォルト: undefined

戻り値: Array<{ tokens: Token[], cost: number }>

Token

Token は単一の形態素トークンを表します。

プロパティ

プロパティ説明
surfacestringトークンの表層形
byteStartnumber元テキストでの開始バイト位置
byteEndnumber元テキストでの終了バイト位置
positionnumberトークンの位置インデックス
wordIdnumber辞書の単語 ID
isUnknownboolean辞書に登録されていない単語の場合 true
detailsstring[] | null形態素の詳細情報(品詞、読みなど)

Token メソッド

getDetail(index)

指定されたインデックスの詳細文字列を返します。インデックスが範囲外の場合は null を返します。

const token = tokenizer.tokenize("東京")[0];
const pos = token.getDetail(0);      // 例: "名詞"
const subpos = token.getDetail(1);   // 例: "固有名詞"
const reading = token.getDetail(7);  // 例: "トウキョウ"

パラメータ:

名前説明
indexnumberdetails 配列へのゼロベースインデックス

戻り値: string | null

details の構造は辞書によって異なります:

  • IPADIC: [品詞, 品詞細分類1, 品詞細分類2, 品詞細分類3, 活用型, 活用形, 原形, 読み, 発音]
  • UniDic: UniDic 仕様に準拠した詳細な形態素情報
  • ko-dic / CC-CEDICT / Jieba: 各辞書固有の詳細フォーマット

辞書管理

Lindera Node.js は、形態素解析で使用する辞書の読み込み、ビルド、管理のための関数を提供します。

辞書の読み込み

システム辞書

loadDictionary(uri) を使用してシステム辞書を読み込みます。GitHub Releases からビルド済み辞書をダウンロードし、展開したディレクトリのパスを指定してください:

const { loadDictionary } = require("lindera-nodejs");

const dictionary = loadDictionary("/path/to/ipadic");

埋め込み辞書(上級者向け) -- embed-* feature フラグ付きでビルドした場合、埋め込み辞書を使用できます:

const dictionary = loadDictionary("embedded://ipadic");

ユーザー辞書

ユーザー辞書はシステム辞書にカスタム語彙を追加します。

const { loadUserDictionary, Metadata } = require("lindera-nodejs");

const metadata = new Metadata();
const userDict = loadUserDictionary("/path/to/user_dictionary", metadata);

トークナイザーのビルド時にユーザー辞書を渡します:

const { Tokenizer, loadDictionary, loadUserDictionary, Metadata } = require("lindera-nodejs");

const dictionary = loadDictionary("/path/to/ipadic");
const metadata = new Metadata();
const userDict = loadUserDictionary("/path/to/user_dictionary", metadata);

const tokenizer = new Tokenizer(dictionary, "normal", userDict);

または、ビルダー経由で設定します:

const { TokenizerBuilder } = require("lindera-nodejs");

const tokenizer = new TokenizerBuilder()
  .setDictionary("/path/to/ipadic")
  .setUserDictionary("/path/to/user_dictionary")
  .build();

辞書のビルド

システム辞書のビルド

ソースファイルからシステム辞書をビルドします:

const { buildDictionary, Metadata } = require("lindera-nodejs");

const metadata = new Metadata({ name: "custom", encoding: "UTF-8" });
buildDictionary("/path/to/input_dir", "/path/to/output_dir", metadata);

入力ディレクトリには辞書のソースファイル(CSV レキシコン、matrix.def など)が含まれている必要があります。

ユーザー辞書のビルド

CSV ファイルからユーザー辞書をビルドします:

const { buildUserDictionary, Metadata } = require("lindera-nodejs");

const metadata = new Metadata();
buildUserDictionary("ipadic", "user_words.csv", "/path/to/output_dir", metadata);

metadata パラメータは省略可能です。省略した場合はデフォルトのメタデータ値が使用されます:

buildUserDictionary("ipadic", "user_words.csv", "/path/to/output_dir");

Metadata

Metadata クラスは辞書のパラメータを設定します。

Metadata の作成

const { Metadata } = require("lindera-nodejs");

// デフォルトのメタデータ
const metadata = new Metadata();

// カスタムメタデータ
const metadata = new Metadata({
  name: "my_dictionary",
  encoding: "UTF-8",
  defaultWordCost: -10000,
});

JSON からの読み込み

const metadata = Metadata.fromJsonFile("metadata.json");

プロパティ

プロパティデフォルト説明
namestring"default"辞書名
encodingstring"UTF-8"文字エンコーディング
defaultWordCostnumber-10000未知語のデフォルトコスト
defaultLeftContextIdnumber1288デフォルトの左文脈 ID
defaultRightContextIdnumber1288デフォルトの右文脈 ID
defaultFieldValuestring"*"欠損フィールドのデフォルト値
flexibleCsvbooleanfalse柔軟な CSV パースを許可
skipInvalidCostOrIdbooleanfalse無効なコストまたは ID のエントリーをスキップ
normalizeDetailsbooleanfalse形態素の詳細情報を正規化
dictionarySchemaSchemaIPADIC スキーマメイン辞書のスキーマ
userDictionarySchemaSchema最小スキーマユーザー辞書のスキーマ

すべてのプロパティは取得と設定の両方をサポートしています:

const metadata = new Metadata();
metadata.name = "custom_dict";
metadata.encoding = "EUC-JP";
console.log(metadata.name); // "custom_dict"

toObject()

メタデータのオブジェクト表現を返します:

const metadata = new Metadata({ name: "test" });
console.log(metadata.toObject());

Schema

Schema クラスは辞書エントリーのフィールド構造を定義します。

Schema の作成

const { Schema } = require("lindera-nodejs");

// デフォルトの IPADIC 互換スキーマ
const schema = Schema.createDefault();

// カスタムスキーマ
const custom = new Schema(["surface", "left_id", "right_id", "cost", "pos", "reading"]);

Schema メソッド

メソッド戻り値説明
getFieldIndex(name)number | nullフィールド名からインデックスを取得
fieldCount()numberフィールドの総数
getFieldName(index)string | nullインデックスからフィールド名を取得
getCustomFields()string[]インデックス 4 以降のフィールド(形態素素性)
getAllFields()string[]すべてのフィールド名
getFieldByName(name)FieldDefinition | nullフィールド定義の完全な情報を取得
validateRecord(record)voidCSV レコードをスキーマに対して検証
const schema = Schema.createDefault();

console.log(schema.fieldCount());           // 13(IPADIC フォーマット)
console.log(schema.getFieldIndex("pos1"));  // 例: 4
console.log(schema.getAllFields());          // ["surface", "left_id", ...]
console.log(schema.getCustomFields());      // インデックス 4 以降のフィールド

FieldDefinition

プロパティ説明
indexnumberフィールドの位置インデックス
namestringフィールド名
fieldTypeFieldTypeフィールド型の列挙値
descriptionstring | undefined任意の説明

FieldType

説明
FieldType.Surface単語の表層形
FieldType.LeftContextId左文脈 ID
FieldType.RightContextId右文脈 ID
FieldType.Cost単語コスト
FieldType.Custom形態素素性フィールド

テキスト処理パイプライン

Lindera Node.js は、トークナイズ前に文字フィルタを適用し、トークナイズ後にトークンフィルタを適用する、組み合わせ可能なテキスト処理パイプラインをサポートしています。フィルタは TokenizerBuilder に追加され、追加された順序で実行されます。

Input Text
  --> Character Filters (preprocessing)
  --> Tokenization
  --> Token Filters (postprocessing)
  --> Output Tokens

文字フィルタ

文字フィルタはトークナイズ前に入力テキストを変換します。

unicode_normalize

入力テキストに Unicode 正規化を適用します。

const { TokenizerBuilder } = require("lindera-nodejs");

const tokenizer = new TokenizerBuilder()
  .setDictionary("embedded://ipadic")
  .appendCharacterFilter("unicode_normalize", { kind: "nfkc" })
  .build();

サポートされる正規化形式: "nfc""nfkc""nfd""nfkd"

mapping

マッピングテーブルに従って文字や文字列を置換します。

const tokenizer = new TokenizerBuilder()
  .setDictionary("embedded://ipadic")
  .appendCharacterFilter("mapping", {
    mapping: {
      "\u30fc": "-",
      "\uff5e": "~",
    },
  })
  .build();

japanese_iteration_mark

日本語の踊り字(繰り返し記号)を完全な形に展開します。

const tokenizer = new TokenizerBuilder()
  .setDictionary("embedded://ipadic")
  .appendCharacterFilter("japanese_iteration_mark", {
    normalize_kanji: true,
    normalize_kana: true,
  })
  .build();

トークンフィルタ

トークンフィルタはトークナイズ後にトークンを変換または除去します。

lowercase

トークンの表層形を小文字に変換します。

const tokenizer = new TokenizerBuilder()
  .setDictionary("embedded://ipadic")
  .appendTokenFilter("lowercase", {})
  .build();

japanese_base_form

辞書の形態素情報を使用して、活用形を基本形(辞書形)に置換します。

const tokenizer = new TokenizerBuilder()
  .setDictionary("embedded://ipadic")
  .appendTokenFilter("japanese_base_form", {})
  .build();

japanese_stop_tags

指定されたタグに一致する品詞のトークンを除去します。

const tokenizer = new TokenizerBuilder()
  .setDictionary("embedded://ipadic")
  .appendTokenFilter("japanese_stop_tags", {
    tags: ["助詞", "助動詞"],
  })
  .build();

japanese_keep_tags

指定されたタグに一致する品詞のトークンのみを保持します。その他のトークンはすべて除去されます。

const tokenizer = new TokenizerBuilder()
  .setDictionary("embedded://ipadic")
  .appendTokenFilter("japanese_keep_tags", {
    tags: ["名詞"],
  })
  .build();

パイプラインの完全な例

以下の例では、複数の文字フィルタとトークンフィルタを1つのパイプラインに組み合わせています:

const { TokenizerBuilder } = require("lindera-nodejs");

const tokenizer = new TokenizerBuilder()
  .setMode("normal")
  .setDictionary("embedded://ipadic")
  // Preprocessing
  .appendCharacterFilter("unicode_normalize", { kind: "nfkc" })
  .appendCharacterFilter("japanese_iteration_mark", {
    normalize_kanji: true,
    normalize_kana: true,
  })
  // Postprocessing
  .appendTokenFilter("japanese_base_form", {})
  .appendTokenFilter("japanese_stop_tags", {
    tags: ["助詞", "助動詞", "記号"],
  })
  .appendTokenFilter("lowercase", {})
  .build();

const tokens = tokenizer.tokenize("Linderaは形態素解析を行うライブラリです。");
for (const token of tokens) {
  console.log(`${token.surface}\t${token.details.join(",")}`);
}

このパイプラインでは:

  1. unicode_normalize が全角文字を半角に変換(NFKC 正規化)
  2. japanese_iteration_mark が踊り字を展開
  3. japanese_base_form が活用形のトークンを基本形に変換
  4. japanese_stop_tags が助詞、助動詞、記号を除去
  5. lowercase がアルファベットを小文字に正規化

学習

Lindera Node.js は、アノテーション付きコーパスからカスタム CRF ベースの形態素解析モデルを学習する機能をサポートしています。この機能には train feature が必要です。

前提条件

train feature を有効にして lindera-nodejs をビルドします(デフォルトで有効):

npm run build -- --features train

モデルの学習

train() を使用して、種辞書とアノテーション付きコーパスから CRF モデルを学習します:

const { train } = require("lindera-nodejs");

train({
  seed: "resources/training/seed.csv",
  corpus: "resources/training/corpus.txt",
  charDef: "resources/training/char.def",
  unkDef: "resources/training/unk.def",
  featureDef: "resources/training/feature.def",
  rewriteDef: "resources/training/rewrite.def",
  output: "/tmp/model.dat",
  lambda: 0.01,
  maxIter: 100,
  maxThreads: 4,
});

学習パラメータ

パラメータデフォルト説明
seedstring必須種辞書ファイルのパス(CSV 形式)
corpusstring必須アノテーション付き学習コーパスのパス
charDefstring必須文字定義ファイルのパス(char.def)
unkDefstring必須未知語定義ファイルのパス(unk.def)
featureDefstring必須素性定義ファイルのパス(feature.def)
rewriteDefstring必須書き換えルール定義ファイルのパス(rewrite.def)
outputstring必須学習済みモデルファイルの出力パス
lambdanumber0.01L1 正則化コスト(0.0--1.0)
maxIternumber100最大学習イテレーション数
maxThreadsnumber | undefinedundefinedスレッド数(undefined = CPU コア数を自動検出)

学習済みモデルのエクスポート

学習後、exportModel() を使用してモデルを辞書ソースファイルにエクスポートします:

const { exportModel } = require("lindera-nodejs");

exportModel({
  model: "/tmp/model.dat",
  output: "/tmp/dictionary_source",
  metadata: "resources/training/metadata.json",
});

エクスポートパラメータ

パラメータデフォルト説明
modelstring必須学習済みモデルファイルのパス(.dat)
outputstring必須辞書ソースファイルの出力ディレクトリ
metadatastring | undefinedundefinedベースとなる metadata.json ファイルのパス

エクスポートにより、出力ディレクトリに以下のファイルが作成されます:

  • lex.csv -- 学習済みコスト付きのレキシコンエントリー
  • matrix.def -- 連接コスト行列
  • unk.def -- 未知語定義
  • char.def -- 文字カテゴリ定義
  • metadata.json -- 更新されたメタデータ(metadata パラメータ指定時)

完全なワークフロー

カスタム辞書の学習と使用の完全なワークフロー:

const {
  train,
  exportModel,
  buildDictionary,
  Metadata,
  TokenizerBuilder,
} = require("lindera-nodejs");

// Step 1: Train the CRF model
train({
  seed: "resources/training/seed.csv",
  corpus: "resources/training/corpus.txt",
  charDef: "resources/training/char.def",
  unkDef: "resources/training/unk.def",
  featureDef: "resources/training/feature.def",
  rewriteDef: "resources/training/rewrite.def",
  output: "/tmp/model.dat",
  lambda: 0.01,
  maxIter: 100,
});

// Step 2: Export to dictionary source files
exportModel({
  model: "/tmp/model.dat",
  output: "/tmp/dictionary_source",
  metadata: "resources/training/metadata.json",
});

// Step 3: Build the dictionary from exported source files
const metadata = Metadata.fromJsonFile("/tmp/dictionary_source/metadata.json");
buildDictionary("/tmp/dictionary_source", "/tmp/dictionary", metadata);

// Step 4: Use the trained dictionary
const tokenizer = new TokenizerBuilder()
  .setDictionary("/tmp/dictionary")
  .setMode("normal")
  .build();

const tokens = tokenizer.tokenize("形態素解析のテスト");
for (const token of tokens) {
  console.log(`${token.surface}\t${token.details.join(",")}`);
}

Lindera Ruby

Lindera Ruby は、Magnusrb-sys を使用して構築された Lindera 形態素解析エンジンの Ruby バインディングです。Ruby 3.1 以降をサポートし、Lindera の高性能なトークナイズ機能を Ruby エコシステムに提供します。

特徴

  • 多言語対応: 日本語(IPADIC、IPADIC NEologd、UniDic)、韓国語(ko-dic)、中国語(CC-CEDICT、Jieba)のテキストをトークナイズ
  • テキスト処理パイプライン: 文字フィルタとトークンフィルタを組み合わせて、柔軟な前処理・後処理が可能
  • CRF ベースの辞書学習: アノテーション付きコーパスからカスタム形態素解析モデルを学習(train feature が必要)
  • 複数のトークナイズモード: 解析粒度に応じた Normal モードと Decompose モード
  • N-best トークナイズ: コスト順にランク付けされた複数のトークナイズ候補を取得
  • ユーザー辞書: システム辞書をカスタム語彙で拡張

ドキュメント

インストール

[!NOTE] lindera-ruby はまだ RubyGems に公開されていません。ソースからビルドする必要があります。

前提条件

  • Ruby 3.1 以降
  • Rust ツールチェーン -- rustup 経由でインストール
  • Bundler -- Ruby の依存関係管理ツール(gem install bundler

辞書の入手

Lindera はパッケージに辞書を同梱していません。ビルド済み辞書を別途入手する必要があります。

GitHub Releases からのダウンロード

ビルド済み辞書は GitHub Releases ページから入手できます。辞書アーカイブをダウンロードしてローカルディレクトリに展開してください:

# 例: IPADIC 辞書のダウンロードと展開
curl -LO https://github.com/lindera/lindera/releases/download/<version>/lindera-ipadic-<version>.zip
unzip lindera-ipadic-<version>.zip -d /path/to/ipadic

開発ビルド

lindera-ruby を開発モードでビルドしてインストールします:

cd lindera-ruby
bundle install
bundle exec rake compile

または、プロジェクトの Makefile を使用します:

make ruby-develop

学習機能付きビルド

train feature を有効にすると、CRF ベースの辞書学習機能が利用可能になります:

LINDERA_FEATURES="train" bundle exec rake compile

Feature フラグ

Feature は環境変数 LINDERA_FEATURES にカンマ区切りリストで指定します。

Feature説明デフォルト
trainCRF 学習機能無効
embed-ipadic日本語辞書(IPADIC)をバイナリに埋め込み無効
embed-unidic日本語辞書(UniDic)をバイナリに埋め込み無効
embed-ipadic-neologd日本語辞書(IPADIC NEologd)をバイナリに埋め込み無効
embed-ko-dic韓国語辞書(ko-dic)をバイナリに埋め込み無効
embed-cc-cedict中国語辞書(CC-CEDICT)をバイナリに埋め込み無効
embed-jieba中国語辞書(Jieba)をバイナリに埋め込み無効
embed-cjk全 CJK 辞書をバイナリに埋め込み(IPADIC、ko-dic、Jieba)無効

複数の feature を組み合わせることができます:

LINDERA_FEATURES="train,embed-ipadic,embed-ko-dic" bundle exec rake compile

[!TIP] 辞書をバイナリに直接埋め込みたい場合(上級者向け)は、対応する embed-* feature フラグを有効にしてビルドし、embedded:// スキームでロードしてください:

dictionary = Lindera.load_dictionary("embedded://ipadic")

詳細は Feature フラグ を参照してください。

インストールの確認

インストール後、Ruby で lindera が利用可能であることを確認します:

require 'lindera'

puts Lindera.version

クイックスタート

このガイドでは、lindera-ruby を使用してテキストをトークナイズする方法を紹介します。

基本的なトークナイズ

トークナイザーの作成には Lindera::TokenizerBuilder の使用を推奨します:

require 'lindera'

builder = Lindera::TokenizerBuilder.new
builder.set_mode('normal')
builder.set_dictionary('/path/to/ipadic')
tokenizer = builder.build

tokens = tokenizer.tokenize('関西国際空港限定トートバッグ')
tokens.each do |token|
  puts "#{token.surface}\t#{token.details.join(',')}"
end

注意: ビルド済み辞書を GitHub Releases からダウンロードし、展開したディレクトリのパスを指定してください。

期待される出力:

関西国際空港    名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
限定    名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ    UNK

逐次的な設定

TokenizerBuilder は逐次的なメソッド呼び出しで設定します:

require 'lindera'

builder = Lindera::TokenizerBuilder.new
builder.set_mode('normal')
builder.set_dictionary('/path/to/ipadic')
tokenizer = builder.build

tokens = tokenizer.tokenize('すもももももももものうち')
tokens.each do |token|
  puts "#{token.surface}\t#{token.get_detail(0)}"
end

トークンプロパティへのアクセス

各トークンは以下のプロパティを公開しています:

require 'lindera'

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('/path/to/ipadic')
tokenizer = builder.build

tokens = tokenizer.tokenize('東京タワー')

tokens.each do |token|
  puts "Surface: #{token.surface}"
  puts "Byte range: #{token.byte_start}..#{token.byte_end}"
  puts "Position: #{token.position}"
  puts "Word ID: #{token.word_id}"
  puts "Unknown: #{token.is_unknown}"
  puts "Details: #{token.details}"
  puts
end

N-best トークナイズ

コスト順にランク付けされた複数のトークナイズ候補を取得します:

require 'lindera'

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('/path/to/ipadic')
tokenizer = builder.build

results = tokenizer.tokenize_nbest('すもももももももものうち', 3, false, nil)

results.each do |tokens, cost|
  surfaces = tokens.map(&:surface)
  puts "Cost #{cost}: #{surfaces.join(' / ')}"
end

Tokenizer API

TokenizerBuilder

Lindera::TokenizerBuilder はビルダーパターンを使用して Tokenizer インスタンスを設定・構築します。

コンストラクタ

Lindera::TokenizerBuilder.new

デフォルト設定で新しいビルダーを作成します。

require 'lindera'

builder = Lindera::TokenizerBuilder.new

設定メソッド

set_mode(mode)

トークナイズモードを設定します。

  • "normal" -- 標準的なトークナイズ(デフォルト)
  • "decompose" -- 複合語をより小さな単位に分解
builder.set_mode('normal')

set_dictionary(path)

システム辞書のパスまたは URI を設定します。

# 埋め込み辞書を使用
builder.set_dictionary('embedded://ipadic')

# 外部辞書を使用
builder.set_dictionary('/path/to/dictionary')

set_user_dictionary(uri)

ユーザー辞書の URI を設定します。

builder.set_user_dictionary('/path/to/user_dictionary')

set_keep_whitespace(keep)

出力に空白トークンを含めるかどうかを制御します。

builder.set_keep_whitespace(true)

append_character_filter(kind, args)

前処理パイプラインに文字フィルタを追加します。

builder.append_character_filter('unicode_normalize', { 'kind' => 'nfkc' })

append_token_filter(kind, args)

後処理パイプラインにトークンフィルタを追加します。args が不要な場合は nil を渡します。

builder.append_token_filter('lowercase', nil)

ビルド

build

設定された内容で Tokenizer をビルドして返します。

tokenizer = builder.build

Tokenizer

Lindera::Tokenizer はテキストに対して形態素解析を行います。

Tokenizer の作成

Lindera::Tokenizer.new(dictionary, mode, user_dictionary)

読み込み済みの辞書から直接トークナイザーを作成します。user_dictionary が不要な場合は nil を渡します。

require 'lindera'

dictionary = Lindera.load_dictionary('embedded://ipadic')
tokenizer = Lindera::Tokenizer.new(dictionary, 'normal', nil)

ユーザー辞書を使用する場合:

dictionary = Lindera.load_dictionary('embedded://ipadic')
metadata = dictionary.metadata
user_dict = Lindera.load_user_dictionary('/path/to/user_dictionary', metadata)
tokenizer = Lindera::Tokenizer.new(dictionary, 'normal', user_dict)

Tokenizer メソッド

tokenize(text)

入力テキストをトークナイズし、Token オブジェクトの配列を返します。

tokens = tokenizer.tokenize('形態素解析')

パラメータ:

名前説明
textStringトークナイズするテキスト

戻り値: Array<Token>

tokenize_nbest(text, n, unique, cost_threshold)

N-best トークナイズ結果を返します。各結果はトータルパスコストとペアになっています。

results = tokenizer.tokenize_nbest('すもももももももものうち', 3, false, nil)
results.each do |tokens, cost|
  puts "#{cost}: #{tokens.map(&:surface).join(' / ')}"
end

パラメータ:

名前説明
textStringトークナイズするテキスト
nInteger返す結果の数
uniqueBoolean結果の重複を排除(false で無効)
cost_thresholdInteger または nil最良パスからの最大コスト差(nil で無制限)

戻り値: Array<[Array<Token>, Integer]>

Token

Token は単一の形態素トークンを表します。

プロパティ

プロパティ説明
surfaceStringトークンの表層形
byte_startInteger元テキストでの開始バイト位置
byte_endInteger元テキストでの終了バイト位置
positionIntegerトークンの位置インデックス
word_idInteger辞書の単語 ID
is_unknownBoolean辞書に登録されていない単語の場合 true
detailsArray<String> または nil形態素の詳細情報(品詞、読みなど)

Token メソッド

get_detail(index)

指定されたインデックスの詳細文字列を返します。インデックスが範囲外の場合は nil を返します。

token = tokenizer.tokenize('東京')[0]
pos = token.get_detail(0)        # 例: "名詞"
subpos = token.get_detail(1)     # 例: "固有名詞"
reading = token.get_detail(7)    # 例: "トウキョウ"

パラメータ:

名前説明
indexIntegerdetails 配列へのゼロベースインデックス

戻り値: String または nil

details の構造は辞書によって異なります:

  • IPADIC: [品詞, 品詞細分類1, 品詞細分類2, 品詞細分類3, 活用型, 活用形, 原形, 読み, 発音]
  • UniDic: UniDic 仕様に準拠した詳細な形態素情報
  • ko-dic / CC-CEDICT / Jieba: 各辞書固有の詳細フォーマット

辞書管理

Lindera Ruby は、形態素解析で使用する辞書の読み込み、ビルド、管理のためのメソッドを提供します。

辞書の読み込み

システム辞書

Lindera.load_dictionary(uri) を使用してシステム辞書を読み込みます。GitHub Releases からビルド済み辞書をダウンロードし、展開したディレクトリのパスを指定してください:

require 'lindera'

dictionary = Lindera.load_dictionary('/path/to/ipadic')

埋め込み辞書(上級者向け) -- embed-* feature フラグ付きでビルドした場合、埋め込み辞書を使用できます:

dictionary = Lindera.load_dictionary('embedded://ipadic')

ユーザー辞書

ユーザー辞書はシステム辞書にカスタム語彙を追加します。

require 'lindera'

dictionary = Lindera.load_dictionary('/path/to/ipadic')
metadata = dictionary.metadata
user_dict = Lindera.load_user_dictionary('/path/to/user_dictionary', metadata)

トークナイザーの作成時にユーザー辞書を渡します:

require 'lindera'

dictionary = Lindera.load_dictionary('/path/to/ipadic')
metadata = dictionary.metadata
user_dict = Lindera.load_user_dictionary('/path/to/user_dictionary', metadata)

tokenizer = Lindera::Tokenizer.new(dictionary, 'normal', user_dict)

または、ビルダー経由で設定します:

require 'lindera'

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('/path/to/ipadic')
builder.set_user_dictionary('/path/to/user_dictionary')
tokenizer = builder.build

辞書のビルド

システム辞書のビルド

ソースファイルからシステム辞書をビルドします:

require 'lindera'

metadata = Lindera::Metadata.from_json_file('metadata.json')
Lindera.build_dictionary('/path/to/input_dir', '/path/to/output_dir', metadata)

入力ディレクトリには辞書のソースファイル(CSV レキシコン、matrix.def など)が含まれている必要があります。

ユーザー辞書のビルド

CSV ファイルからユーザー辞書をビルドします:

require 'lindera'

metadata = Lindera::Metadata.new
Lindera.build_user_dictionary('ipadic', 'user_words.csv', '/path/to/output_dir', metadata)

Metadata

Lindera::Metadata クラスは辞書のパラメータを設定します。

Metadata の作成

require 'lindera'

# デフォルトのメタデータ
metadata = Lindera::Metadata.new

# JSON ファイルからの読み込み
metadata = Lindera::Metadata.from_json_file('metadata.json')

辞書からのメタデータ取得

読み込み済みの辞書からメタデータを取得できます:

dictionary = Lindera.load_dictionary('/path/to/ipadic')
metadata = dictionary.metadata

プロパティ

プロパティデフォルト説明
nameString"default"辞書名
encodingString"UTF-8"文字エンコーディング
default_word_costInteger-10000未知語のデフォルトコスト
default_left_context_idInteger1288デフォルトの左文脈 ID
default_right_context_idInteger1288デフォルトの右文脈 ID
default_field_valueString"*"欠損フィールドのデフォルト値
flexible_csvBooleanfalse柔軟な CSV パースを許可
skip_invalid_cost_or_idBooleanfalse無効なコストまたは ID のエントリーをスキップ
normalize_detailsBooleanfalse形態素の詳細情報を正規化

テキスト処理パイプライン

Lindera Ruby は、トークナイズ前に文字フィルタを適用し、トークナイズ後にトークンフィルタを適用する、組み合わせ可能なテキスト処理パイプラインをサポートしています。フィルタは Lindera::TokenizerBuilder に追加され、追加された順序で実行されます。

Input Text
  --> Character Filters (preprocessing)
  --> Tokenization
  --> Token Filters (postprocessing)
  --> Output Tokens

文字フィルタ

文字フィルタはトークナイズ前に入力テキストを変換します。

unicode_normalize

入力テキストに Unicode 正規化を適用します。

require 'lindera'

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('embedded://ipadic')
builder.append_character_filter('unicode_normalize', { 'kind' => 'nfkc' })
tokenizer = builder.build

サポートされる正規化形式: "nfc""nfkc""nfd""nfkd"

mapping

マッピングテーブルに従って文字や文字列を置換します。

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('embedded://ipadic')
builder.append_character_filter('mapping', {
  'mapping' => {
    "\u30fc" => '-',
    "\uff5e" => '~'
  }
})
tokenizer = builder.build

japanese_iteration_mark

日本語の踊り字(繰り返し記号)を完全な形に展開します。

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('embedded://ipadic')
builder.append_character_filter('japanese_iteration_mark', {
  'normalize_kanji' => 'true',
  'normalize_kana' => 'true'
})
tokenizer = builder.build

トークンフィルタ

トークンフィルタはトークナイズ後にトークンを変換または除去します。

lowercase

トークンの表層形を小文字に変換します。

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('embedded://ipadic')
builder.append_token_filter('lowercase', nil)
tokenizer = builder.build

japanese_base_form

辞書の形態素情報を使用して、活用形を基本形(辞書形)に置換します。

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('embedded://ipadic')
builder.append_token_filter('japanese_base_form', nil)
tokenizer = builder.build

japanese_stop_tags

指定されたタグに一致する品詞のトークンを除去します。

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('embedded://ipadic')
builder.append_token_filter('japanese_stop_tags', {
  'tags' => ['助詞', '助動詞']
})
tokenizer = builder.build

japanese_keep_tags

指定されたタグに一致する品詞のトークンのみを保持します。その他のトークンはすべて除去されます。

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('embedded://ipadic')
builder.append_token_filter('japanese_keep_tags', {
  'tags' => ['名詞']
})
tokenizer = builder.build

japanese_katakana_stem

カタカナ語の末尾にある長音記号を除去します。最小文字数を指定できます。

builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('embedded://ipadic')
builder.append_token_filter('japanese_katakana_stem', { 'min' => 3 })
tokenizer = builder.build

パイプラインの完全な例

以下の例では、複数の文字フィルタとトークンフィルタを1つのパイプラインに組み合わせています:

require 'lindera'

builder = Lindera::TokenizerBuilder.new
builder.set_mode('normal')
builder.set_dictionary('embedded://ipadic')

# Preprocessing
builder.append_character_filter('unicode_normalize', { 'kind' => 'nfkc' })
builder.append_character_filter('japanese_iteration_mark', {
  'normalize_kanji' => 'true',
  'normalize_kana' => 'true'
})

# Postprocessing
builder.append_token_filter('japanese_base_form', nil)
builder.append_token_filter('japanese_stop_tags', {
  'tags' => ['助詞', '助動詞', '記号']
})
builder.append_token_filter('lowercase', nil)

tokenizer = builder.build

tokens = tokenizer.tokenize('Linderaは形態素解析を行うライブラリです。')
tokens.each do |token|
  puts "#{token.surface}\t#{token.details.join(',')}"
end

このパイプラインでは:

  1. unicode_normalize が全角文字を半角に変換(NFKC 正規化)
  2. japanese_iteration_mark が踊り字を展開
  3. japanese_base_form が活用形のトークンを基本形に変換
  4. japanese_stop_tags が助詞、助動詞、記号を除去
  5. lowercase がアルファベットを小文字に正規化

学習

Lindera Ruby は、アノテーション付きコーパスからカスタム CRF ベースの形態素解析モデルを学習する機能をサポートしています。この機能には train feature が必要です。

前提条件

train feature を有効にして lindera-ruby をビルドします:

LINDERA_FEATURES="embed-ipadic,train" bundle exec rake compile

モデルの学習

Lindera.train を使用して、種辞書とアノテーション付きコーパスから CRF モデルを学習します:

require 'lindera'

Lindera.train(
  'resources/training/seed.csv',
  'resources/training/corpus.txt',
  'resources/training/char.def',
  'resources/training/unk.def',
  'resources/training/feature.def',
  'resources/training/rewrite.def',
  '/tmp/model.dat',
  0.01,   # lambda (L1 regularization)
  100,    # max_iter
  nil     # max_threads (nil = auto-detect)
)

学習パラメータ

Lindera.train の引数は位置引数として順番に渡します:

順番パラメータ説明
1seedString種辞書ファイルのパス(CSV 形式)
2corpusStringアノテーション付き学習コーパスのパス
3char_defString文字定義ファイルのパス(char.def)
4unk_defString未知語定義ファイルのパス(unk.def)
5feature_defString素性定義ファイルのパス(feature.def)
6rewrite_defString書き換えルール定義ファイルのパス(rewrite.def)
7outputString学習済みモデルファイルの出力パス
8lambdaFloatL1 正則化コスト(0.0--1.0)
9max_iterInteger最大学習イテレーション数
10max_threadsInteger または nilスレッド数(nil = CPU コア数を自動検出)

学習済みモデルのエクスポート

学習後、Lindera.export を使用してモデルを辞書ソースファイルにエクスポートします:

require 'lindera'

Lindera.export('/tmp/model.dat', '/tmp/dictionary_source', 'resources/training/metadata.json')

エクスポートパラメータ

順番パラメータ説明
1modelString学習済みモデルファイルのパス(.dat)
2outputString辞書ソースファイルの出力ディレクトリ
3metadataString または nilベースとなる metadata.json ファイルのパス

エクスポートにより、出力ディレクトリに以下のファイルが作成されます:

  • lex.csv -- 学習済みコスト付きのレキシコンエントリー
  • matrix.def -- 連接コスト行列
  • unk.def -- 未知語定義
  • char.def -- 文字カテゴリ定義
  • metadata.json -- 更新されたメタデータ(metadata パラメータ指定時)

完全なワークフロー

カスタム辞書の学習と使用の完全なワークフロー:

require 'lindera'

# Step 1: Train the CRF model
Lindera.train(
  'resources/training/seed.csv',
  'resources/training/corpus.txt',
  'resources/training/char.def',
  'resources/training/unk.def',
  'resources/training/feature.def',
  'resources/training/rewrite.def',
  '/tmp/model.dat',
  0.01,  # lambda
  100,   # max_iter
  nil    # max_threads
)

# Step 2: Export to dictionary source files
Lindera.export('/tmp/model.dat', '/tmp/dictionary_source', 'resources/training/metadata.json')

# Step 3: Build the dictionary from exported source files
metadata = Lindera::Metadata.from_json_file('/tmp/dictionary_source/metadata.json')
Lindera.build_dictionary('/tmp/dictionary_source', '/tmp/dictionary', metadata)

# Step 4: Use the trained dictionary
builder = Lindera::TokenizerBuilder.new
builder.set_dictionary('/tmp/dictionary')
builder.set_mode('normal')
tokenizer = builder.build

tokens = tokenizer.tokenize('形態素解析のテスト')
tokens.each do |token|
  puts "#{token.surface}\t#{token.details.join(',')}"
end

Lindera PHP

Lindera PHP は、ext-php-rs を使用して構築された Lindera 形態素解析エンジンの PHP バインディングです。PHP 8.1 以降をサポートし、Lindera の高性能なトークナイズ機能を PHP エコシステムに提供します。

特徴

  • 多言語対応: 日本語(IPADIC、IPADIC NEologd、UniDic)、韓国語(ko-dic)、中国語(CC-CEDICT、Jieba)のテキストをトークナイズ
  • テキスト処理パイプライン: 文字フィルタとトークンフィルタを組み合わせて、柔軟な前処理・後処理が可能
  • CRF ベースの辞書学習: アノテーション付きコーパスからカスタム形態素解析モデルを学習(train feature が必要)
  • 複数のトークナイズモード: 解析粒度に応じた Normal モードと Decompose モード
  • N-best トークナイズ: コスト順にランク付けされた複数のトークナイズ候補を取得
  • ユーザー辞書: システム辞書をカスタム語彙で拡張

ドキュメント

インストール

[!NOTE] lindera-php はまだ Packagist に公開されていません。ソースからビルドする必要があります。

前提条件

  • PHP 8.1 以降
  • Rust ツールチェーン -- rustup 経由でインストール
  • Composer -- PHP の依存関係管理(テスト実行時に必要)

辞書の入手

Lindera はパッケージに辞書を同梱していません。ビルド済み辞書を別途入手する必要があります。

GitHub Releases からのダウンロード

ビルド済み辞書は GitHub Releases ページから入手で���ます。辞書アーカイブをダウンロードしてローカルディレクトリに展開してください:

# 例: IPADIC 辞書のダウンロードと展開
curl -LO https://github.com/lindera/lindera/releases/download/<version>/lindera-ipadic-<version>.zip
unzip lindera-ipadic-<version>.zip -d /path/to/ipadic

ビルド

lindera-php をビルドします:

cargo build -p lindera-php

または、プロジェクトの Makefile を使用します:

make php-build

学習機能付きビルド

train feature を有効にすると、CRF ベースの辞書学習機能が利用可能になります。デフォルトで有効になっています:

cargo build -p lindera-php --features train

PHP 拡張の読み込み

ビルド後、-d extension= オプションでビルドされた共有ライブラリを指定して PHP を実行します:

php -d extension=target/debug/liblindera_php.so script.php

リリースビルドの場合:

cargo build -p lindera-php --release
php -d extension=target/release/liblindera_php.so script.php

Feature フラグ

Feature説明デフォルト
trainCRF 学習機能有効
embed-ipadic日本語辞書(IPADIC)をバイナリに埋め込み無効
embed-unidic日本語辞書(UniDic)をバイナリに埋め込み無効
embed-ipadic-neologd日本語辞書(IPADIC NEologd)をバイナリに埋め込み無効
embed-ko-dic韓国語辞書(ko-dic)をバイナリに埋め込み無効
embed-cc-cedict中国語辞書(CC-CEDICT)をバイナリに埋め込み無効
embed-jieba中国語辞書(Jieba)をバイナリに埋め込み無効
embed-cjk全 CJK 辞書をバイナリに埋め込み(IPADIC、ko-dic、Jieba)無効

複数の feature を組み合わせることができます:

cargo build -p lindera-php --features "train,embed-ipadic,embed-ko-dic"

[!TIP] 辞書をバイナリに直接埋め込みたい場合(上級者向け)は、対応する embed-* feature フラグを有効にしてビルドし、embedded:// スキームでロードしてください:

$dictionary = Lindera\Dictionary::load('embedded://ipadic');

詳細は Feature フラグ を参照してください。

インストールの確認

インストール後、PHP で lindera が利用可能であることを確認します:

<?php

$version = Lindera\Dictionary::version();
echo "Lindera version: {$version}\n";

実行方法:

php -d extension=target/debug/liblindera_php.so script.php

クイックスタート

このガイドでは、lindera-php を使用してテキストをトークナイズする方法を紹介します。

基本的なトークナイズ

辞書を読み込み、トークナイザーを作成してテキストをトークナイズします:

<?php

// Load the dictionary
$dictionary = Lindera\Dictionary::load('/path/to/ipadic');

// Create a tokenizer
$tokenizer = new Lindera\Tokenizer($dictionary, 'normal');

// Tokenize the text
$tokens = $tokenizer->tokenize('関西国際空港限定トートバッグ');
foreach ($tokens as $token) {
    echo $token->surface . "\t" . implode(',', $token->details) . "\n";
}

注意: ビルド済み辞書を GitHub Releases からダウンロードし、展開したディレクトリのパスを指定してください。

期待される出力:

関西国際空港    名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
限定    名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ    UNK

TokenizerBuilder の使用

TokenizerBuilder を使用すると、より柔軟にトークナイザーを設定できます:

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setMode('normal');
$builder->setDictionary('/path/to/ipadic');
$tokenizer = $builder->build();

$tokens = $tokenizer->tokenize('すもももももももものうち');
foreach ($tokens as $token) {
    echo $token->surface . "\t" . $token->getDetail(0) . "\n";
}

トークンプロパティへのアクセス

各トークンは以下のプロパティを公開しています:

<?php

$dictionary = Lindera\Dictionary::load('/path/to/ipadic');
$tokenizer = new Lindera\Tokenizer($dictionary, 'normal');
$tokens = $tokenizer->tokenize('東京タワー');

foreach ($tokens as $token) {
    echo "Surface: {$token->surface}\n";
    echo "Byte range: {$token->byte_start}..{$token->byte_end}\n";
    echo "Position: {$token->position}\n";
    echo "Word ID: {$token->word_id}\n";
    echo "Unknown: " . ($token->is_unknown ? 'true' : 'false') . "\n";
    echo "Details: " . implode(',', $token->details) . "\n";
    echo "\n";
}

N-best トークナイズ

コスト順にランク付けされた複数のトークナイズ候補を取得します:

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setDictionary('/path/to/ipadic');
$tokenizer = $builder->build();

$results = $tokenizer->tokenizeNbest('東京都', 3);
foreach ($results as $result) {
    $surfaces = array_map(fn($t) => $t->surface, $result->tokens);
    echo "Cost {$result->cost}: " . implode(' / ', $surfaces) . "\n";
}

Decompose モード

Decompose モードでは、複合語をより小さな単位に分解します:

<?php

$dictionary = Lindera\Dictionary::load('/path/to/ipadic');
$tokenizer = new Lindera\Tokenizer($dictionary, 'decompose');

$tokens = $tokenizer->tokenize('関西国際空港限定トートバッグ');
foreach ($tokens as $token) {
    echo $token->surface . "\n";
}

トークナイザー API

TokenizerBuilder

TokenizerBuilder はビルダーパターンを使用して Tokenizer インスタンスを設定・構築します。

コンストラクタ

new Lindera\TokenizerBuilder()

デフォルト設定で新しいビルダーを作成します。

<?php

$builder = new Lindera\TokenizerBuilder();

設定メソッド

すべてのセッターメソッドはメソッドチェーンのために $this を返します。

setMode($mode)

トークナイズモードを設定します。

  • "normal" -- 標準的なトークナイズ(デフォルト)
  • "decompose" -- 複合語をより小さな単位に分解
$builder->setMode('normal');

setDictionary($uri)

システム辞書のパスまたは URI を設定します。

// 埋め込み辞書を使用
$builder->setDictionary('embedded://ipadic');

// 外部辞書を使用
$builder->setDictionary('/path/to/dictionary');

setUserDictionary($uri)

ユーザー辞書の URI を設定します。

$builder->setUserDictionary('/path/to/user_dictionary');

setKeepWhitespace($keep)

出力に空白トークンを含めるかどうかを制御します。

$builder->setKeepWhitespace(true);

appendCharacterFilter($kind, $args)

前処理パイプラインに文字フィルタを追加します。

$builder->appendCharacterFilter('unicode_normalize', ['kind' => 'nfkc']);

appendTokenFilter($kind, $args)

後処理パイプラインにトークンフィルタを追加します。

$builder->appendTokenFilter('lowercase');
$builder->appendTokenFilter('japanese_stop_tags', ['tags' => ['助詞', '助動詞']]);

ビルド

build()

設定された内容で Tokenizer をビルドして返します。

$tokenizer = $builder->build();

Tokenizer

Tokenizer はテキストに対して形態素解析を行います。

Tokenizer の作成

new Lindera\Tokenizer($dictionary, $mode, $userDictionary)

読み込み済みの辞書から直接トークナイザーを作成します。

<?php

$dictionary = Lindera\Dictionary::load('embedded://ipadic');
$tokenizer = new Lindera\Tokenizer($dictionary, 'normal');

ユーザー辞書を指定する場合:

<?php

$dictionary = Lindera\Dictionary::load('embedded://ipadic');
$metadata = $dictionary->metadata();
$userDictionary = Lindera\Dictionary::loadUser('/path/to/user_dictionary', $metadata);

$tokenizer = new Lindera\Tokenizer($dictionary, 'normal', $userDictionary);

Tokenizer メソッド

tokenize($text)

入力テキストをトークナイズし、Token オブジェクトの配列を返します。

$tokens = $tokenizer->tokenize('形態素解析');

パラメータ:

名前説明
$textstringトークナイズするテキスト

戻り値: array<Token>

tokenizeNbest($text, $n)

N-best トークナイズ結果を返します。各結果は NbestResult オブジェクトで、トークン配列とトータルパスコストを含みます。

$results = $tokenizer->tokenizeNbest('すもももももももものうち', 3);
foreach ($results as $result) {
    echo "Cost: {$result->cost}\n";
    foreach ($result->tokens as $token) {
        echo "  {$token->surface}\n";
    }
}

パラメータ:

名前説明
$textstringトークナイズするテキスト
$nint返す結果の数

戻り値: array<NbestResult>

NbestResult

NbestResult は N-best トークナイズの個別の結果を表します。

NbestResult プロパティ

プロパティ説明
tokensarray<Token>トークンの配列
costintトータルパスコスト

Token

Token は単一の形態素トークンを表します。

Token プロパティ

プロパティ説明
surfacestringトークンの表層形
byte_startint元テキストでの開始バイト位置
byte_endint元テキストでの終了バイト位置
positionintトークンの位置インデックス
word_idint辞書の単語 ID
is_unknownbool辞書に登録されていない単語の場合 true
detailsarray<string>形態素の詳細情報(品詞、読みなど)

Token メソッド

getDetail($index)

指定されたインデックスの詳細文字列を返します。インデックスが範囲外の場合は null を返します。

$token = $tokenizer->tokenize('東京')[0];
$pos = $token->getDetail(0);        // 例: "名詞"
$subpos = $token->getDetail(1);     // 例: "固有名詞"
$reading = $token->getDetail(7);    // 例: "トウキョウ"

パラメータ:

名前説明
$indexintdetails 配列へのゼロベースインデックス

戻り値: string または null

details の構造は辞書によって異なります:

  • IPADIC: [品詞, 品詞細分類1, 品詞細分類2, 品詞細分類3, 活用型, 活用形, 原形, 読み, 発音]
  • UniDic: UniDic 仕様に準拠した詳細な形態素情報
  • ko-dic / CC-CEDICT / Jieba: 各辞書固有の詳細フォーマット

Mode

Mode はトークナイズの動作モードを表します。

Mode の作成

new Lindera\Mode($name)

$mode = new Lindera\Mode('normal');
$mode = new Lindera\Mode('decompose');
$mode = new Lindera\Mode();  // デフォルト: 'normal'

Mode プロパティ

プロパティ説明
namestringモード名("normal" または "decompose"

Mode メソッド

メソッド戻り値説明
isNormal()boolNormal モードの場合 true
isDecompose()boolDecompose モードの場合 true

辞書管理

Lindera PHP は、形態素解析で使用する辞書の読み込み、ビルド、管理のためのクラスを提供します。

辞書の読み込み

システム辞書

Lindera\Dictionary::load($uri) を使用してシステム辞書を読み込みます。GitHub Releases からビルド済み辞書をダウンロードし、展開したディレクトリのパスを指定してください:

<?php

$dictionary = Lindera\Dictionary::load('/path/to/ipadic');

埋め込み辞書(上級者向け) -- embed-* feature フラグ付きでビルドした場合、埋め込み辞書を使用できます:

<?php

$dictionary = Lindera\Dictionary::load('embedded://ipadic');

ユーザー辞書

ユーザー辞書はシステム辞書にカスタム語彙を追加します。Lindera\Dictionary::loadUser() を使用して読み込みます。

<?php

$dictionary = Lindera\Dictionary::load('/path/to/ipadic');
$metadata = $dictionary->metadata();
$userDictionary = Lindera\Dictionary::loadUser('/path/to/user_dictionary.csv', $metadata);

トークナイザーの作成時にユーザー辞書を渡します:

<?php

$dictionary = Lindera\Dictionary::load('/path/to/ipadic');
$metadata = $dictionary->metadata();
$userDictionary = Lindera\Dictionary::loadUser('/path/to/user_dictionary.csv', $metadata);

$tokenizer = new Lindera\Tokenizer($dictionary, 'normal', $userDictionary);

または、ビルダー経由で設定します:

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setDictionary('/path/to/ipadic');
$builder->setUserDictionary('/path/to/user_dictionary');
$tokenizer = $builder->build();

Dictionary メソッド

メソッド戻り値説明
Dictionary::load($uri)Dictionaryシステム辞書を読み込む
Dictionary::loadUser($path, $metadata)UserDictionaryユーザー辞書を読み込む
Dictionary::version()stringLindera のバージョン文字列を返す
Dictionary::build($source, $dest, $metadata)void辞書をビルドする
$dictionary->metadata()Metadata辞書のメタデータを返す
$dictionary->metadataName()string辞書名を返す
$dictionary->metadataEncoding()string辞書のエンコーディングを返す

辞書のビルド

システム辞書のビルド

ソースファイルからシステム辞書をビルドします:

<?php

$metadata = Lindera\Metadata::fromJsonFile('/path/to/metadata.json');
Lindera\Dictionary::build('/path/to/input_dir', '/path/to/output_dir', $metadata);

入力ディレクトリには辞書のソースファイル(CSV レキシコン、matrix.def など)が含まれている必要があります。

以下は IPADIC 辞書をダウンロードしてビルドする例です:

<?php

$url = 'https://lindera.dev/mecab-ipadic-2.7.0-20070801.tar.gz';
$filename = '/tmp/mecab-ipadic-2.7.0-20070801.tar.gz';

// Download and extract dictionary source
file_put_contents($filename, file_get_contents($url));
$phar = new PharData($filename);
$phar->extractTo('/tmp/', null, true);

// Load metadata and build
$metadata = Lindera\Metadata::fromJsonFile('resources/ipadic_metadata.json');
Lindera\Dictionary::build(
    '/tmp/mecab-ipadic-2.7.0-20070801',
    '/tmp/lindera-ipadic',
    $metadata
);

Metadata

Metadata クラスは辞書のパラメータを設定します。

Metadata の作成

<?php

// デフォルトのメタデータ
$metadata = Lindera\Metadata::createDefault();

// カスタムメタデータ
$metadata = new Lindera\Metadata('my_dictionary', 'UTF-8', -10000);

JSON からの読み込み

$metadata = Lindera\Metadata::fromJsonFile('metadata.json');

プロパティ

プロパティデフォルト説明
namestring"default"辞書名
encodingstring"UTF-8"文字エンコーディング
default_word_costint-10000未知語のデフォルトコスト

Schema

Schema クラスは辞書のフィールド構造を定義します。

Schema の作成

<?php

// デフォルトスキーマ(IPADIC 互換)
$schema = Lindera\Schema::createDefault();

// カスタムスキーマ
$schema = new Lindera\Schema(['surface', 'pos']);

メソッド

メソッド戻り値説明
fieldCount()intフィールド数を返す
getFieldIndex($name)intフィールドのインデックスを返す(見つからない場合は -1
getFieldByName($name)Field または nullフィールド情報を返す
getCustomFields()array<string>カスタムフィールド名の配列を返す
validateRecord($record)voidレコードがスキーマに適合するか検証する

Schema プロパティ

プロパティ説明
fieldsarray<string>フィールド名の配列

テキスト処理パイプライン

Lindera PHP は、トークナイズ前に文字フィルタを適用し、トークナイズ後にトークンフィルタを適用する、組み合わせ可能なテキスト処理パイプラインをサポートしています。フィルタは TokenizerBuilder に追加され、追加された順序で実行されます。

Input Text
  --> Character Filters (preprocessing)
  --> Tokenization
  --> Token Filters (postprocessing)
  --> Output Tokens

文字フィルタ

文字フィルタはトークナイズ前に入力テキストを変換します。

unicode_normalize

入力テキストに Unicode 正規化を適用します。

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setDictionary('embedded://ipadic');
$builder->appendCharacterFilter('unicode_normalize', ['kind' => 'nfkc']);
$tokenizer = $builder->build();

サポートされる正規化形式: "nfc""nfkc""nfd""nfkd"

mapping

マッピングテーブルに従って文字や文字列を置換します。

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setDictionary('embedded://ipadic');
$builder->appendCharacterFilter('mapping', [
    'mapping' => [
        'リンデラ' => 'lindera',
    ],
]);
$tokenizer = $builder->build();

japanese_iteration_mark

日本語の踊り字(繰り返し記号)を完全な形に展開します。

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setDictionary('embedded://ipadic');
$builder->appendCharacterFilter('japanese_iteration_mark', [
    'normalize_kanji' => 'true',
    'normalize_kana' => 'true',
]);
$tokenizer = $builder->build();

トークンフィルタ

トークンフィルタはトークナイズ後にトークンを変換または除去します。

lowercase

トークンの表層形を小文字に変換します。

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setDictionary('embedded://ipadic');
$builder->appendTokenFilter('lowercase');
$tokenizer = $builder->build();

japanese_base_form

辞書の形態素情報を使用して、活用形を基本形(辞書形)に置換します。

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setDictionary('embedded://ipadic');
$builder->appendTokenFilter('japanese_base_form', []);
$tokenizer = $builder->build();

japanese_katakana_stem

カタカナ語の語尾の長音記号を除去してステミングを行います。

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setDictionary('embedded://ipadic');
$builder->appendTokenFilter('japanese_katakana_stem', ['min' => 3]);
$tokenizer = $builder->build();

japanese_stop_tags

指定されたタグに一致する品詞のトークンを除去します。

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setDictionary('embedded://ipadic');
$builder->appendTokenFilter('japanese_stop_tags', [
    'tags' => ['助詞', '助動詞', '記号'],
]);
$tokenizer = $builder->build();

japanese_keep_tags

指定されたタグに一致する品詞のトークンのみを保持します。その他のトークンはすべて除去されます。

<?php

$builder = new Lindera\TokenizerBuilder();
$builder->setDictionary('embedded://ipadic');
$builder->appendTokenFilter('japanese_keep_tags', [
    'tags' => ['名詞'],
]);
$tokenizer = $builder->build();

パイプラインの完全な例

以下の例では、複数の文字フィルタとトークンフィルタを1つのパイプラインに組み合わせています:

<?php

$builder = new Lindera\TokenizerBuilder();

// Set mode and dictionary
$builder->setMode('normal');
$builder->setDictionary('embedded://ipadic');

// Preprocessing
$builder->appendCharacterFilter('unicode_normalize', ['kind' => 'nfkc']);
$builder->appendCharacterFilter(
    'japanese_iteration_mark',
    ['normalize_kanji' => 'true', 'normalize_kana' => 'true']
);
$builder->appendCharacterFilter('mapping', ['mapping' => ['リンデラ' => 'lindera']]);

// Postprocessing
$builder->appendTokenFilter('japanese_katakana_stem', ['min' => 3]);
$builder->appendTokenFilter('japanese_stop_tags', [
    'tags' => [
        '接続詞',
        '助詞',
        '助詞,格助詞',
        '助詞,格助詞,一般',
        '助詞,係助詞',
        '助詞,副助詞',
        '助詞,終助詞',
        '助詞,連体化',
        '助動詞',
        '記号',
        '記号,一般',
        '記号,読点',
        '記号,句点',
        '記号,空白',
    ],
]);
$builder->appendTokenFilter('lowercase');

// Build the tokenizer
$tokenizer = $builder->build();

// Tokenize
$text = 'Linderaは形態素解析エンジンです。';
$tokens = $tokenizer->tokenize($text);

foreach ($tokens as $token) {
    echo $token->surface . "\t" . implode(',', $token->details) . "\n";
}

このパイプラインでは:

  1. unicode_normalize が全角文字を半角に変換(NFKC 正規化)
  2. japanese_iteration_mark が踊り字を展開
  3. mapping が指定された文字列を置換
  4. japanese_katakana_stem がカタカナ語をステミング
  5. japanese_stop_tags が助詞、助動詞、記号を除去
  6. lowercase がアルファベットを小文字に正規化

学習

Lindera PHP は、アノテーション付きコーパスからカスタム CRF ベースの形態素解析モデルを学習する機能をサポートしています。この機能には train feature が必要です。

前提条件

train feature を有効にして lindera-php をビルドします(デフォルトで有効):

cargo build -p lindera-php --features train

モデルの学習

Lindera\Trainer::train() を使用して、種辞書とアノテーション付きコーパスから CRF モデルを学習します:

<?php

Lindera\Trainer::train(
    '/path/to/seed.csv',         // seed: 種辞書ファイル
    '/path/to/corpus.txt',       // corpus: アノテーション付きコーパス
    '/path/to/char.def',         // char_def: 文字定義ファイル
    '/path/to/unk.def',          // unk_def: 未知語定義ファイル
    '/path/to/feature.def',      // feature_def: 素性定義ファイル
    '/path/to/rewrite.def',      // rewrite_def: 書き換えルール定義ファイル
    '/tmp/model.dat',            // output: 学習済みモデルの出力パス
    0.01,                        // lambda: L1 正則化コスト
    100,                         // max_iter: 最大イテレーション数
    null                         // max_threads: スレッド数(null = 自動検出)
);

学習パラメータ

パラメータデフォルト説明
$seedstring必須種辞書ファイルのパス(CSV 形式)
$corpusstring必須アノテーション付き学習コーパスのパス
$charDefstring必須文字定義ファイルのパス(char.def)
$unkDefstring必須未知語定義ファイルのパス(unk.def)
$featureDefstring必須素性定義ファイルのパス(feature.def)
$rewriteDefstring必須書き換えルール定義ファイルのパス(rewrite.def)
$outputstring必須学習済みモデルファイルの出力パス
$lambdafloat0.01L1 正則化コスト(0.0--1.0)
$maxIterint100最大学習イテレーション数
$maxThreadsint または nullnullスレッド数(null = CPU コア数を自動検出)

学習済みモデルのエクスポート

学習後、Lindera\Trainer::export() を使用してモデルを辞書ソースファイルにエクスポートします:

<?php

Lindera\Trainer::export(
    '/tmp/model.dat',                    // model: 学習済みモデルファイル
    '/tmp/dictionary_source',            // output: 出力ディレクトリ
    '/path/to/metadata.json'             // metadata: メタデータファイル(省略可)
);

エクスポートパラメータ

パラメータデフォルト説明
$modelstring必須学習済みモデルファイルのパス(.dat)
$outputstring必須辞書ソースファイルの出力ディレクトリ
$metadatastring または nullnullベースとなる metadata.json ファイルのパス

エクスポートにより、出力ディレクトリに以下のファイルが作成されます:

  • lex.csv -- 学習済みコスト付きのレキシコンエントリー
  • matrix.def -- 連接コスト行列
  • unk.def -- 未知語定義
  • char.def -- 文字カテゴリ定義
  • metadata.json -- 更新されたメタデータ($metadata パラメータ指定時)

完全なワークフロー

カスタム辞書の学習と使用の完全なワークフロー:

<?php

// Step 1: Train the CRF model
Lindera\Trainer::train(
    'resources/training/seed.csv',
    'resources/training/corpus.txt',
    'resources/training/char.def',
    'resources/training/unk.def',
    'resources/training/feature.def',
    'resources/training/rewrite.def',
    '/tmp/model.dat',
    0.01,   // lambda
    100,    // max_iter
    null    // max_threads
);

// Step 2: Export to dictionary source files
Lindera\Trainer::export(
    '/tmp/model.dat',
    '/tmp/dictionary_source',
    'resources/training/metadata.json'
);

// Step 3: Build the dictionary from exported source files
$metadata = Lindera\Metadata::fromJsonFile('/tmp/dictionary_source/metadata.json');
Lindera\Dictionary::build('/tmp/dictionary_source', '/tmp/dictionary', $metadata);

// Step 4: Use the trained dictionary
$dictionary = Lindera\Dictionary::load('/tmp/dictionary');
$tokenizer = new Lindera\Tokenizer($dictionary, 'normal');

$tokens = $tokenizer->tokenize('形態素解析のテスト');
foreach ($tokens as $token) {
    echo $token->surface . "\t" . implode(',', $token->details) . "\n";
}

Lindera WASM

Lindera WASM は、wasm-bindgen を使用して構築された Lindera 形態素解析エンジンの WebAssembly バインディングです。Web ブラウザ、Node.js、バンドラー環境で日本語、韓国語、中国語のテキストトークナイズを直接実行できます。

配布フォーマット

Lindera WASM は wasm-pack を通じて複数の配布フォーマットをサポートしています:

ターゲット用途モジュールシステム
webブラウザ ESMES Modules
bundlerWebpack、Vite、RollupES Modules(バンドラー解決)

辞書パッケージ

各パッケージはオフライン使用のために特定の辞書を埋め込みます:

Feature フラグ辞書言語
(なし)埋め込み辞書なし--
embed-ipadicIPADIC日本語
embed-unidicUniDic日本語
embed-ko-dicko-dic韓国語
embed-cc-cedictCC-CEDICT中国語
embed-jiebaJieba中国語
embed-cjkIPADIC + ko-dic + JiebaCJK

セクション

インストール

前提条件

  • Rust(stable ツールチェーン)
  • wasm-pack(v0.10 以降)

辞書の入手

Lindera WASM はデフォルトで辞書を同梱しません。ブラウザ環境では、OPFS(Origin Private File System)API を使用して辞書を実行時にダウンロードする方法を推奨します。

GitHub Releases からのダウンロード

ビルド済み辞書は GitHub Releases ページから入手できます。ブラウザ環境では、OPFS ヘルパーを使用して辞書をダウンロードしてキャッシュします:

import { downloadDictionary, hasDictionary } from 'lindera-wasm-web/opfs';

if (!await hasDictionary("ipadic")) {
    await downloadDictionary(
        "https://github.com/lindera/lindera/releases/download/<version>/lindera-ipadic-<version>.zip",
        "ipadic",
    );
}

詳細は OPFS 辞書ストレージ を参照してください。

wasm-pack によるビルド

ターゲット環境に合わせて WASM パッケージをビルドします:

Web(ブラウザ向け ES Modules)

wasm-pack build --target web

バンドラー(Webpack、Vite、Rollup)

wasm-pack build --target bundler

出力は lindera-wasm クレート内の pkg/ ディレクトリに書き込まれます。

利用可能な Feature フラグ(上級者向け)

辞書を WASM バイナリに直接埋め込みたい上級者向けに、以下の feature フラグが利用できます。バイナリサイズが大幅に増加しますが、実行時の辞書ダウンロードが不要になります。

Feature辞書言語
embed-ipadicIPADIC日本語
embed-unidicUniDic日本語
embed-ko-dicko-dic韓国語
embed-cc-cedictCC-CEDICT中国語
embed-jiebaJieba中国語
embed-cjkIPADIC + ko-dic + JiebaCJK(全言語)

複数の feature フラグを有効にして複数の辞書を組み合わせることができます:

wasm-pack build --target web --features embed-ipadic,embed-ko-dic

npm パッケージの命名規則

npm に公開する際の推奨命名規則は以下の通りです:

lindera-wasm-{target}
lindera-wasm-{target}-{dict}

例:

  • lindera-wasm-web
  • lindera-wasm-web-ipadic
  • lindera-wasm-bundler-unidic
  • lindera-wasm-web-cjk

公開前にパッケージ名を設定するには、生成された pkg/package.jsonname フィールドを編集します。

npm からのインストール

ビルド済みパッケージが npm で公開されています:

npm install lindera-wasm-web

または yarn で:

yarn add lindera-wasm-web

[!NOTE] npm パッケージには辞書が含まれていません。OPFS ヘルパーを使用して辞書を実行時にダウンロードしてください。詳細は OPFS 辞書ストレージ を参照してください。

クイックスタート

Web(ブラウザ) -- OPFS 辞書ロード

推奨される方法は、OPFS ヘルパーを使用して辞書を実行時にダウンロードすることです:

import __wbg_init, { TokenizerBuilder, loadDictionaryFromBytes } from 'lindera-wasm-web';
import { downloadDictionary, loadDictionaryFiles, hasDictionary } from 'lindera-wasm-web/opfs';

async function main() {
    await __wbg_init();

    // キャッシュされていない場合は辞書をダウンロード
    if (!await hasDictionary("ipadic")) {
        await downloadDictionary(
            "https://github.com/lindera/lindera/releases/download/<version>/lindera-ipadic-<version>.zip",
            "ipadic",
        );
    }

    // OPFS から辞書を読み込み
    const files = await loadDictionaryFiles("ipadic");
    const dictionary = loadDictionaryFromBytes(
        files.metadata, files.dictDa, files.dictVals, files.dictWordsIdx,
        files.dictWords, files.matrixMtx, files.charDef, files.unk,
    );

    // トークナイザーを構築
    const builder = new TokenizerBuilder();
    builder.setDictionaryInstance(dictionary);
    builder.setMode("normal");
    const tokenizer = builder.build();

    const tokens = tokenizer.tokenize("関西国際空港限定トートバッグ");
    tokens.forEach(token => {
        console.log(`${token.surface}\t${token.details.join(',')}`);
    });
}

main();

注意: ビルド済み辞書を GitHub Releases からダウンロードしてください。完全なワークフローは OPFS 辞書ストレージ を参照してください。

期待される出力:

関西国際空港    名詞,固有名詞,一般,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
限定    名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ    名詞,一般,*,*,*,*,*,*,*

埋め込み辞書の使用(上級者向け)

embed-* feature フラグ付きでビルドした場合、埋め込み辞書を使用できます:

import __wbg_init, { TokenizerBuilder } from 'lindera-wasm-web-ipadic';

async function main() {
    await __wbg_init();

    const builder = new TokenizerBuilder();
    builder.setDictionary("embedded://ipadic");
    builder.setMode("normal");
    const tokenizer = builder.build();

    const tokens = tokenizer.tokenize("関西国際空港限定トートバッグ");
    tokens.forEach(token => {
        console.log(`${token.surface}\t${token.details.join(',')}`);
    });
}

main();

フィルタの使用

トークナイズパイプラインに文字フィルタやトークンフィルタを追加できます:

import __wbg_init, { TokenizerBuilder, loadDictionaryFromBytes } from 'lindera-wasm-web';
import { loadDictionaryFiles } from 'lindera-wasm-web/opfs';

async function main() {
    await __wbg_init();

    // OPFS にキャッシュ済みの辞書を読み込み
    const files = await loadDictionaryFiles("ipadic");
    const dictionary = loadDictionaryFromBytes(
        files.metadata, files.dictDa, files.dictVals, files.dictWordsIdx,
        files.dictWords, files.matrixMtx, files.charDef, files.unk,
    );

    const builder = new TokenizerBuilder();
    builder.setDictionaryInstance(dictionary);
    builder.setMode("normal");

    // Add Unicode NFKC normalization
    builder.appendCharacterFilter("unicode_normalize", { kind: "nfkc" });

    // Add a stop-tags filter to remove particles and auxiliary verbs
    builder.appendTokenFilter("japanese_stop_tags", {
        tags: ["助詞", "助動詞"]
    });

    const tokenizer = builder.build();
    const tokens = tokenizer.tokenize("Linderaは形態素解析エンジンです");
    tokens.forEach(token => {
        console.log(`${token.surface}\t${token.details.join(',')}`);
    });
}

main();

N-Best トークナイズ

コスト順にランク付けされた複数のトークナイズ候補を取得します:

const results = tokenizer.tokenizeNbest("すもももももももものうち", 3);
results.forEach((result, rank) => {
    console.log(`--- NBEST ${rank + 1} (cost=${result.cost}) ---`);
    result.tokens.forEach(token => {
        console.log(`${token.surface}\t${token.details.join(',')}`);
    });
});

Tokenizer API

このページでは、lindera-wasm が公開する JavaScript/TypeScript API について説明します。

TokenizerBuilder

設定済みの Tokenizer インスタンスを作成するためのビルダークラスです。

コンストラクタ

const builder = new TokenizerBuilder();

デフォルト設定で新しいビルダーを作成します。

メソッド

setMode(mode)

トークナイズモードを設定します。

  • パラメータ: mode (string) -- "normal" または "decompose"
  • 戻り値: void
builder.setMode("normal");

setDictionary(uri)

トークナイズに使用する辞書を設定します。

  • パラメータ: uri (string) -- 辞書の URI(例: "embedded://ipadic"
  • 戻り値: void
builder.setDictionary("embedded://ipadic");

setDictionaryInstance(dictionary)

読み込み済みの辞書インスタンスをトークナイズに設定します。 URI の代わりにバイトデータから読み込んだ辞書(例: loadDictionaryFromBytes() 経由)を使用する場合に使います。

  • パラメータ: dictionary (Dictionary) -- 読み込み済みの辞書オブジェクト
  • 戻り値: void
import { loadDictionaryFromBytes } from 'lindera-wasm-web';
import { loadDictionaryFiles } from 'lindera-wasm-web/opfs';

const files = await loadDictionaryFiles("ipadic");
const dictionary = loadDictionaryFromBytes(
    files.metadata, files.dictDa, files.dictVals, files.dictWordsIdx,
    files.dictWords, files.matrixMtx, files.charDef, files.unk,
);

builder.setDictionaryInstance(dictionary);

setUserDictionary(uri)

ユーザー定義辞書を設定します。

  • パラメータ: uri (string) -- ユーザー辞書のパスまたは URI
  • 戻り値: void
builder.setUserDictionary("file:///path/to/user_dict.csv");

setUserDictionaryInstance(userDictionary)

読み込み済みのユーザー辞書インスタンスを設定します。URI の代わりにバイトデータから読み込んだユーザー辞書を使用する場合に使います。

  • パラメータ: userDictionary (UserDictionary) -- 読み込み済みのユーザー辞書オブジェクト
  • 戻り値: void

setKeepWhitespace(keep)

出力に空白トークンを保持するかどうかを設定します。

  • パラメータ: keep (boolean) -- true で空白トークンを保持
  • 戻り値: void
builder.setKeepWhitespace(true);

appendCharacterFilter(name, args)

前処理パイプラインに文字フィルタを追加します。

  • パラメータ:
    • name (string) -- フィルタ名(例: "unicode_normalize""japanese_iteration_mark"
    • args (object, 省略可) -- フィルタの設定
  • 戻り値: void
builder.appendCharacterFilter("unicode_normalize", { kind: "nfkc" });

appendTokenFilter(name, args)

後処理パイプラインにトークンフィルタを追加します。

  • パラメータ:
    • name (string) -- フィルタ名(例: "japanese_stop_tags""lowercase"
    • args (object, 省略可) -- フィルタの設定
  • 戻り値: void
builder.appendTokenFilter("japanese_stop_tags", {
    tags: ["助詞", "助動詞", "記号"]
});

build()

設定済みの Tokenizer インスタンスをビルドして返します。ビルダーは消費されます。

  • 戻り値: Tokenizer
const tokenizer = builder.build();

Tokenizer

メインのトークナイザークラスです。TokenizerBuilder.build() またはコンストラクタ経由で作成できます。

Tokenizer コンストラクタ

const tokenizer = new Tokenizer(dictionary, mode, userDictionary);
  • パラメータ:
    • dictionary (Dictionary) -- 読み込み済みの辞書オブジェクト
    • mode (string, 省略可) -- トークナイズモード("normal" または "decompose"、デフォルト: "normal"
    • userDictionary (UserDictionary, 省略可) -- 読み込み済みのユーザー辞書

Tokenizer メソッド

tokenize(text)

入力テキストをトークナイズします。

  • パラメータ: text (string) -- トークナイズするテキスト
  • 戻り値: Token[] -- トークンオブジェクトの配列
const tokens = tokenizer.tokenize("関西国際空港");

tokenizeNbest(text, n, unique?, costThreshold?)

トータルパスコスト順に N-best トークナイズ結果を返します。

  • パラメータ:
    • text (string) -- トークナイズするテキスト
    • n (number) -- 返す結果の数
    • unique (boolean, 省略可) -- 同一のセグメンテーション結果を重複排除(デフォルト: false
    • costThreshold (number, 省略可) -- bestCost + threshold 以内のパスのみ返す
  • 戻り値: { tokens: object[], cost: number } の配列
const results = tokenizer.tokenizeNbest("すもももももももものうち", 3);

Token

トークナイザーが生成する単一のトークンを表します。

プロパティ

プロパティ説明
surfacestringトークンの表層形
byteStartnumber元テキストでの開始バイトオフセット
byteEndnumber元テキストでの終了バイトオフセット
positionnumberトークンの位置インデックス
wordIdnumber辞書内の単語 ID
isUnknownboolean未知語かどうか
detailsstring[]形態素の詳細フィールド

Token メソッド

getDetail(index)

指定されたインデックスの詳細文字列を返します。

  • パラメータ: index (number) -- details 配列へのゼロベースインデックス
  • 戻り値: string | undefined
const pos = token.getDetail(0);   // 例: "名詞"
const reading = token.getDetail(7); // 例: "トウキョウ"

toJSON()

トークンのプレーンな JavaScript オブジェクト表現を返します。

  • 戻り値: surfacebyteStartbyteEndpositionwordIdisUnknowndetails をキーに持つ object
console.log(JSON.stringify(token.toJSON(), null, 2));

ヘルパー関数

loadDictionary(uri)

指定された URI から辞書を読み込みます。

  • パラメータ: uri (string) -- 辞書の URI(例: "embedded://ipadic"
  • 戻り値: Dictionary
import { loadDictionary } from 'lindera-wasm-web-ipadic';

const dict = loadDictionary("embedded://ipadic");

loadUserDictionary(uri, metadata)

指定された URI からユーザー辞書を読み込みます。

  • パラメータ:
    • uri (string) -- ユーザー辞書ファイルのパスまたは URI
    • metadata (Metadata) -- 辞書のメタデータオブジェクト
  • 戻り値: UserDictionary

buildDictionary(inputDir, outputDir, metadata)

ソースファイルからコンパイル済み辞書をビルドします。

  • パラメータ:
    • inputDir (string) -- 辞書ソースファイルを含むディレクトリのパス
    • outputDir (string) -- 出力ディレクトリのパス
    • metadata (Metadata) -- 辞書のメタデータオブジェクト
  • 戻り値: void

buildUserDictionary(inputFile, outputDir, metadata?)

CSV ファイルからコンパイル済みユーザー辞書をビルドします。

  • パラメータ:
    • inputFile (string) -- ユーザー辞書 CSV ファイルのパス
    • outputDir (string) -- 出力ディレクトリのパス
    • metadata (Metadata, 省略可) -- 辞書のメタデータオブジェクト
  • 戻り値: void

version() / getVersion()

lindera-wasm パッケージのバージョン文字列を返します。

  • 戻り値: string
import { version } from 'lindera-wasm-web-ipadic';

console.log(version()); // 例: "2.1.1"

列挙型とユーティリティクラス

Mode

トークナイズモードの列挙型です。

説明
Mode.Normal辞書コストに基づく標準的なトークナイズ
Mode.Decomposeペナルティベースのセグメンテーションによる複合語分解

Penalty

decompose モードの設定です。複合語をどの程度積極的に分解するかを制御します。

const penalty = new Penalty(
    kanjiThreshold?,     // 漢字の長さ閾値(デフォルト: 2)
    kanjiPenalty?,       // 漢字の長さペナルティ(デフォルト: 3000)
    otherThreshold?,     // その他の文字の長さ閾値(デフォルト: 7)
    otherPenalty?,       // その他の文字の長さペナルティ(デフォルト: 1700)
);
プロパティデフォルト説明
kanji_penalty_length_thresholdnumber2漢字複合語分割の長さ閾値
kanji_penalty_length_penaltynumber3000閾値を超える漢字複合語のペナルティコスト
other_penalty_length_thresholdnumber7非漢字複合語分割の長さ閾値
other_penalty_length_penaltynumber1700閾値を超える非漢字複合語のペナルティコスト

LinderaError

Lindera 操作のエラー型です。

const error = new LinderaError("message");
console.log(error.message);    // "message"
console.log(error.toString()); // "message"
プロパティ / メソッド説明
messagestringエラーメッセージ
toString()stringエラーメッセージを返す

snake_case エイリアス

Python API との一貫性のため、すべてのメソッドは snake_case 形式でも利用可能です:

camelCasesnake_case
setMode()set_mode()
setDictionary()set_dictionary()
setDictionaryInstance()set_dictionary_instance()
setUserDictionary()set_user_dictionary()
setUserDictionaryInstance()set_user_dictionary_instance()
setKeepWhitespace()set_keep_whitespace()
appendCharacterFilter()append_character_filter()
appendTokenFilter()append_token_filter()
tokenizeNbest()tokenize_nbest()
loadDictionary()load_dictionary()
loadDictionaryFromBytes()load_dictionary_from_bytes()
loadUserDictionary()load_user_dictionary()
buildDictionary()build_dictionary()
buildUserDictionary()build_user_dictionary()

辞書管理

OPFS からの辞書読み込み

WASM で辞書を使用する推奨方法は、GitHub Releases からダウンロードし、OPFS 経由で読み込むことです。これにより、WASM バイナリに大きな辞書を埋め込む必要がなくなります。

バイトデータからの読み込み

OPFS やその他のブラウザストレージに保存された辞書を loadDictionaryFromBytes() で読み込みます。

loadDictionaryFromBytes(metadata, dictDa, dictVals, dictWordsIdx, dictWords, matrixMtx, charDef, unk)

  • パラメータ:
    • metadata (Uint8Array) -- metadata.json の内容
    • dictDa (Uint8Array) -- dict.da の内容(Double-Array Trie)
    • dictVals (Uint8Array) -- dict.vals の内容(単語値データ)
    • dictWordsIdx (Uint8Array) -- dict.wordsidx の内容(単語詳細インデックス)
    • dictWords (Uint8Array) -- dict.words の内容(単語詳細)
    • matrixMtx (Uint8Array) -- matrix.mtx の内容(連接コスト行列)
    • charDef (Uint8Array) -- char_def.bin の内容(文字定義)
    • unk (Uint8Array) -- unk.bin の内容(未知語辞書)
  • 戻り値: Dictionary
import { loadDictionaryFromBytes, TokenizerBuilder } from 'lindera-wasm-web';
import { loadDictionaryFiles } from 'lindera-wasm-web/opfs';

// OPFS から辞書ファイルを読み込む
const files = await loadDictionaryFiles("ipadic");

// バイトデータから Dictionary を作成
const dictionary = loadDictionaryFromBytes(
    files.metadata,
    files.dictDa,
    files.dictVals,
    files.dictWordsIdx,
    files.dictWords,
    files.matrixMtx,
    files.charDef,
    files.unk,
);

// TokenizerBuilder で使用
const builder = new TokenizerBuilder();
builder.setDictionaryInstance(dictionary);
builder.setMode("normal");
const tokenizer = builder.build();

ダウンロードとキャッシュを含む完全なワークフローは OPFS 辞書ストレージ を参照してください。

埋め込み辞書(上級者向け)

embed-* feature フラグ付きでビルドした場合、embedded:// URI スキームで埋め込み辞書を読み込めます。WASM バイナリのサイズが大幅に増加します。

埋め込み辞書の読み込み

import { loadDictionary } from 'lindera-wasm-web-ipadic';

const dictionary = loadDictionary("embedded://ipadic");

利用可能な埋め込み辞書の URI(ビルド時に有効にした feature に依存):

URIFeature フラグ
embedded://ipadicembed-ipadic
embedded://unidicembed-unidic
embedded://ko-dicembed-ko-dic
embedded://cc-cedictembed-cc-cedict
embedded://jiebaembed-jieba

TokenizerBuilder での使用

const builder = new TokenizerBuilder();
builder.setDictionary("embedded://ipadic");
builder.setMode("normal");
const tokenizer = builder.build();

Tokenizer コンストラクタでの使用

import { loadDictionary, Tokenizer } from 'lindera-wasm-web-ipadic';

const dictionary = loadDictionary("embedded://ipadic");
const tokenizer = new Tokenizer(dictionary, "normal");

Dictionary クラス

Dictionary クラスは、読み込み済みの形態素解析辞書を表します。

プロパティ

プロパティ説明
namestring辞書名(例: "ipadic"
encodingstring辞書の文字エンコーディング
metadataMetadata完全なメタデータオブジェクト
console.log(dictionary.name);     // "ipadic"
console.log(dictionary.encoding); // "utf-8"

ユーザー辞書

ユーザー辞書を使用すると、システム辞書にないカスタム語彙を追加できます。

ユーザー辞書の読み込み

import { loadUserDictionary } from 'lindera-wasm-web';

const metadata = dictionary.metadata;
const userDict = loadUserDictionary("/path/to/user_dict.csv", metadata);

Tokenizer でのユーザー辞書の使用

import { loadDictionaryFromBytes, loadUserDictionary, Tokenizer } from 'lindera-wasm-web';
import { loadDictionaryFiles } from 'lindera-wasm-web/opfs';

const files = await loadDictionaryFiles("ipadic");
const dictionary = loadDictionaryFromBytes(
    files.metadata, files.dictDa, files.dictVals, files.dictWordsIdx,
    files.dictWords, files.matrixMtx, files.charDef, files.unk,
);
const userDict = loadUserDictionary("/path/to/user_dict.csv", dictionary.metadata);
const tokenizer = new Tokenizer(dictionary, "normal", userDict);

ユーザー辞書の CSV フォーマット

ユーザー辞書の CSV は Lindera ユーザー辞書と同じフォーマットに準拠します:

東京スカイツリー,カスタム名詞,トウキョウスカイツリー
東武スカイツリーライン,カスタム名詞,トウブスカイツリーライン

各行の構成: surface,part_of_speech,reading

辞書のビルド

JavaScript API を使用してソースファイルからコンパイル済み辞書をビルドできます。

システム辞書のビルド

import { buildDictionary } from 'lindera-wasm-web';

const metadata = {
    name: "custom-dict",
    encoding: "utf-8",
    // ... other metadata fields
};

buildDictionary("/path/to/source/dir", "/path/to/output/dir", metadata);

ユーザー辞書のビルド

import { buildUserDictionary } from 'lindera-wasm-web';

buildUserDictionary("/path/to/user_dict.csv", "/path/to/output/dir");

buildUserDictionarymetadata パラメータは省略可能です。省略した場合はデフォルトのメタデータが使用されます。

Metadata

Metadata クラスは辞書のパラメータを設定します。

コンストラクタ

const metadata = new Metadata(name?, encoding?);
  • パラメータ:
    • name (string, 省略可) -- 辞書名(デフォルト: "default"
    • encoding (string, 省略可) -- 文字エンコーディング(デフォルト: "UTF-8"

静的メソッド

Metadata.createDefault()

デフォルト値で Metadata インスタンスを作成します。

const metadata = Metadata.createDefault();

Metadata プロパティ

プロパティデフォルト説明
namestring"default"辞書名
encodingstring"UTF-8"文字エンコーディング
dictionary_schemaSchemaIPADIC スキーマメイン辞書のスキーマ
user_dictionary_schemaSchema最小スキーマユーザー辞書のスキーマ

すべてのプロパティは取得と設定の両方に対応しています:

const metadata = Metadata.createDefault();
metadata.name = "custom_dict";
metadata.encoding = "EUC-JP";
console.log(metadata.name); // "custom_dict"

読み込み済み辞書のメタデータには dictionary.metadata からアクセスできます。

Schema

Schema クラスは辞書エントリのフィールド構造を定義します。

Schema コンストラクタ

const schema = new Schema(["surface", "left_id", "right_id", "cost", "pos", "reading"]);

Schema 静的メソッド

  • Schema.create_default() -- デフォルトの IPADIC 互換スキーマを作成

Schema メソッド

メソッド戻り値説明
get_field_index(name)number | undefinedフィールド名からインデックスを取得
field_count()numberフィールドの総数
get_field_name(index)string | undefinedインデックスからフィールド名を取得
get_custom_fields()string[]インデックス 3 以降のフィールド(形態素素性)
get_all_fields()string[]すべてのフィールド名
get_field_by_name(name)FieldDefinition | undefinedフィールド定義の完全な情報を取得

FieldDefinition

プロパティ説明
indexnumberフィールドの位置インデックス
namestringフィールド名
field_typeFieldTypeフィールド型の列挙値
descriptionstring | undefined説明(省略可)

FieldType

説明
FieldType.Surface単語の表層形テキスト
FieldType.LeftContextId左文脈 ID
FieldType.RightContextId右文脈 ID
FieldType.Cost単語コスト
FieldType.Custom形態素素性フィールド

ブラウザでの使用

ES Module インポート

ブラウザ環境では、Lindera の関数を使用する前に WASM モジュールを初期化する必要があります。デフォルトエクスポートの __wbg_init がこの初期化を処理します。

推奨される方法は、辞書を WASM バイナリに埋め込むのではなく、OPFS から読み込むことです:

import __wbg_init, { TokenizerBuilder, loadDictionaryFromBytes } from 'lindera-wasm-web';
import { downloadDictionary, loadDictionaryFiles, hasDictionary } from 'lindera-wasm-web/opfs';

async function main() {
    // Initialize the WASM module (must be called once before using any API)
    await __wbg_init();

    // キャッシュされていない場合は辞書をダウンロード
    if (!await hasDictionary("ipadic")) {
        await downloadDictionary(
            "https://github.com/lindera/lindera/releases/download/<version>/lindera-ipadic-<version>.zip",
            "ipadic",
        );
    }

    // OPFS から辞書を読み込み
    const files = await loadDictionaryFiles("ipadic");
    const dictionary = loadDictionaryFromBytes(
        files.metadata, files.dictDa, files.dictVals, files.dictWordsIdx,
        files.dictWords, files.matrixMtx, files.charDef, files.unk,
    );

    const builder = new TokenizerBuilder();
    builder.setDictionaryInstance(dictionary);
    builder.setMode("normal");
    const tokenizer = builder.build();

    const tokens = tokenizer.tokenize("形態素解析を行います");
    tokens.forEach(token => {
        console.log(`${token.surface}: ${token.details.join(',')}`);
    });
}

main();

埋め込み辞書の使用(上級者向け)

embed-* feature フラグ付きでビルドした場合、OPFS の代わりに埋め込み辞書を使用できます:

import __wbg_init, { TokenizerBuilder } from 'lindera-wasm-web-ipadic';

async function main() {
    await __wbg_init();

    const builder = new TokenizerBuilder();
    builder.setDictionary("embedded://ipadic");
    builder.setMode("normal");
    const tokenizer = builder.build();

    const tokens = tokenizer.tokenize("形態素解析を行います");
    tokens.forEach(token => {
        console.log(`${token.surface}: ${token.details.join(',')}`);
    });
}

main();

HTML の例

OPFS 辞書ロードを使用した lindera-wasm の最小限の HTML ページ:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Lindera WASM Demo</title>
</head>
<body>
    <textarea id="input" rows="4" cols="50">関西国際空港限定トートバッグ</textarea>
    <br>
    <button id="tokenize" disabled>Tokenize</button>
    <pre id="output">Loading dictionary...</pre>

    <script type="module">
        import __wbg_init, { TokenizerBuilder, loadDictionaryFromBytes } from './pkg/lindera_wasm.js';
        import { downloadDictionary, loadDictionaryFiles, hasDictionary } from './pkg/opfs.js';

        let tokenizer;

        async function init() {
            await __wbg_init();

            // キャッシュされていない場合は辞書をダウンロード
            if (!await hasDictionary("ipadic")) {
                document.getElementById('output').textContent = 'Downloading dictionary...';
                await downloadDictionary(
                    "https://github.com/lindera/lindera/releases/download/<version>/lindera-ipadic-<version>.zip",
                    "ipadic",
                );
            }

            // OPFS から辞書を読み込み
            const files = await loadDictionaryFiles("ipadic");
            const dictionary = loadDictionaryFromBytes(
                files.metadata, files.dictDa, files.dictVals, files.dictWordsIdx,
                files.dictWords, files.matrixMtx, files.charDef, files.unk,
            );

            const builder = new TokenizerBuilder();
            builder.setDictionaryInstance(dictionary);
            builder.setMode("normal");
            tokenizer = builder.build();

            document.getElementById('tokenize').disabled = false;
            document.getElementById('output').textContent = 'Ready!';
        }

        document.getElementById('tokenize').addEventListener('click', () => {
            const text = document.getElementById('input').value;
            const tokens = tokenizer.tokenize(text);
            const output = tokens.map(t =>
                `${t.surface}\t${t.details.join(',')}`
            ).join('\n');
            document.getElementById('output').textContent = output;
        });

        init();
    </script>
</body>
</html>

Webpack の設定

Webpack 5 を使用する場合は、asyncWebAssembly experiment を有効にします:

// webpack.config.js
module.exports = {
    experiments: {
        asyncWebAssembly: true,
    },
    module: {
        rules: [
            {
                test: /\.wasm$/,
                type: "webassembly/async",
            },
        ],
    },
};

次に、bundler ターゲットビルドを使用してインポートします:

import { TokenizerBuilder, loadDictionaryFromBytes } from 'lindera-wasm-bundler';
import { loadDictionaryFiles } from 'lindera-wasm-bundler/opfs';

// OPFS から辞書を読み込み(セットアップは OPFS 辞書ストレージを参照)
const files = await loadDictionaryFiles("ipadic");
const dictionary = loadDictionaryFromBytes(
    files.metadata, files.dictDa, files.dictVals, files.dictWordsIdx,
    files.dictWords, files.matrixMtx, files.charDef, files.unk,
);

const builder = new TokenizerBuilder();
builder.setDictionaryInstance(dictionary);
builder.setMode("normal");
const tokenizer = builder.build();

bundler ターゲットでは、__wbg_init() はバンドラーによって自動的に呼び出されます。

Vite / Rollup のセットアップ

Vite は web ターゲットでの WASM をそのままサポートしています。ビルド済みの pkg/ ディレクトリをプロジェクトに配置し、直接インポートします:

import __wbg_init, { TokenizerBuilder, loadDictionaryFromBytes } from './pkg/lindera_wasm.js';
import { loadDictionaryFiles } from './pkg/opfs.js';

await __wbg_init();
// OPFS から辞書を読み込み、上記のように TokenizerBuilder を使用

bundler ターゲットで Vite を使用する場合は、vite-plugin-wasm プラグインが必要になることがあります:

// vite.config.js
import wasm from 'vite-plugin-wasm';

export default {
    plugins: [wasm()],
};

Chrome 拡張機能に関する注意事項

Manifest V3 を使用する Chrome 拡張機能では、デフォルトで WebAssembly.compileWebAssembly.instantiate が制限されています。拡張機能で lindera-wasm を使用するには、Content Security Policy に wasm-unsafe-eval を追加する必要があります:

{
    "content_security_policy": {
        "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
    }
}

wasm-unsafe-eval は WebAssembly の実行のみを許可し、任意の JavaScript eval() は許可しません。

パフォーマンスのヒント

  • 初期化は一度だけ: __wbg_init() はアプリケーション起動時に一度だけ呼び出し、トークナイズリクエストごとには呼び出さないでください。
  • トークナイザーの再利用: Tokenizer インスタンスは一度作成し、複数の tokenize() 呼び出しで再利用してください。
  • Web Workers: 大量のトークナイズ処理を行う場合は、メインスレッドのブロックを避けるため、Web Worker での Lindera の実行を検討してください。

OPFS 辞書ストレージ

Lindera WASM は、Web ブラウザでの辞書の永続キャッシュのために OPFS(Origin Private File System)ヘルパーユーティリティを提供します。辞書を一度ダウンロードすれば、WASM バイナリに埋め込むことなく、セッションをまたいで再利用できます。

概要

OPFS ヘルパーは、WASM パッケージとともに別の JavaScript モジュール(opfs.js)として配布されます。ブラウザの Origin Private File System を使用して、辞書のダウンロード、保存、読み込み、管理を行う関数を提供します。

辞書は OPFS パス lindera/dictionaries/<name>/ に保存されます。

インポート

import { downloadDictionary, loadDictionaryFiles, removeDictionary,
         listDictionaries, hasDictionary } from 'lindera-wasm-web/opfs';

関数

downloadDictionary(url, name, options?)

辞書の zip アーカイブをダウンロードし、展開して、ファイルを OPFS に保存します。

アーカイブは、必要な 8 つの辞書ファイルを含む zip ファイルである必要があります。サブディレクトリにネストされていても構いません。

  • 引数:
    • url (string) -- 辞書 zip アーカイブの URL
    • name (string) -- 辞書の保存名(例: "ipadic"
    • options (object, 省略可):
      • onProgress (function) -- 進捗コールバック
  • 戻り値: Promise<void>
await downloadDictionary(
    "https://example.com/ipadic.zip",
    "ipadic",
    {
        onProgress: (progress) => {
            switch (progress.phase) {
                case "downloading":
                    console.log(`Downloading: ${progress.loaded}/${progress.total} bytes`);
                    break;
                case "extracting":
                    console.log("Extracting archive...");
                    break;
                case "storing":
                    console.log("Storing in OPFS...");
                    break;
                case "complete":
                    console.log("Done!");
                    break;
            }
        },
    },
);

進捗コールバック

onProgress コールバックは以下の形式のオブジェクトを受け取ります:

プロパティ説明
phasestring"downloading""extracting""storing"、または "complete"
loadednumber | undefinedダウンロード済みバイト数("downloading" フェーズのみ)
totalnumber | undefined合計バイト数(判明している場合、"downloading" フェーズのみ)

loadDictionaryFiles(name)

OPFS から辞書ファイルを Uint8Array 値のオブジェクトとして読み込みます。

返されたオブジェクトは loadDictionaryFromBytes() にそのまま渡すことができます。

  • 引数: name (string) -- 辞書名(例: "ipadic"
  • 戻り値: Promise<DictionaryFiles>
const files = await loadDictionaryFiles("ipadic");

DictionaryFiles

プロパティソースファイル
metadataUint8Arraymetadata.json
dictDaUint8Arraydict.da(Double-Array Trie)
dictValsUint8Arraydict.vals(単語値データ)
dictWordsIdxUint8Arraydict.wordsidx(単語詳細インデックス)
dictWordsUint8Arraydict.words(単語詳細)
matrixMtxUint8Arraymatrix.mtx(連接コスト行列)
charDefUint8Arraychar_def.bin(文字定義)
unkUint8Arrayunk.bin(未知語辞書)

removeDictionary(name)

OPFS から辞書を削除します。

  • 引数: name (string) -- 削除する辞書名
  • 戻り値: Promise<void>
await removeDictionary("ipadic");

listDictionaries()

OPFS に保存されているすべての辞書を一覧表示します。

  • 戻り値: Promise<string[]> -- 辞書名の配列
const names = await listDictionaries();
console.log(names); // 例: ["ipadic", "unidic"]

hasDictionary(name)

OPFS に辞書が存在するかどうかを確認します。

  • 引数: name (string) -- 確認する辞書名
  • 戻り値: Promise<boolean>
if (await hasDictionary("ipadic")) {
    console.log("Dictionary is cached");
}

完全なワークフロー

OPFS ベースの辞書を使用する一般的なワークフロー:

import __wbg_init, { TokenizerBuilder, loadDictionaryFromBytes } from 'lindera-wasm-web';
import { downloadDictionary, loadDictionaryFiles, hasDictionary } from 'lindera-wasm-web/opfs';

async function main() {
    await __wbg_init();

    const DICT_NAME = "ipadic";
    const DICT_URL = "https://github.com/lindera/lindera/releases/download/<version>/lindera-ipadic-<version>.zip";

    // キャッシュされていない場合は辞書をダウンロード
    if (!await hasDictionary(DICT_NAME)) {
        await downloadDictionary(DICT_URL, DICT_NAME, {
            onProgress: ({ phase, loaded, total }) => {
                if (phase === "downloading" && total) {
                    console.log(`${(loaded / total * 100).toFixed(1)}%`);
                }
            },
        });
    }

    // OPFS から辞書を読み込み
    const files = await loadDictionaryFiles(DICT_NAME);
    const dictionary = loadDictionaryFromBytes(
        files.metadata, files.dictDa, files.dictVals, files.dictWordsIdx,
        files.dictWords, files.matrixMtx, files.charDef, files.unk,
    );

    // トークナイザーを構築
    const builder = new TokenizerBuilder();
    builder.setDictionaryInstance(dictionary);
    builder.setMode("normal");
    const tokenizer = builder.build();

    // トークナイズ
    const tokens = tokenizer.tokenize("形態素解析を行います");
    tokens.forEach(token => {
        console.log(`${token.surface}\t${token.details.join(',')}`);
    });
}

main();

必要な辞書ファイル

有効な辞書アーカイブには以下の 8 ファイルが含まれている必要があります:

ファイル説明
metadata.json辞書メタデータ(名前、エンコーディング、スキーマなど)
dict.daDouble-Array Trie 構造
dict.vals単語値データ
dict.wordsidx単語詳細インデックス
dict.words単語詳細(形態素素性)
matrix.mtx連接コスト行列
char_def.bin文字カテゴリ定義
unk.bin未知語辞書

ブラウザ互換性

OPFS は安全なコンテキスト(HTTPS または localhost)が必要で、以下のブラウザでサポートされています:

  • Chrome 86+
  • Edge 86+
  • Firefox 111+
  • Safari 15.2+

zip の展開には DecompressionStream API を使用しており、以下が必要です:

  • Chrome 80+
  • Edge 80+
  • Firefox 113+
  • Safari 16.4+

Lindera IPADIC

Lindera IPADIC は、IPADIC に基づく日本語辞書クレートです。IPADIC は、日本語の形態素解析で最も広く使われている辞書です。

目次

API リファレンス

Lindera IPADIC

辞書バージョン

このリポジトリには mecab-ipadic が含まれています。

辞書フォーマット

IPADIC の辞書フォーマットおよび品詞タグの詳細については、マニュアルを参照してください。

IndexName (Japanese)Name (English)Notes
0表層形Surface
1左文脈IDLeft context ID
2右文脈IDRight context ID
3コストCost
4品詞Part-of-speech
5品詞細分類1Part-of-speech subcategory 1
6品詞細分類2Part-of-speech subcategory 2
7品詞細分類3Part-of-speech subcategory 3
8活用形Conjugation form
9活用型Conjugation type
10原形Base form
11読みReading
12発音Pronunciation

ユーザー辞書フォーマット (CSV)

簡易版

IndexName (Japanese)Name (English)Notes
0表層形Surface
1品詞Part-of-speech
2読みReading

詳細版

IndexName (Japanese)Name (English)Notes
0表層形Surface
1左文脈IDLeft context ID
2右文脈IDRight context ID
3コストCost
4品詞Part-of-speech
5品詞細分類1Part-of-speech subcategory 1
6品詞細分類2Part-of-speech subcategory 2
7品詞細分類3Part-of-speech subcategory 3
8活用形Conjugation form
9活用型Conjugation type
10原形Base form
11読みReading
12発音Pronunciation
13--13 以降は自由に拡張可能です。

API リファレンス

API リファレンスは以下の URL から参照できます:

ビルド

このページでは、ソースファイルから IPADIC 辞書をビルドする方法を説明します。

システム辞書のビルド

IPADIC のソースファイルをダウンロードし、辞書をビルドします:

# IPADIC ソースファイルのダウンロードと展開
% curl -L -o /tmp/mecab-ipadic-2.7.0-20250920.tar.gz "https://Lindera.dev/mecab-ipadic-2.7.0-20250920.tar.gz"
% tar zxvf /tmp/mecab-ipadic-2.7.0-20250920.tar.gz -C /tmp

# 辞書のビルド
% lindera build \
  --src /tmp/mecab-ipadic-2.7.0-20250920 \
  --dest /tmp/lindera-ipadic-2.7.0-20250920 \
  --metadata ./lindera-ipadic/metadata.json

ユーザー辞書のビルド

CSV ファイルからユーザー辞書をビルドします:

% lindera build \
  --src ./resources/user_dict/ipadic_simple_userdic.csv \
  --dest ./resources/user_dict \
  --metadata ./lindera-ipadic/metadata.json \
  --user

ユーザー辞書フォーマットの詳細については、辞書フォーマットを参照してください。

バイナリへの埋め込み

IPADIC 辞書をバイナリに直接埋め込むには、以下のようにビルドします:

cargo build --features=embed-ipadic

これにより、外部辞書ファイルなしで embedded://ipadic を辞書パスとして使用できるようになります。

使用例

このページでは、IPADIC 辞書を使用したトークナイズの例を示します。

外部 IPADIC でトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict /tmp/lindera-ipadic-2.7.0-20250920
日本語  名詞,一般,*,*,*,*,日本語,ニホンゴ,ニホンゴ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
行う    動詞,自立,*,*,五段・ワ行促音便,基本形,行う,オコナウ,オコナウ
こと    名詞,非自立,一般,*,*,*,こと,コト,コト
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
でき    動詞,自立,*,*,一段,連用形,できる,デキ,デキ
ます    助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。      記号,句点,*,*,*,*,。,。,。
EOS

埋め込み IPADIC でトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict embedded://ipadic
日本語  名詞,一般,*,*,*,*,日本語,ニホンゴ,ニホンゴ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
行う    動詞,自立,*,*,五段・ワ行促音便,基本形,行う,オコナウ,オコナウ
こと    名詞,非自立,一般,*,*,*,こと,コト,コト
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
でき    動詞,自立,*,*,一段,連用形,できる,デキ,デキ
ます    助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。      記号,句点,*,*,*,*,。,。,。
EOS

注意: IPADIC 辞書をバイナリに含めるには、--features=embed-ipadic オプションを付けてビルドする必要があります。

ユーザー辞書を使用したトークナイズ (CSV フォーマット)

% echo "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です" | lindera tokenize \
  --dict embedded://ipadic \
  --user-dict ./resources/user_dict/ipadic_simple_userdic.csv
東京スカイツリー        カスタム名詞,*,*,*,*,*,東京スカイツリー,トウキョウスカイツリー,*
の      助詞,連体化,*,*,*,*,の,ノ,ノ
最寄り駅        名詞,一般,*,*,*,*,最寄り駅,モヨリエキ,モヨリエキ
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
とうきょうスカイツリー駅        カスタム名詞,*,*,*,*,*,とうきょうスカイツリー駅,トウキョウスカイツリーエキ,*
です    助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
EOS

ユーザー辞書を使用したトークナイズ (バイナリフォーマット)

% echo "東京スカイツリーの最寄り駅はとうきょうスカイツリー駅です" | lindera tokenize \
  --dict /tmp/lindera-ipadic-2.7.0-20250920 \
  --user-dict ./resources/user_dict/ipadic_simple_userdic.bin
東京スカイツリー        カスタム名詞,*,*,*,*,*,東京スカイツリー,トウキョウスカイツリー,*
の      助詞,連体化,*,*,*,*,の,ノ,ノ
最寄り駅        名詞,一般,*,*,*,*,最寄り駅,モヨリエキ,モヨリエキ
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
とうきょうスカイツリー駅        カスタム名詞,*,*,*,*,*,とうきょうスカイツリー駅,トウキョウスカイツリーエキ,*
です    助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
EOS

Rust API の使用例

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://ipadic")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let text = "日本語の形態素解析を行うことができます。";
    let mut tokens = tokenizer.tokenize(text)?;
    for token in tokens.iter_mut() {
        let details = token.details().join(",");
        println!("{}\t{}", token.surface.as_ref(), details);
    }
    Ok(())
}

Lindera IPADIC NEologd

Lindera IPADIC NEologd は、新語を含む IPADIC NEologd に基づく日本語辞書クレートです。標準の IPADIC 辞書を拡張し、最新の用語や固有名詞を追加した語彙を提供します。

目次

API リファレンス

Lindera IPADIC NEologd

辞書バージョン

このリポジトリには mecab-ipadic-neologd が含まれています。

辞書フォーマット

IPADIC の辞書フォーマットおよび品詞タグの詳細については、マニュアルを参照してください。

IndexName (Japanese)Name (English)Notes
0表層形Surface
1左文脈IDLeft context ID
2右文脈IDRight context ID
3コストCost
4品詞Part-of-speech
5品詞細分類1Part-of-speech subcategory 1
6品詞細分類2Part-of-speech subcategory 2
7品詞細分類3Part-of-speech subcategory 3
8活用形Conjugation form
9活用型Conjugation type
10原形Base form
11読みReading
12発音Pronunciation

ユーザー辞書フォーマット (CSV)

簡易版

IndexName (Japanese)Name (English)Notes
0表層形Surface
1品詞Part-of-speech
2読みReading

詳細版

IndexName (Japanese)Name (English)Notes
0表層形Surface
1左文脈IDLeft context ID
2右文脈IDRight context ID
3コストCost
4品詞Part-of-speech
5品詞細分類1Part-of-speech subcategory 1
6品詞細分類2Part-of-speech subcategory 2
7品詞細分類3Part-of-speech subcategory 3
8活用形Conjugation form
9活用型Conjugation type
10原形Base form
11読みReading
12発音Pronunciation
13--13 以降は自由に拡張可能です。

API リファレンス

API リファレンスは以下の URL から参照できます:

ビルド

このページでは、ソースファイルから IPADIC NEologd 辞書をビルドする方法を説明します。

システム辞書のビルド

IPADIC NEologd のソースファイルをダウンロードし、辞書をビルドします:

% curl -L -o /tmp/mecab-ipadic-neologd-0.0.7-20200820.tar.gz "https://lindera.dev/mecab-ipadic-neologd-0.0.7-20200820.tar.gz"
% tar zxvf /tmp/mecab-ipadic-neologd-0.0.7-20200820.tar.gz -C /tmp

% lindera build \
  --src /tmp/mecab-ipadic-neologd-0.0.7-20200820 \
  --dest /tmp/lindera-ipadic-neologd-0.0.7-20200820 \
  --metadata ./lindera-ipadic-neologd/metadata.json

バイナリへの埋め込み

IPADIC NEologd 辞書をバイナリに直接埋め込むには、以下のようにビルドします:

cargo build --features=embed-ipadic-neologd

これにより、外部辞書ファイルなしで embedded://ipadic-neologd を辞書パスとして使用できるようになります。

使用例

このページでは、IPADIC NEologd 辞書を使用したトークナイズの例を示します。

外部 IPADIC NEologd でトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict /tmp/lindera-ipadic-neologd-0.0.7-20200820
日本語  名詞,一般,*,*,*,*,日本語,ニホンゴ,ニホンゴ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
形態素解析      名詞,固有名詞,一般,*,*,*,形態素解析,ケイタイソカイセキ,ケイタイソカイセキ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
行う    動詞,自立,*,*,五段・ワ行促音便,基本形,行う,オコナウ,オコナウ
こと    名詞,非自立,一般,*,*,*,こと,コト,コト
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
でき    動詞,自立,*,*,一段,連用形,できる,デキ,デキ
ます    助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。      記号,句点,*,*,*,*,。,。,。
EOS

NEologd では「形態素解析」が単一の複合名詞として扱われますが、標準の IPADIC では「形態素」と「解析」に分割されます。

埋め込み IPADIC NEologd でトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict embedded://ipadic-neologd
日本語  名詞,一般,*,*,*,*,日本語,ニホンゴ,ニホンゴ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
形態素解析      名詞,固有名詞,一般,*,*,*,形態素解析,ケイタイソカイセキ,ケイタイソカイセキ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
行う    動詞,自立,*,*,五段・ワ行促音便,基本形,行う,オコナウ,オコナウ
こと    名詞,非自立,一般,*,*,*,こと,コト,コト
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
でき    動詞,自立,*,*,一段,連用形,できる,デキ,デキ
ます    助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
。      記号,句点,*,*,*,*,。,。,。
EOS

注意: IPADIC NEologd 辞書をバイナリに含めるには、--features=embed-ipadic-neologd オプションを付けてビルドする必要があります。

Rust API の使用例

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://ipadic-neologd")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let text = "日本語の形態素解析を行うことができます。";
    let mut tokens = tokenizer.tokenize(text)?;
    for token in tokens.iter_mut() {
        let details = token.details().join(",");
        println!("{}\t{}", token.surface.as_ref(), details);
    }
    Ok(())
}

Lindera UniDic

Lindera UniDic は、統一的な単語単位の定義を使用する UniDic に基づく日本語辞書クレートです。UniDic は IPADIC よりも詳細な形態素情報を提供し、1エントリあたり 21 フィールドを持ちます。

目次

API リファレンス

Lindera UniDic

辞書バージョン

このリポジトリには unidic-mecab が含まれています。

辞書フォーマット

unidic-mecab の辞書フォーマットおよび品詞タグの詳細については、マニュアルを参照してください。

IndexName (Japanese)Name (English)Notes
0表層形Surface
1左文脈IDLeft context ID
2右文脈IDRight context ID
3コストCost
4品詞大分類Part-of-speech
5品詞中分類Part-of-speech subcategory 1
6品詞小分類Part-of-speech subcategory 2
7品詞細分類Part-of-speech subcategory 3
8活用型Conjugation type
9活用形Conjugation form
10語彙素読みReading
11語彙素(語彙素表記 + 語彙素細分類)Lexeme
12書字形出現形Orthographic surface form
13発音形出現形Phonological surface form
14書字形基本形Orthographic base form
15発音形基本形Phonological base form
16語種Word type
17語頭変化型Initial mutation type
18語頭変化形Initial mutation form
19語末変化型Final mutation type
20語末変化形Final mutation form

ユーザー辞書フォーマット (CSV)

簡易版

IndexName (Japanese)Name (English)Notes
0表層形Surface
1品詞大分類Part-of-speech
2語彙素読みReading

詳細版

IndexName (Japanese)Name (English)Notes
0表層形Surface
1左文脈IDLeft context ID
2右文脈IDRight context ID
3コストCost
4品詞大分類Part-of-speech
5品詞中分類Part-of-speech subcategory 1
6品詞小分類Part-of-speech subcategory 2
7品詞細分類Part-of-speech subcategory 3
8活用型Conjugation type
9活用形Conjugation form
10語彙素読みReading
11語彙素(語彙素表記 + 語彙素細分類)Lexeme
12書字形出現形Orthographic surface form
13発音形出現形Phonological surface form
14書字形基本形Orthographic base form
15発音形基本形Phonological base form
16語種Word type
17語頭変化型Initial mutation type
18語頭変化形Initial mutation form
19語末変化型Final mutation type
20語末変化形Final mutation form
21--21 以降は自由に拡張可能です。

API リファレンス

API リファレンスは以下の URL から参照できます:

ビルド

このページでは、ソースファイルから UniDic 辞書をビルドする方法を説明します。

システム辞書のビルド

UniDic のソースファイルをダウンロードし、辞書をビルドします:

% curl -L -o /tmp/unidic-mecab-2.1.2.tar.gz "https://Lindera.dev/unidic-mecab-2.1.2.tar.gz"
% tar zxvf /tmp/unidic-mecab-2.1.2.tar.gz -C /tmp

% lindera build \
  --src /tmp/unidic-mecab-2.1.2 \
  --dest /tmp/lindera-unidic-2.1.2 \
  --metadata ./lindera-unidic/metadata.json

ユーザー辞書のビルド

CSV ファイルからユーザー辞書をビルドします:

% lindera build \
  --src ./resources/user_dict/unidic_simple_userdic.csv \
  --dest ./resources/user_dict \
  --metadata ./lindera-unidic/metadata.json \
  --user

ユーザー辞書フォーマットの詳細については、辞書フォーマットを参照してください。

バイナリへの埋め込み

UniDic 辞書をバイナリに直接埋め込むには、以下のようにビルドします:

cargo build --features=embed-unidic

これにより、外部辞書ファイルなしで embedded://unidic を辞書パスとして使用できるようになります。

使用例

このページでは、UniDic 辞書を使用したトークナイズの例を示します。

外部 UniDic でトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict /tmp/lindera-unidic-2.1.2
日本    名詞,固有名詞,地名,国,*,*,ニッポン,日本,日本,ニッポン,日本,ニッポン,固,*,*,*,*
語      名詞,普通名詞,一般,*,*,*,ゴ,語,語,ゴ,語,ゴ,漢,*,*,*,*
の      助詞,格助詞,*,*,*,*,ノ,の,の,ノ,の,ノ,和,*,*,*,*
形態    名詞,普通名詞,一般,*,*,*,ケイタイ,形態,形態,ケータイ,形態,ケータイ,漢,*,*,*,*
素      接尾辞,名詞的,一般,*,*,*,ソ,素,素,ソ,素,ソ,漢,*,*,*,*
解析    名詞,普通名詞,サ変可能,*,*,*,カイセキ,解析,解析,カイセキ,解析,カイセキ,漢,*,*,*,*
を      助詞,格助詞,*,*,*,*,ヲ,を,を,オ,を,オ,和,*,*,*,*
行う    動詞,一般,*,*,五段-ワア行,連体形-一般,オコナウ,行う,行う,オコナウ,行う,オコナウ,和,*,*,*,*
こと    名詞,普通名詞,一般,*,*,*,コト,事,こと,コト,こと,コト,和,コ濁,基本形,*,*
が      助詞,格助詞,*,*,*,*,ガ,が,が,ガ,が,ガ,和,*,*,*,*
でき    動詞,非自立可能,*,*,上一段-カ行,連用形-一般,デキル,出来る,でき,デキ,できる,デキル,和,*,*,*,*
ます    助動詞,*,*,*,助動詞-マス,終止形-一般,マス,ます,ます,マス,ます,マス,和,*,*,*,*
。      補助記号,句点,*,*,*,*,,。,。,,。,,記号,*,*,*,*
EOS

UniDic では「日本語」が「日本」と「語」に、「形態素」が「形態」と「素」に分割されます。これは UniDic の統一的な単語単位の定義を反映しています。

埋め込み UniDic でトークナイズ

% echo "日本語の形態素解析を行うことができます。" | lindera tokenize \
  --dict embedded://unidic
日本    名詞,固有名詞,地名,国,*,*,ニッポン,日本,日本,ニッポン,日本,ニッポン,固,*,*,*,*
語      名詞,普通名詞,一般,*,*,*,ゴ,語,語,ゴ,語,ゴ,漢,*,*,*,*
の      助詞,格助詞,*,*,*,*,ノ,の,の,ノ,の,ノ,和,*,*,*,*
形態    名詞,普通名詞,一般,*,*,*,ケイタイ,形態,形態,ケータイ,形態,ケータイ,漢,*,*,*,*
素      接尾辞,名詞的,一般,*,*,*,ソ,素,素,ソ,素,ソ,漢,*,*,*,*
解析    名詞,普通名詞,サ変可能,*,*,*,カイセキ,解析,解析,カイセキ,解析,カイセキ,漢,*,*,*,*
を      助詞,格助詞,*,*,*,*,ヲ,を,を,オ,を,オ,和,*,*,*,*
行う    動詞,一般,*,*,五段-ワア行,連体形-一般,オコナウ,行う,行う,オコナウ,行う,オコナウ,和,*,*,*,*
こと    名詞,普通名詞,一般,*,*,*,コト,事,こと,コト,こと,コト,和,コ濁,基本形,*,*
が      助詞,格助詞,*,*,*,*,ガ,が,が,ガ,が,ガ,和,*,*,*,*
でき    動詞,非自立可能,*,*,上一段-カ行,連用形-一般,デキル,出来る,でき,デキ,できる,デキル,和,*,*,*,*
ます    助動詞,*,*,*,助動詞-マス,終止形-一般,マス,ます,ます,マス,ます,マス,和,*,*,*,*
。      補助記号,句点,*,*,*,*,,。,。,,。,,記号,*,*,*,*
EOS

注意: UniDic 辞書をバイナリに含めるには、--features=embed-unidic オプションを付けてビルドする必要があります。

Rust API の使用例

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://unidic")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let text = "日本語の形態素解析を行うことができます。";
    let mut tokens = tokenizer.tokenize(text)?;
    for token in tokens.iter_mut() {
        let details = token.details().join(",");
        println!("{}\t{}", token.surface.as_ref(), details);
    }
    Ok(())
}

Lindera ko-dic

Lindera ko-dic は、mecab-ko-dic に基づく韓国語辞書クレートです。

目次

API リファレンス

Lindera ko-dic

辞書バージョン

このリポジトリには mecab-ko-dic が含まれています。

辞書フォーマット

mecab-ko-dic で使用される辞書フォーマットおよび品詞タグの情報は、mecab-ko-dic のリポジトリ README からリンクされているこの Google スプレッドシートに記載されています。

ko-dic は NAIST JDIC よりもフィールド列が 1 つ少なく、全体的に異なる情報セットを持っています(例: 単語の「原形」を提供しません)。

タグは世宗(Sejong)で規定されたものを若干修正したものです。世宗から mecab-ko-dic のタグ名へのマッピングは、上記スプレッドシートの 태그 v2.0 タブに記載されています。

辞書フォーマットの完全な仕様は(韓国語で)スプレッドシートの 사전 형식 v2.0 タブに記載されています。空の値はデフォルトで * になります。

IndexName (Korean)Name (English)Notes
0표면Surface
1왼쪽 문맥 IDLeft context ID
2오른쪽 문맥 IDRight context ID
3비용Cost
4품사 태그Part-of-speech tagスプレッドシートの 태그 v2.0 タブを参照
5의미 부류Meaning(確信するには例が少なすぎます)
6종성 유무Presence or absenceT は true、F は false、それ以外は *
7읽기Reading通常は表層形と一致しますが、外来語(例: 漢字語)では異なる場合があります
8타입TypeInflect(活用)、Compound(複合名詞)、Preanalysis(基分析)のいずれか
9첫번째 품사First part-of-speech例: 品詞タグが "VV+EM+VX+EP" の場合、VV を返します
10마지막 품사Last part-of-speech例: 品詞タグが "VV+EM+VX+EP" の場合、EP を返します
11표현Expression활용, 복합명사, 기분석이 어떻게 구성되는지 알려주는 필드 -- 活用、複合名詞、基分析がどのように構成されるかを示すフィールド

ユーザー辞書フォーマット (CSV)

簡易版

IndexName (Japanese)Name (English)Notes
0표면Surface
1품사 태그part-of-speech tagスプレッドシートの 태그 v2.0 タブを参照
2읽기reading通常は表層形と一致しますが、外来語(例: 漢字語)では異なる場合があります

詳細版

IndexName (Korean)Name (English)Notes
0표면Surface
1왼쪽 문맥 IDLeft context ID
2오른쪽 문맥 IDRight context ID
3비용Cost
4품사 태그part-of-speech tagスプレッドシートの 태그 v2.0 タブを参照
5의미 부류meaning(確信するには例が少なすぎます)
6종성 유무presence or absenceT は true、F は false、それ以外は *
7읽기reading通常は表層形と一致しますが、外来語(例: 漢字語)では異なる場合があります
8타입typeInflect(活用)、Compound(複合名詞)、Preanalysis(基分析)のいずれか
9첫번째 품사first part-of-speech例: 品詞タグが "VV+EM+VX+EP" の場合、VV を返します
10마지막 품사last part-of-speech例: 品詞タグが "VV+EM+VX+EP" の場合、EP を返します
11표현expression활용, 복합명사, 기분석이 어떻게 구성되는지 알려주는 필드 -- 活用、複合名詞、基分析がどのように構成されるかを示すフィールド
12--12 以降は自由に拡張可能です。

API リファレンス

API リファレンスは以下の URL から参照できます:

ビルド

システム辞書のビルド

mecab-ko-dic のソースファイルをダウンロード・展開し、辞書をビルドします:

% curl -L -o /tmp/mecab-ko-dic-2.1.1-20180720.tar.gz "https://Lindera.dev/mecab-ko-dic-2.1.1-20180720.tar.gz"
% tar zxvf /tmp/mecab-ko-dic-2.1.1-20180720.tar.gz -C /tmp
% lindera build \
  --src /tmp/mecab-ko-dic-2.1.1-20180720 \
  --dest /tmp/lindera-ko-dic-2.1.1-20180720 \
  --metadata ./lindera-ko-dic/metadata.json

ユーザー辞書のビルド

% lindera build \
  --src ./resources/user_dict/ko-dic_simple_userdic.csv \
  --dest ./resources/user_dict \
  --metadata ./lindera-ko-dic/metadata.json \
  --user

辞書の埋め込み

ko-dic 辞書をバイナリに直接埋め込むには、以下の feature フラグを付けてビルドします:

% cargo build --features=embed-ko-dic

使用例

外部 ko-dic でトークナイズ

% echo "한국어의형태해석을실시할수있습니다." | lindera tokenize \
  --dict /tmp/lindera-ko-dic-2.1.1-20180720
한국어  NNG,*,F,한국어,Compound,*,*,한국/NNG/*+어/NNG/*
의      JKG,*,F,의,*,*,*,*
형태    NNG,*,F,형태,*,*,*,*
해석    NNG,행위,T,해석,*,*,*,*
을      JKO,*,T,을,*,*,*,*
실시    NNG,행위,F,실시,*,*,*,*
할      XSV+ETM,*,T,할,Inflect,XSV,ETM,하/XSV/*+ᆯ/ETM/*
수      NNB,*,F,수,*,*,*,*
있      VV,*,T,있,*,*,*,*
습니다  EF,*,F,습니다,*,*,*,*
.       SF,*,*,*,*,*,*,*
EOS

埋め込み ko-dic でトークナイズ

% echo "한국어의형태해석을실시할수있습니다." | lindera tokenize \
  --dict embedded://ko-dic
한국어  NNG,*,F,한국어,Compound,*,*,한국/NNG/*+어/NNG/*
의      JKG,*,F,의,*,*,*,*
형태    NNG,*,F,형태,*,*,*,*
해석    NNG,행위,T,해석,*,*,*,*
을      JKO,*,T,을,*,*,*,*
실시    NNG,행위,F,실시,*,*,*,*
할      XSV+ETM,*,T,할,Inflect,XSV,ETM,하/XSV/*+ᆯ/ETM/*
수      NNB,*,F,수,*,*,*,*
있      VV,*,T,있,*,*,*,*
습니다  EF,*,F,습니다,*,*,*,*
.       SF,*,*,*,*,*,*,*
EOS

注意: ko-dic 辞書をバイナリに含めるには、--features=embed-ko-dic オプションを付けてビルドする必要があります。

Rust API の使用例

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://ko-dic")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let text = "한국어의형태해석을실시할수있습니다.";
    let mut tokens = tokenizer.tokenize(text)?;
    for token in tokens.iter_mut() {
        let details = token.details().join(",");
        println!("{}\t{}", token.surface.as_ref(), details);
    }
    Ok(())
}

Lindera CC-CEDICT

Lindera CC-CEDICT は、CC-CEDICT-MeCab に基づく中国語辞書クレートです。

目次

API リファレンス

Lindera CC-CE-DICT

辞書バージョン

このリポジトリには CC-CEDICT-MeCab が含まれています。

辞書フォーマット

unidic-mecab の辞書フォーマットおよび品詞タグの詳細については、マニュアルを参照してください。

IndexName (Chinese)Name (English)Notes
0表面形式Surface
1左语境IDLeft context ID
2右语境IDRight context ID
3成本Cost
4词类Part-of-speech
5词类1Part-of-speech subcategory 1
6词类2Part-of-speech subcategory 2
7词类3Part-of-speech subcategory 3
8併音Pinyin
9繁体字Traditional
10簡体字Simplified
11定义Definition

ユーザー辞書フォーマット (CSV)

簡易版

IndexName (Japanese)Name (English)Notes
0表面形式Surface
1词类Part-of-speech
2併音Pinyin

詳細版

IndexName (Japanese)Name (English)Notes
0表面形式Surface
1左语境IDLeft context ID
2右语境IDRight context ID
3成本Cost
4词类Part-of-speech
5词类1Part-of-speech subcategory 1
6词类2Part-of-speech subcategory 2
7词类3Part-of-speech subcategory 3
8併音Pinyin
9繁体字Traditional
10簡体字Simplified
11定义Definition
12--12 以降は自由に拡張可能です。

API リファレンス

API リファレンスは以下の URL から参照できます:

ビルド

システム辞書のビルド

CC-CEDICT-MeCab のソースファイルをダウンロード・展開し、辞書をビルドします:

% curl -L -o /tmp/CC-CEDICT-MeCab-0.1.0-20200409.tar.gz "https://lindera.dev/CC-CEDICT-MeCab-0.1.0-20200409.tar.gz"
% tar zxvf /tmp/CC-CEDICT-MeCab-0.1.0-20200409.tar.gz -C /tmp
% lindera build \
  --src /tmp/CC-CEDICT-MeCab-0.1.0-20200409 \
  --dest /tmp/lindera-cc-cedict-0.1.0-20200409 \
  --metadata ./lindera-cc-cedict/metadata.json

ユーザー辞書のビルド

% lindera build \
  --src ./resources/user_dict/cc-cedict_simple_userdic.csv \
  --dest ./resources/user_dict \
  --metadata ./lindera-cc-cedict/metadata.json \
  --user

辞書の埋め込み

CC-CEDICT 辞書をバイナリに直接埋め込むには、以下の feature フラグを付けてビルドします:

% cargo build --features=embed-cc-cedict

使用例

外部 CC-CEDICT でトークナイズ

% echo "可以进行中文形态学分析。" | lindera tokenize \
  --dict /tmp/lindera-cc-cedict-0.1.0-20200409
可以    *,*,*,*,ke3 yi3,可以,可以,can/may/possible/able to/not bad/pretty good/
进行    *,*,*,*,jin4 xing2,進行,进行,to advance/to conduct/underway/in progress/to do/to carry out/to carry on/to execute/
中文    *,*,*,*,Zhong1 wen2,中文,中文,Chinese language/
形态学  *,*,*,*,xing2 tai4 xue2,形態學,形态学,morphology (in biology or linguistics)/
分析    *,*,*,*,fen1 xi1,分析,分析,to analyze/analysis/CL:個|个[ge4]/
。      *,*,*,*,*,*,*,*
EOS

埋め込み CC-CEDICT でトークナイズ

% echo "可以进行中文形态学分析。" | lindera tokenize \
  --dict embedded://cc-cedict
可以    *,*,*,*,ke3 yi3,可以,可以,can/may/possible/able to/not bad/pretty good/
进行    *,*,*,*,jin4 xing2,進行,进行,to advance/to conduct/underway/in progress/to do/to carry out/to carry on/to execute/
中文    *,*,*,*,Zhong1 wen2,中文,中文,Chinese language/
形态学  *,*,*,*,xing2 tai4 xue2,形態學,形态学,morphology (in biology or linguistics)/
分析    *,*,*,*,fen1 xi1,分析,分析,to analyze/analysis/CL:個|个[ge4]/
。      *,*,*,*,*,*,*,*
EOS

注意: CC-CEDICT 辞書をバイナリに含めるには、--features=embed-cc-cedict オプションを付けてビルドする必要があります。

Rust API の使用例

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://cc-cedict")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let text = "可以进行中文形态学分析。";
    let mut tokens = tokenizer.tokenize(text)?;
    for token in tokens.iter_mut() {
        let details = token.details().join(",");
        println!("{}\t{}", token.surface.as_ref(), details);
    }
    Ok(())
}

Lindera Jieba

Lindera Jieba は、mecab-jieba に基づく中国語辞書クレートです。

目次

API リファレンス

Lindera Jieba

辞書バージョン

このリポジトリには mecab-jieba が含まれています。

辞書フォーマット

IndexName (Chinese)Name (English)Notes
0表面形式Surface
1左语境IDLeft context ID
2右语境IDRight context ID
3成本Cost
4词类Part-of-speech
5併音Pinyin
6繁体字Traditional
7簡体字Simplified
8定义Definition

ユーザー辞書フォーマット (CSV)

簡易版

IndexName (Chinese)Name (English)Notes
0表面形式Surface
1词类Part-of-speech
2併音Pinyin

詳細版

IndexName (Chinese)Name (English)Notes
0表面形式Surface
1左语境IDLeft context ID
2右语境IDRight context ID
3成本Cost
4词类Part-of-speech
5併音Pinyin
6繁体字Traditional
7簡体字Simplified
8定义Definition
9--9 以降は自由に拡張可能です。

API リファレンス

API リファレンスは以下の URL から参照できます:

ビルド

システム辞書のビルド

mecab-jieba のソースファイルをダウンロード・展開し、辞書をビルドします:

% curl -L -o /tmp/mecab-jieba-0.1.1.tar.gz "https://lindera.dev/mecab-jieba-0.1.1.tar.gz"
% tar zxvf /tmp/mecab-jieba-0.1.1.tar.gz -C /tmp
% lindera build \
  --src /tmp/mecab-jieba-0.1.1/dict-src \
  --dest /tmp/lindera-jieba-0.1.1 \
  --metadata ./lindera-jieba/metadata.json

ユーザー辞書のビルド

% lindera build \
  --src ./resources/user_dict/jieba_simple_userdic.csv \
  --dest ./resources/user_dict \
  --metadata ./lindera-jieba/metadata.json \
  --user

辞書の埋め込み

Jieba 辞書をバイナリに直接埋め込むには、以下の feature フラグを付けてビルドします:

% cargo build --features=embed-jieba

使用例

外部 Jieba でトークナイズ

% echo "可以进行中文形态学分析。" | lindera tokenize \
  --dict /tmp/lindera-jieba-0.1.1
可以    c,CHINESE,ke3 yi3,可以,可以,can/may/possible/able to/not bad/pretty good,2,可,以,high
进行    v,CHINESE,jin4 xing2,進行,进行,(of a process etc) to proceed; to be in progress; to be underway/(of people) to carry out; to conduct (an investigation or discussion etc)/(of an army etc) to be on the march; to advance,2,进,行,high
中文    nz,CHINESE,Zhong1 wen2,中文,中文,Chinese language,2,中,文,high
形态    n,CHINESE,xing2 tai4,形態,形态,shape/form/pattern/morphology,2,形,态,high
学      n,CHINESE,xue2,學,学,to learn/to study/to imitate/science/-ology,1,学,学,high
分析    vn,CHINESE,fen1 xi1,分析,分析,to analyze/analysis/CL:個|个[ge4],2,分,析,high
。      w,*,*,*,*,*,*,*,*,*
EOS

埋め込み Jieba でトークナイズ

% echo "可以进行中文形态学分析。" | lindera tokenize \
  --dict embedded://jieba
可以    c,CHINESE,ke3 yi3,可以,可以,can/may/possible/able to/not bad/pretty good,2,可,以,high
进行    v,CHINESE,jin4 xing2,進行,进行,(of a process etc) to proceed; to be in progress; to be underway/(of people) to carry out; to conduct (an investigation or discussion etc)/(of an army etc) to be on the march; to advance,2,进,行,high
中文    nz,CHINESE,Zhong1 wen2,中文,中文,Chinese language,2,中,文,high
形态    n,CHINESE,xing2 tai4,形態,形态,shape/form/pattern/morphology,2,形,态,high
学      n,CHINESE,xue2,學,学,to learn/to study/to imitate/science/-ology,1,学,学,high
分析    vn,CHINESE,fen1 xi1,分析,分析,to analyze/analysis/CL:個|个[ge4],2,分,析,high
。      w,*,*,*,*,*,*,*,*,*
EOS

注意: Jieba 辞書をバイナリに含めるには、--features=embed-jieba オプションを付けてビルドする必要があります。

Rust API の使用例

use lindera::dictionary::load_dictionary;
use lindera::mode::Mode;
use lindera::segmenter::Segmenter;
use lindera::tokenizer::Tokenizer;
use lindera::LinderaResult;

fn main() -> LinderaResult<()> {
    let dictionary = load_dictionary("embedded://jieba")?;
    let segmenter = Segmenter::new(Mode::Normal, dictionary, None);
    let tokenizer = Tokenizer::new(segmenter);

    let text = "可以进行中文形态学分析。";
    let mut tokens = tokenizer.tokenize(text)?;
    for token in tokens.iter_mut() {
        let details = token.details().join(",");
        println!("{}\t{}", token.surface.as_ref(), details);
    }
    Ok(())
}

開発ガイド

このセクションでは、Lindera のビルド、テスト、貢献に関する情報を提供します。

ビルドとテスト

ビルド

デフォルトビルド

デフォルトの feature(mmap)でワークスペースをビルドします:

cargo build

学習機能付きビルド

CRF ベースの辞書学習機能を含めてビルドします:

cargo build --features train

CLI のみビルド

cargo build -p lindera-cli

CLI ではデフォルトで train feature が有効になっています。

テスト

単一テスト

クレート内の特定のテストを実行します(開発時はこちらを推奨):

cargo test -p <crate> <test_name>

学習機能のテスト

cargo test -p lindera-dictionary --features train

クレート単位の全機能テスト

単一クレートの全テストスイートを実行します(CI と同等):

cargo test -p <crate> --all-features

ワークスペース全体のテスト

cargo test

品質チェック

フォーマットチェック

コードのフォーマットがプロジェクトのスタイルに一致しているか確認します:

cargo fmt --all -- --check

フォーマットを自動修正するには:

cargo fmt --all

リント

Clippy を警告をエラーとして扱うモードで実行します:

cargo clippy -- -D warnings

ドキュメント

API ドキュメント

Rust の API ドキュメントを生成して開きます:

cargo doc --no-deps --open

mdBook ドキュメント

ユーザー向けドキュメントをビルドします:

mdbook build docs

http://localhost:3000 でローカルプレビュー:

mdbook serve docs

Markdown リント

ドキュメントの Markdown スタイルの問題をチェックします:

markdownlint-cli2 "docs/src/**/*.md"

ルールはリポジトリルートの .markdownlint.json で設定されています。

Feature フラグ

Lindera は Cargo の feature フラグを使用して、オプション機能と辞書の埋め込みを制御します。

コア Feature

Feature説明デフォルト
mmapメモリマップドファイルサポート有効
trainCRF ベースの辞書学習(lindera-crf に依存)CLI のみ
  • mmap はメインの lindera クレートでデフォルトで有効です。
  • train はデフォルトでは lindera-cli でのみ有効です。ライブラリとして使用する場合は --features train で明示的に有効にしてください。

外部辞書の使用(推奨)

推奨される方法は、ビルド済み辞書を外部ファイルとして使用することです。GitHub Releases から辞書をダウンロードし、実行時にそのパスを指定してください:

#![allow(unused)]
fn main() {
let dictionary = load_dictionary("/path/to/ipadic")?;
}

この使用方法では、追加の feature フラグは不要です。

辞書埋め込み Feature(上級者向け)

これらの feature はビルド済み辞書をバイナリに直接埋め込み、実行時に外部辞書ファイルを不要にします。自己完結型バイナリが必要な上級者向けの機能です。

Feature辞書言語
embed-ipadicIPADIC日本語
embed-ipadic-neologdIPADIC NEologd日本語
embed-unidicUniDic日本語
embed-ko-dicko-dic韓国語
embed-cc-cedictCC-CEDICT中国語
embed-jiebaJieba中国語

いずれもデフォルトでは無効です。必要に応じて有効にしてください:

[dependencies]
lindera = { version = "2.3.2", features = ["embed-ipadic"] }

埋め込みを有効にした場合、以下のように辞書を読み込めます:

#![allow(unused)]
fn main() {
let dictionary = load_dictionary("embedded://ipadic")?;
}

組み合わせ Feature

多言語アプリケーション向けに、複数の辞書を一度に有効にするメタ Feature です。

Feature含まれる辞書
embed-cjkIPADIC + ko-dic + Jieba
embed-cjk2UniDic + ko-dic + Jieba
embed-cjk3IPADIC NEologd + ko-dic + Jieba

Feature フラグの組み合わせ

複数の feature フラグを組み合わせることができます。例えば、日本語と韓国語の辞書を両方埋め込む場合:

[dependencies]
lindera = { version = "2.3.2", features = ["embed-ipadic", "embed-ko-dic"] }

またはコマンドラインから:

cargo build --features embed-ipadic,embed-ko-dic

注意事項

  • 辞書の埋め込みはバイナリサイズを大幅に増加させます。実際に必要な辞書のみを埋め込んでください。
  • train feature は lindera-crf への依存を追加し、コンパイル時間が増加します。トークナイズのみのユースケースでは不要です。
  • mmap feature はメモリマップドによる辞書読み込みを有効にし、ディスクから読み込む大規模辞書のメモリ使用量を削減します。埋め込み辞書には影響しません。

プロジェクト構成

Lindera は複数のクレートで構成される Cargo ワークスペースとして組織されています。

ディレクトリ構成

lindera/
├── lindera-crf/            # CRF engine (pure Rust, no_std)
├── lindera-dictionary/     # Dictionary base library
├── lindera/                # Core morphological analysis library
├── lindera-cli/            # CLI tool
├── lindera-ipadic/         # IPADIC dictionary (Japanese)
├── lindera-ipadic-neologd/ # IPADIC NEologd dictionary (Japanese)
├── lindera-unidic/         # UniDic dictionary (Japanese)
├── lindera-ko-dic/         # ko-dic dictionary (Korean)
├── lindera-cc-cedict/      # CC-CEDICT dictionary (Chinese)
├── lindera-jieba/          # Jieba dictionary (Chinese)
├── lindera-python/         # Python bindings (PyO3)
├── lindera-wasm/           # WebAssembly bindings (wasm-bindgen)
├── resources/              # Test resources and sample data
├── docs/                   # Documentation (mdBook)
└── examples/               # Example code

クレートの説明

コアクレート

lindera-crf

条件付き確率場(CRF)の pure Rust 実装です。no_std 環境をサポートします。高速なゼロコピーシリアライゼーションに rkyv を使用します。辞書学習で使用される統計学習エンジンを提供します。

lindera-dictionary

辞書のベースライブラリです。辞書の読み込み、ビルド、クエリ機能を提供します。train feature を有効にすると、カスタム辞書作成のための CRF 学習パイプラインも提供します。

src/trainer/ 配下の主要モジュール:

モジュール役割
config.rs設定管理(種辞書、char.def、feature.def、rewrite.def)
corpus.rs学習コーパスの処理
feature_extractor.rs素性テンプレートの解析と素性 ID 管理
feature_rewriter.rsMeCab 互換の素性書き換え(3セクション形式)
model.rs学習済みモデルの保存、シリアライゼーション、辞書出力

lindera

メインの形態素解析ライブラリです。辞書クレートを統合し、TokenizerSegmenter、文字フィルタ、トークンフィルタを提供します。

lindera-cli

トークナイズ、辞書学習、エクスポート、ビルドのためのコマンドラインインターフェースです。デフォルトで train feature が有効です。

辞書クレート

各辞書クレートには、特定の言語と辞書ソースのビルド済み辞書データが含まれます。

クレート言語辞書ソース
lindera-ipadic日本語IPADIC
lindera-ipadic-neologd日本語IPADIC NEologd(拡張語彙)
lindera-unidic日本語UniDic
lindera-ko-dic韓国語ko-dic
lindera-cc-cedict中国語CC-CEDICT
lindera-jieba中国語Jieba

バインディング

lindera-python

PyO3 で構築された Python バインディングです。Lindera のトークナイザー API を Python アプリケーションに公開します。

lindera-wasm

wasm-bindgen で構築された WebAssembly バインディングです。ブラウザと Node.js でのトークナイズを可能にします。

その他のディレクトリ

resources/

テストスイートで使用されるサンプル辞書、ユーザー辞書、テストコーパスなどのテストリソースです。

docs/

mdBook で構築されたユーザー向けドキュメントです。目次は docs/src/SUMMARY.md で定義されています。日本語翻訳は docs/ja/ 配下にあります。

examples/

一般的な使用パターンを示す実行可能なサンプルプログラムです。以下のコマンドで実行できます:

cargo run --features=embed-ipadic --example=<example_name>

学習パイプライン

Lindera は、カスタム形態素解析モデルを作成するための CRF ベースの辞書学習機能を提供します。この機能には train feature フラグが必要です。

概要

学習パイプラインは3つのステージで構成されます:

lindera train --> model.dat --> lindera export --> dictionary files --> lindera build --> compiled dictionary
  1. Train: アノテーション付きコーパスと種辞書から CRF の重みを学習し、バイナリモデルファイルを生成します。
  2. Export: 学習済みモデルを Lindera 辞書ソースファイルに変換します。
  3. Build: ソースファイルを Lindera が実行時に読み込めるバイナリ辞書にコンパイルします。

必要な入力ファイル

1. 種辞書 (seed.csv)

MeCab CSV 形式のベース語彙辞書です。

外国,0,0,0,名詞,一般,*,*,*,*,外国,ガイコク,ガイコク
人,0,0,0,名詞,接尾,一般,*,*,*,人,ジン,ジン
参政,0,0,0,名詞,サ変接続,*,*,*,*,参政,サンセイ,サンセイ

各行の構成: surface,left_id,right_id,cost,pos,pos_detail1,pos_detail2,pos_detail3,inflection_type,inflection_form,base_form,reading,pronunciation

種辞書では left_idright_idcost フィールドは 0 に設定されます。学習器が CRF モデルから適切な値を計算します。

2. 学習コーパス (corpus.txt)

タブ区切り形式のアノテーション付きテキストデータです。各行は surface<TAB>pos_info で、文は EOS で区切られます。

外国	名詞,一般,*,*,*,*,外国,ガイコク,ガイコク
人	名詞,接尾,一般,*,*,*,人,ジン,ジン
参政	名詞,サ変接続,*,*,*,*,参政,サンセイ,サンセイ
権	名詞,接尾,一般,*,*,*,権,ケン,ケン
EOS

これ	連体詞,*,*,*,*,*,これ,コレ,コレ
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
テスト	名詞,サ変接続,*,*,*,*,テスト,テスト,テスト
EOS

学習の品質はこのコーパスの量と質に大きく依存します。

3. 文字定義 (char.def)

文字タイプのカテゴリと Unicode コードポイント範囲を定義します。

# Category definition: category_name compatibility_flag continuity_flag length
DEFAULT 0 1 0
HIRAGANA 1 1 0
KATAKANA 1 1 0
KANJI 0 0 2
ALPHA 1 1 0
NUMERIC 1 1 0

# Character range mapping
0x3041..0x3096 HIRAGANA  # Hiragana
0x30A1..0x30F6 KATAKANA  # Katakana
0x4E00..0x9FAF KANJI     # Kanji
0x0030..0x0039 NUMERIC   # Numbers
0x0041..0x005A ALPHA     # Uppercase letters
0x0061..0x007A ALPHA     # Lowercase letters

パラメータは各文字タイプの未知語がどのように分割されるかを制御します。隣接文字との互換性、同一タイプの連続が1つのトークンとして続くかどうか、デフォルトのトークン長を指定します。

4. 未知語定義 (unk.def)

文字タイプごとに未知語の処理方法を定義します。

DEFAULT,0,0,0,名詞,一般,*,*,*,*,*,*,*
HIRAGANA,0,0,0,名詞,一般,*,*,*,*,*,*,*
KATAKANA,0,0,0,名詞,一般,*,*,*,*,*,*,*
KANJI,0,0,0,名詞,一般,*,*,*,*,*,*,*
ALPHA,0,0,0,名詞,固有名詞,一般,*,*,*,*,*,*
NUMERIC,0,0,0,名詞,数,*,*,*,*,*,*,*

5. 素性テンプレート (feature.def)

CRF モデルが学習に使用する情報を定義する MeCab 互換の素性抽出パターンです。

# Unigram features (word-level)
UNIGRAM U00:%F[0]           # POS
UNIGRAM U01:%F[0],%F?[1]    # POS + POS detail (%F?[n] = optional, skipped if *)
UNIGRAM U02:%F[6]           # Base form
UNIGRAM U03:%w              # Surface form

# Bigram features (context combination)
BIGRAM B00:%L[0]/%R[0]      # Left POS / Right POS
BIGRAM B01:%L[0],%L[1]/%R[0],%R[1]  # Left POS detail / Right POS detail

テンプレート変数:

変数説明
%F[n] / %F?[n]インデックス n の素性フィールド(? = オプション、値が * の場合はスキップ)
%L[n]左文脈の素性フィールド(rewrite.def の左セクションから)
%R[n]右文脈の素性フィールド(rewrite.def の右セクションから)
%w単語の表層形
%uユニグラム書き換え後の素性文字列
%l左書き換え後の素性文字列
%r右書き換え後の素性文字列

6. 素性書き換えルール (rewrite.def)

MeCab 互換の3セクション形式による素性正規化ルールです。セクションは空行で区切られます。

# Section 1: Unigram rewrite rules
名詞,固有名詞,*  名詞,固有名詞
助動詞,*,*,*,特殊・デス  助動詞
*  *

# Section 2: Left context rewrite rules
名詞,固有名詞,*  名詞,固有名詞
助詞,*  助詞
*  *

# Section 3: Right context rewrite rules
名詞,固有名詞,*  名詞,固有名詞
助詞,*  助詞
*  *

各行は pattern<TAB>replacement です。パターンはワイルドカードとして * を使用し、前方一致で照合されます。各セクションで最初に一致したルールが適用されます。ユニグラム、左文脈、右文脈に対して異なるルールを独立して適用できるため、スパース性を低減するきめ細かい素性正規化が可能です。

学習パラメータ

パラメータ説明デフォルト
lambdaL1 正則化係数(過学習の制御)0.01
max-iterations最大学習イテレーション数100
max-threads並列処理スレッド数1

CLI の使用

Train

lindera train \
    --seed seed.csv \
    --corpus corpus.txt \
    --char-def char.def \
    --unk-def unk.def \
    --feature-def feature.def \
    --rewrite-def rewrite.def \
    --lambda 0.01 \
    --max-iter 100 \
    --max-threads 4 \
    --output model.dat

Export

学習済みモデルを辞書ソースファイルに変換します:

lindera export --model model.dat --output-dir ./dict-source

以下のファイルが生成されます:

ファイル説明
lex.csv学習済みコスト付きレキシコン
matrix.def連接コスト行列
unk.def未知語定義
char.def文字定義
feature.def素性テンプレート
rewrite.def素性書き換えルール
left-id.def左文脈 ID マッピング
right-id.def右文脈 ID マッピング
metadata.json辞書メタデータ

Build

エクスポートされたソースファイルをバイナリ辞書にコンパイルします:

lindera build --input-dir ./dict-source --output-dir ./dict-compiled

出力モデルの形式

学習済みモデルは高速読み込みのために rkyv バイナリ形式でシリアライズされます。以下を含みます:

  • CRF で学習された素性の重み
  • ラベルセット(語彙エントリー)
  • 品詞情報
  • 素性テンプレート
  • 学習メタデータ(正則化、イテレーション数、素性・ラベル数)

API の使用

#![allow(unused)]
fn main() {
use std::fs::File;
use lindera_dictionary::trainer::{Corpus, Trainer, TrainerConfig};

// Load configuration from files
let seed_file = File::open("resources/training/seed.csv")?;
let char_file = File::open("resources/training/char.def")?;
let unk_file = File::open("resources/training/unk.def")?;
let feature_file = File::open("resources/training/feature.def")?;
let rewrite_file = File::open("resources/training/rewrite.def")?;

let config = TrainerConfig::from_readers(
    seed_file,
    char_file,
    unk_file,
    feature_file,
    rewrite_file
)?;

// Initialize and configure trainer
let trainer = Trainer::new(config)?
    .regularization_cost(0.01)
    .max_iter(100)
    .num_threads(4);

// Load corpus
let corpus_file = File::open("resources/training/corpus.txt")?;
let corpus = Corpus::from_reader(corpus_file)?;

// Execute training
let model = trainer.train(corpus)?;

// Save model (binary format)
let mut output = File::create("trained_model.dat")?;
model.write_model(&mut output)?;

// Output in Lindera dictionary format
let mut lex_out = File::create("output_lex.csv")?;
let mut conn_out = File::create("output_conn.dat")?;
let mut unk_out = File::create("output_unk.def")?;
let mut user_out = File::create("output_user.csv")?;
model.write_dictionary(&mut lex_out, &mut conn_out, &mut unk_out, &mut user_out)?;

Ok::<(), Box<dyn std::error::Error>>(())
}

推奨コーパス仕様

実用的なアプリケーション向けの辞書を生成するための推奨事項:

コーパスサイズ

レベル文数用途
最小100以上基本的な動作確認
推奨1,000以上実用的なアプリケーション
理想10,000以上商用品質

品質ガイドライン

  • 語彙の多様性: さまざまな品詞のバランスの取れた分布、活用形・接尾語のカバー、専門用語・固有名詞の適切な含有。
  • 一貫性: コーパス全体で分析基準を一貫して適用すること。
  • 検証: 形態素解析結果を手動で検証すること。エラー率を5%以下に維持すること。

貢献ガイド

Lindera への貢献に興味をお持ちいただきありがとうございます。このページでは、貢献を始めるためのガイドラインを紹介します。

はじめに

  1. GitHub でリポジトリをフォークします。

  2. フォークをローカルにクローンします:

    git clone https://github.com/<your-username>/lindera.git
    cd lindera
    
  3. feature ブランチを作成します:

    git checkout -b feature/my-feature
    
  4. 変更を行い、すべてのチェックに通ることを確認します:

    cargo fmt --all -- --check
    cargo clippy -- -D warnings
    cargo test
    
  5. 変更をコミットしてプッシュし、プルリクエストを開きます。

コードスタイル

  • リポジトリの既存のコードスタイルに従ってください。
  • コミット前に cargo fmt を実行してください。
  • すべての public および private アイテム(型、関数、モジュール、フィールド、定数、型エイリアス)にドキュメントコメント(///)を記述してください。
  • trait 実装メソッドにも、実装固有の振る舞いを説明するドキュメントコメントを記述してください。
  • 関数・メソッドのドキュメントには、該当する場合 # Arguments# Returns セクションを含めてください。
  • コードコメント、ドキュメントコメント、コミットメッセージ、ログメッセージ、エラーメッセージは英語で記述してください。
  • 本番コードでは unwrap()expect() を避けてください(テストコードでは使用可)。
  • unsafe ブロックは必要な場合にのみ使用し、必ず // SAFETY: ... コメントを付けてください。
  • モジュールは mod.rs スタイルではなく、ファイルベースのスタイル(src/tokenizer.rs)を使用してください。

テスト

  • すべての新機能にユニットテストを作成してください。

  • 開発中は迅速なフィードバックのために関連するテストのみを実行してください:

    cargo test -p <crate> <test_name>
    
  • train feature に関連する作業では、feature フラグを含めてください:

    cargo test -p lindera-dictionary --features train
    

コミットメッセージ

Conventional Commits の仕様に従ってください。コミットメッセージは英語で記述してください。

例:

  • feat: add Korean dictionary support
  • fix: correct character category ID in trainer
  • docs: update installation instructions
  • refactor: split large training method into smaller functions

ドキュメント

  • 変更がユーザー向けドキュメントに影響する場合は、docs/src/ 配下の関連ファイルを更新してください。

  • Markdown ファイルの編集後は、リントエラーがないことを確認してください:

    markdownlint-cli2 "docs/src/**/*.md"
    
  • ルールはリポジトリルートの .markdownlint.json で設定されています。

依存関係

新しい依存関係を追加する際は、ライセンスの互換性を確認してください。Lindera は MIT / Apache-2.0 デュアルライセンスを使用しています。

Feature フラグ

学習関連コードの条件コンパイルには #[cfg(feature = "train")] を使用してください。完全なリストは Feature フラグ を参照してください。

問題の報告

バグを報告する際は、以下の情報を含めてください:

  • Lindera のバージョン(lindera --version または Cargo.toml を確認)
  • Rust のバージョン(rustc --version
  • オペレーティングシステム
  • 問題の再現手順
  • 期待される動作と実際の動作