#tantivy #icu #localization

tantivy-analysis-contrib

一组Tantivy的分析组件

19个版本 (11个重大更新)

0.12.2 2024年8月11日
0.12.1 2024年6月21日
0.12.0 2024年4月12日
0.11.1 2024年2月28日
0.1.0 2022年3月22日

144文本处理

Download history 4/week @ 2024-05-27 102/week @ 2024-06-17 10/week @ 2024-06-24 20/week @ 2024-07-15 7/week @ 2024-07-22 67/week @ 2024-08-05

每月94 次下载

MIT/Apache

290KB
7.5K SLoC

Tantivy分析

Crate Build Status codecov dependency status Documentation Crate Crate

这是一个针对 TantivyTokenizerTokenFilters 的集合,旨在复制 Lucene 中的功能。

它依赖于Google的 Rust ICU。为了编译,需要安装 libicu-dev 和 clang。

破坏性单词规则来自 Lucene

功能

  • icu 功能包括以下组件(它们也是功能)
    • ICUTokenizer
    • ICUNormalizer2TokenFilter
    • ICUTransformTokenFilter
  • commons 功能包括以下组件
    • LengthTokenFilter
    • LimitTokenCountFilter
    • PathTokenizer
    • ReverseTokenFilter
    • ElisionTokenFilter
    • EdgeNgramTokenFilter
  • phonetic 功能包括一些语音算法(Beider-Morse,Soundex,Metaphone等,请参阅Crate文档
    • PhoneticTokenFilter
  • embedded 启用 rphonetic crate 的嵌入式规则。此功能默认不包含。它有两个子功能 embedded-bm,它只启用嵌入式 Beider-Morse 规则,以及 embedded-dm,它只启用 Daitch-Mokotoff 规则。

请注意,语音支持可能需要改进。

默认情况下,包含 icucommonsphonetic

示例

use tantivy::collector::TopDocs;
use tantivy::query::QueryParser;
use tantivy::schema::{IndexRecordOption, SchemaBuilder, TextFieldIndexing, TextOptions, Value};
use tantivy::tokenizer::TextAnalyzer;
use tantivy::{doc, Index, ReloadPolicy, TantivyDocument};
use tantivy_analysis_contrib::icu::{Direction, ICUTokenizer, ICUTransformTokenFilter};

const ANALYSIS_NAME: &str = "test";

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let options = TextOptions::default()
        .set_indexing_options(
            TextFieldIndexing::default()
                .set_tokenizer(ANALYSIS_NAME)
                .set_index_option(IndexRecordOption::WithFreqsAndPositions),
        )
        .set_stored();
    let mut schema = SchemaBuilder::new();
    schema.add_text_field("field", options);
    let schema = schema.build();

    let transform = ICUTransformTokenFilter::new(
        "Any-Latin; NFD; [:Nonspacing Mark:] Remove; Lower;  NFC".to_string(),
        None,
        Direction::Forward,
    )?;
    let icu_analyzer = TextAnalyzer::builder(ICUTokenizer)
        .filter(transform)
        .build();

    let field = schema.get_field("field").expect("Can't get field.");

    let index = Index::create_in_ram(schema);
    index.tokenizers().register(ANALYSIS_NAME, icu_analyzer);

    let mut index_writer = index.writer(15_000_000)?;

    index_writer.add_document(doc!(
        field => "中国"
    ))?;
    index_writer.add_document(doc!(
        field => "Another Document"
    ))?;

    index_writer.commit()?;

    let reader = index
        .reader_builder()
        .reload_policy(ReloadPolicy::Manual)
        .try_into()?;

    let searcher = reader.searcher();

    let query_parser = QueryParser::for_index(&index, vec![field]);

    let query = query_parser.parse_query("zhong")?;
    let top_docs = searcher.search(&query, &TopDocs::with_limit(10))?;
    let mut result: Vec<String> = Vec::new();
    for (_, doc_address) in top_docs {
        let retrieved_doc = searcher.doc::<TantivyDocument>(doc_address)?;
        result = retrieved_doc
            .get_all(field)
            .map(|v| v.as_str().unwrap().to_string())
            .collect();
    }
    let expected: Vec<String> = vec!["中国".to_string()];
    assert_eq!(expected, result);

    let query = query_parser.parse_query("")?;
    let top_docs = searcher.search(&query, &TopDocs::with_limit(10))?;
    let mut result: Vec<String> = Vec::new();
    for (_, doc_address) in top_docs {
        let retrieved_doc = searcher.doc::<TantivyDocument>(doc_address)?;
        result = retrieved_doc
            .get_all(field)
            .map(|v| v.as_str().unwrap().to_string())
            .collect();
    }
    let expected: Vec<String> = vec!["中国".to_string()];
    assert_eq!(expected, result);
    let query = query_parser.parse_query("document")?;
    let top_docs = searcher.search(&query, &TopDocs::with_limit(10))?;
    let mut result: Vec<String> = Vec::new();
    for (_, doc_address) in top_docs {
        let retrieved_doc = searcher.doc::<TantivyDocument>(doc_address)?;
        result = retrieved_doc
            .get_all(field)
            .map(|v| v.as_str().unwrap().to_string())
            .collect();
    }
    let expected: Vec<String> = vec!["Another Document".to_string()];
    assert_eq!(expected, result);
    Ok(())
}

许可

根据您的选择许可以下之一

贡献

除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交并包含在作品中的任何贡献,均应双授权,且无任何附加条款或条件。

依赖项

~0.6–2.9MB
~56K SLoC