Architecture

Lindera is organized as a Cargo workspace comprising multiple crates. Each crate has a focused responsibility, from low-level CRF computation to high-level CLI and language bindings.

Crate Dependency Graph

graph TB
    CRF["lindera-crf\n(CRF Engine)"]
    DICT["lindera-dictionary\n(Dictionary Base)"]
    TRAINER["lindera-trainer\n(CRF Training)"]
    IPADIC["lindera-ipadic"]
    UNIDIC["lindera-unidic"]
    SUDACHIDICT["lindera-sudachidict"]
    KODIC["lindera-ko-dic"]
    CCCEDICT["lindera-cc-cedict"]
    JIEBA["lindera-jieba"]
    NEOLOGD["lindera-ipadic-neologd"]
    SEGMENTER["lindera-segmenter\n(Segmenter)"]
    ANALYSIS["lindera-analysis\n(Analysis Chain)"]
    LIB["lindera\n(Facade)"]
    CLI["lindera-cli\n(CLI)"]
    BINDING["lindera-binding"]
    PY["lindera-python"]
    NODEJS["lindera-nodejs"]
    RUBY["lindera-ruby"]
    PHP["lindera-php"]
    WASM["lindera-wasm"]

    CRF --> TRAINER
    DICT --> TRAINER
    TRAINER -.->|"train feature"| SEGMENTER
    DICT --> IPADIC
    DICT --> UNIDIC
    DICT --> SUDACHIDICT
    DICT --> KODIC
    DICT --> CCCEDICT
    DICT --> JIEBA
    DICT --> NEOLOGD
    DICT --> SEGMENTER
    IPADIC --> SEGMENTER
    UNIDIC --> SEGMENTER
    SUDACHIDICT --> SEGMENTER
    KODIC --> SEGMENTER
    CCCEDICT --> SEGMENTER
    JIEBA --> SEGMENTER
    NEOLOGD --> SEGMENTER
    SEGMENTER --> ANALYSIS
    SEGMENTER --> LIB
    ANALYSIS -.->|"analysis feature"| LIB
    LIB --> CLI
    LIB --> BINDING
    BINDING --> PY
    BINDING --> NODEJS
    BINDING --> RUBY
    BINDING --> PHP
    BINDING --> WASM

Crate Overview

CrateTypeDescription
lindera-crfCorePure Rust CRF (Conditional Random Field) implementation. Supports no_std. Uses rkyv for serialization.
lindera-dictionaryCoreDictionary base library. Provides dictionary loading and building.
lindera-trainerCoreCRF-based dictionary training pipeline. Builds on lindera-crf and lindera-dictionary; consumed directly or via the lindera facade's train feature.
lindera-segmenterCorePure morphological segmenter (the lindera crate of v6 and earlier). Integrates the dictionary crates and provides the Segmenter API.
lindera-analysisCoreLucene-style analysis chain on top of lindera-segmenter: character filters, token filters, and the Tokenizer that composes them around a Segmenter. Reachable as lindera::analysis.
linderaCoreFacade crate and the one dependency Rust users add: re-exports lindera-segmenter and, with the default analysis feature, lindera-analysis as lindera::analysis.
lindera-cliApplicationCommand-line interface for tokenization, dictionary building, and CRF training.
lindera-bindingCoreFFI-independent helpers shared by the five language bindings below; depends on the lindera facade.
lindera-ipadicDictionaryJapanese dictionary based on IPADIC.
lindera-ipadic-neologdDictionaryJapanese dictionary based on IPADIC NEologd (includes neologisms).
lindera-unidicDictionaryJapanese dictionary based on UniDic.
lindera-sudachidictDictionaryJapanese dictionary based on SudachiDict.
lindera-ko-dicDictionaryKorean dictionary based on ko-dic.
lindera-cc-cedictDictionaryChinese dictionary based on CC-CEDICT.
lindera-jiebaDictionaryChinese dictionary based on Jieba.
lindera-pythonBindingPython bindings via PyO3.
lindera-nodejsBindingNode.js bindings via NAPI-RS.
lindera-rubyBindingRuby bindings via Magnus + rb-sys.
lindera-phpBindingPHP bindings via ext-php-rs.
lindera-wasmBindingWebAssembly bindings via wasm-bindgen.

Tokenization Pipeline

Lindera processes text through a multi-stage pipeline:

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

The Segmenter is the core component. It builds a lattice of candidate tokens from the dictionary, then applies the Viterbi algorithm to find the lowest-cost path, producing the most likely segmentation. Dictionary lookups walk a char-wise double-array trie (built with crawdad) in place over the serialized bytes of dict.trie, rather than deserializing into an owned structure. For repeated tokenization, Segmenter::new_worker() returns a SegmentWorker that reuses lattice and scratch-buffer allocations across calls, with an automatic shrink policy to bound retained memory.

Feature Flags

FeatureDescriptionDefault
analysisRe-export of lindera-analysis as lindera::analysis (character filters, token filters, Tokenizer)Enabled (off with default-features = false)
mmapMemory-mapped file support for filesystem-based dictionary loading (opt-in via --mmap/use_mmap; the word-list files, the connection-cost matrix, and the trie all stay lazily paged)Enabled
trainCRF-based dictionary training functionality (depends on lindera-crf)CLI + Python/Node.js/Ruby/PHP bindings (default); opt-in for the lindera library crate; unavailable in lindera-wasm
embed-ipadicEmbed the IPADIC dictionary into the binaryDisabled
embed-ipadic-neologdEmbed the IPADIC NEologd dictionary into the binaryDisabled
embed-unidicEmbed the UniDic dictionary into the binaryDisabled
embed-sudachidictEmbed the SudachiDict dictionary into the binaryDisabled
embed-ko-dicEmbed the ko-dic dictionary into the binaryDisabled
embed-cc-cedictEmbed the CC-CEDICT dictionary into the binaryDisabled
embed-jiebaEmbed the Jieba dictionary into the binaryDisabled
embed-cjkEmbed IPADIC + ko-dic + Jieba dictionariesDisabled
embed-cjk2Embed UniDic + ko-dic + Jieba dictionariesDisabled
embed-cjk3Embed IPADIC NEologd + ko-dic + Jieba dictionariesDisabled
embed-cjk4Embed SudachiDict + ko-dic + Jieba dictionariesDisabled

Learn More