///|
/// Name-based registry for field indexing and query-time analysis.
pub struct TokenizerManager {
names : Array[String]
tokenizers : Array[&Tokenizer]
}
///|
pub fn TokenizerManager::new() -> TokenizerManager {
{ names: [], tokenizers: [] }
}
///|
pub fn TokenizerManager::register(
self : TokenizerManager,
name : String,
tokenizer : &Tokenizer,
) -> Unit raise AnalysisError {
guard @schema.valid_tokenizer_name(name) else {
raise AnalysisError::InvalidTokenizerName(name)
}
match self.names.search_by(existing => existing == name) {
Some(index) => self.tokenizers[index] = tokenizer
None => {
self.names.push(name)
self.tokenizers.push(tokenizer)
}
}
}
///|
/// Compatibility spelling for callers that explicitly register a Tokenizer.
pub fn TokenizerManager::register_tokenizer(
self : TokenizerManager,
name : String,
tokenizer : &Tokenizer,
) -> Unit raise AnalysisError {
self.register(name, tokenizer)
}
///|
pub fn TokenizerManager::contains(
self : TokenizerManager,
name : String,
) -> Bool {
self.names.search_by(existing => existing == name) is Some(_)
}
///|
pub fn TokenizerManager::snapshot(self : TokenizerManager) -> TokenizerManager {
let names : Array[String] = []
let tokenizers : Array[&Tokenizer] = []
for name in self.names {
names.push(name)
}
for tokenizer in self.tokenizers {
tokenizers.push(tokenizer)
}
{ names, tokenizers }
}
///|
/// Resolves a registered analysis pipeline as a lazy TokenStream.
pub fn TokenizerManager::token_stream(
self : TokenizerManager,
name : String,
text : String,
) -> &TokenStream raise AnalysisError {
match self.names.search_by(existing => existing == name) {
Some(index) => self.tokenizers[index].token_stream(text)
None => raise AnalysisError::UnknownTokenizer(name)
}
}
///|
/// Eager convenience API for query construction, diagnostics, and tests.
pub fn TokenizerManager::analyze(
self : TokenizerManager,
name : String,
text : String,
) -> Array[Token] raise AnalysisError {
collect_token_stream(self.token_stream(name, text))
}
///|
/// Creates the built-in pipelines. NgramTokenizer remains opt-in because its
/// parameters and use case must be chosen by the application.
pub fn TokenizerManager::with_defaults() -> TokenizerManager {
let manager = TokenizerManager::new()
manager.register_tokenizer("raw", RawTokenizer::new()) catch {
error => abort(error.to_string())
}
manager.register_tokenizer("whitespace", WhitespaceTokenizer::new()) catch {
error => abort(error.to_string())
}
let default_analyzer = TextAnalyzer::new(SimpleTokenizer::new())
default_analyzer.add_filter(RemoveLongFilter::new(40))
default_analyzer.add_filter(LowerCaseFilter::new())
manager.register("default", default_analyzer) catch {
error => abort(error.to_string())
}
manager.register("en_stem", english_stem_analyzer()) catch {
error => abort(error.to_string())
}
manager
}