litsea-ruby
Ruby binding for Litsea, a compact word segmentation and POS (Part-of-Speech) tagging library for Japanese, Chinese, Korean, and English.
Installation
gem install litsea
The gem compiles the native extension on install, so a Rust toolchain is required. Ruby 3.1 or later.
Models are not bundled
The gem ships code only. Download a pre-trained model from the Litsea repository and point the segmenter at it:
| Model | Purpose | Size |
|---|---|---|
japanese.model, chinese.model, korean.model, english.model |
Segmentation | 84 KB – 2.0 MB |
japanese_pos.model, chinese_pos.model, korean_pos.model, english_pos.model |
Segmentation + POS | 3.0 – 8.0 MB |
You never have to say which kind you have: the model file identifies itself, and has_pos? reports what the loaded model can do.
Usage
Segmentation
require "litsea"
seg = Litsea::Segmenter.open(:japanese, "models/japanese.model")
seg.segment("これはテストです。")
# => ["これ", "は", "テスト", "です", "。"]
seg.segment_batch(["これはテストです。", "東京都から神奈川県へ引っ越した"])
The language accepts a Symbol or a String, and the ISO 639-1 code works too: :ja, "japanese".
For space-delimited languages the whitespace comes back as its own token, so the tokens always reconstruct the input:
Litsea::Segmenter.open(:korean, "models/korean.model").segment("안녕하세요 반갑습니다")
# => ["안녕하세요", " ", "반갑습니다"]
POS tagging
seg = Litsea::Segmenter.open(:japanese, "models/japanese_pos.model")
seg.segment_with_pos("これはテストです。").each do |token|
puts "#{token.surface}\t#{token.pos}\t[#{token.start}..#{token.end}]"
end
# これ PRON [0..6]
# は ADP [6..9]
# テスト NOUN [9..18]
# です AUX [18..24]
# 。 PUNCT [24..27]
start and end are byte offsets, so slice with byteslice — Ruby's String#[] counts characters:
text.byteslice(token.start, token.end - token.start) # == token.surface
Calling segment_with_pos on a segmentation-only model raises Litsea::PosUnavailableError.
Other model sources
Litsea::Segmenter.from_bytes(:korean, File.binread("korean.model"))
Litsea::Segmenter.from_uri(:chinese, "https://example.com/chinese.model")
Training
Litsea::Extractor.new(:japanese).extract("corpus.txt", "features.txt")
metrics = Litsea::Trainer.new(0.01, 10_000, "features.txt").train("japanese.model")
puts format("accuracy: %.2f%%", metrics.accuracy)
Two-stage (segmentation + POS) training:
Litsea::Extractor.new(:japanese).extract_two_stage("corpus_pos.txt", "features", feature_set: "fast")
metrics = Litsea::TwoStageTrainer.new(10, "features").train("japanese_pos.model")
puts metrics.stage1.accuracy, metrics.stage2.accuracy
A TwoStageTrainer can only be used once — training collapses stage 1 into an AdaBoost model, which consumes it. available? reports whether it can still run, and a second train raises.
Cancelling a training run
Training releases the GVL, so other Ruby threads keep running — which means one of them can stop a run that is already going:
cancel = Litsea::CancelToken.new
Thread.new { sleep 60; cancel.cancel }
metrics = Litsea::Trainer.new(0.01, 100_000, "features.txt").train("japanese.model", cancel: cancel)
Cancelling is not an error: training stops at its next check point, still writes the partially trained model, and returns its metrics. The binding never installs a signal handler.
Errors
Every error derives from Litsea::Error, so one rescue handles them all.
| Error | Raised when |
|---|---|
Litsea::InvalidArgumentError |
Unknown language name, unknown feature set, reused trainer |
Litsea::ModelError |
Download failed, or the file is a legacy joint POS model |
Litsea::IoError |
A file could not be read or written |
Litsea::ParseError |
The model or training data is malformed |
Litsea::UnsupportedError |
The scheme or operation is unavailable in this build |
Litsea::PosUnavailableError |
POS tagging requested from a segmentation-only model |
Development
make test-litsea-ruby # cargo test + rake compile + rake test
make build-litsea-ruby # release build
The parity tests build the litsea CLI and compare the binding's output against it. Note that bundle must be available for the active Ruby; with rbenv, rbenv local 3.4.9 (or any installed 3.1+) is enough.
License
MIT. See LICENSE.