6 个版本 (3 个重大变更)
0.4.2 | 2024 年 5 月 12 日 |
---|---|
0.4.1 |
|
0.4.0 | 2024 年 4 月 30 日 |
0.3.0 | 2024 年 4 月 15 日 |
0.1.1 | 2019 年 5 月 3 日 |
在 压缩 中排名 16
每月 30,296 次下载
在 37 个 包中使用 37 (直接使用 18 个)
1MB
1.5K SLoC
trie-rs
基于 LOUDS 的内存高效 trie(前缀树)和映射库。
主 API 文档 | 发布 API 文档 | 基准测试结果 | 变更日志
快速入门
要使用 trie-rs,请将以下内容添加到您的 Cargo.toml
文件中
[dependencies]
trie-rs = "0.4.2"
使用概述
use std::str;
use trie_rs::TrieBuilder;
let mut builder = TrieBuilder::new(); // Inferred `TrieBuilder<u8>` automatically
builder.push("すし");
builder.push("すしや");
builder.push("すしだね");
builder.push("すしづめ");
builder.push("すしめし");
builder.push("すしをにぎる");
builder.push("すし"); // Word `push`ed twice is just ignored.
builder.push("🍣");
let trie = builder.build();
// exact_match(): Find a word exactly match to query.
assert_eq!(trie.exact_match("すし"), true);
assert_eq!(trie.exact_match("🍣"), true);
assert_eq!(trie.exact_match("🍜"), false);
// predictive_search(): Find words which include `query` as their prefix.
let results_in_u8s: Vec<Vec<u8>> = trie.predictive_search("すし").collect();
let results_in_str: Vec<String> = trie.predictive_search("すし").collect();
assert_eq!(
results_in_str,
vec![
"すし",
"すしだね",
"すしづめ",
"すしめし",
"すしや",
"すしをにぎる"
] // Sorted by `Vec<u8>`'s order
);
// common_prefix_search(): Find words which is included in `query`'s prefix.
let results_in_u8s: Vec<Vec<u8>> = trie.common_prefix_search("すしや").collect();
let results_in_str: Vec<String> = trie.common_prefix_search("すしや").collect();
assert_eq!(
results_in_str,
vec![
"すし",
"すしや",
] // Sorted by `Vec<u8>`'s order
);
与各种数据类型的结合使用
TrieBuilder
使用泛型类型实现,如下所示
impl<Label: Ord> TrieBuilder<Label> {
...
pub fn push<Arr: AsRef<[Label]>>(&mut self, word: Arr) where Label: Clone { ... }
...
}
在上面的 使用概述
示例中,我们使用了 Label=u8, Arr=&str
。如果 Label
没有实现 Clone
,则使用 insert()
。
这里展示了其他 Label
和 Arr
类型示例。
标签=&str,Arr=Vec<&str>
假设 Label
是英文单词,而 Arr
是英文短语。
use trie_rs::TrieBuilder;
let mut builder = TrieBuilder::new();
builder.push(vec!["a", "woman"]);
builder.push(vec!["a", "woman", "on", "the", "beach"]);
builder.push(vec!["a", "woman", "on", "the", "run"]);
let trie = builder.build();
assert_eq!(
trie.exact_match(vec!["a", "woman", "on", "the", "beach"]),
true
);
let r: Vec<Vec<&str>> = trie.predictive_search(vec!["a", "woman", "on"]).collect();
assert_eq!(
r,
vec![
["a", "woman", "on", "the", "beach"],
["a", "woman", "on", "the", "run"],
],
);
let s: Vec<Vec<&str>> = trie.common_prefix_search(vec!["a", "woman", "on", "the", "beach"]).collect();
assert_eq!(
s,
vec![vec!["a", "woman"], vec!["a", "woman", "on", "the", "beach"]],
);
标签=u8,Arr=[u8;n]
假设 Label
是 π(= 3.14...)中的数字,而 Arr
是将 π 的数字每 10 个分开的窗口。
use trie_rs::TrieBuilder;
let mut builder = TrieBuilder::<u8>::new(); // Pi = 3.14...
builder.push([1, 4, 1, 5, 9, 2, 6, 5, 3, 5]);
builder.push([8, 9, 7, 9, 3, 2, 3, 8, 4, 6]);
builder.push([2, 6, 4, 3, 3, 8, 3, 2, 7, 9]);
builder.push([6, 9, 3, 9, 9, 3, 7, 5, 1, 0]);
builder.push([5, 8, 2, 0, 9, 7, 4, 9, 4, 4]);
builder.push([5, 9, 2, 3, 0, 7, 8, 1, 6, 4]);
builder.push([0, 6, 2, 8, 6, 2, 0, 8, 9, 9]);
builder.push([8, 6, 2, 8, 0, 3, 4, 8, 2, 5]);
builder.push([3, 4, 2, 1, 1, 7, 0, 6, 7, 9]);
builder.push([8, 2, 1, 4, 8, 0, 8, 6, 5, 1]);
builder.push([3, 2, 8, 2, 3, 0, 6, 6, 4, 7]);
builder.push([0, 9, 3, 8, 4, 4, 6, 0, 9, 5]);
builder.push([5, 0, 5, 8, 2, 2, 3, 1, 7, 2]);
builder.push([5, 3, 5, 9, 4, 0, 8, 1, 2, 8]);
let trie = builder.build();
assert_eq!(trie.exact_match([5, 3, 5, 9, 4, 0, 8, 1, 2, 8]), true);
let t: Vec<Vec<u8>> = trie.predictive_search([3]).collect();
assert_eq!(
t,
vec![
[3, 2, 8, 2, 3, 0, 6, 6, 4, 7],
[3, 4, 2, 1, 1, 7, 0, 6, 7, 9],
],
);
let u: Vec<Vec<u8>> = trie.common_prefix_search([1, 4, 1, 5, 9, 2, 6, 5, 3, 5]).collect();
assert_eq!(
u,
vec![[1, 4, 1, 5, 9, 2, 6, 5, 3, 5]],
);
trie 映射使用
要存储每个单词的值,请使用 trie_rs::map::{Trie, TrieBuilder}
。
use std::str;
use trie_rs::map::TrieBuilder;
let mut builder = TrieBuilder::new(); // Inferred `TrieBuilder<u8, u8>` automatically
builder.push("すし", 0);
builder.push("すしや", 1);
builder.push("すしだね", 2);
builder.push("すしづめ", 3);
builder.push("すしめし", 4);
builder.push("すしをにぎる", 5);
builder.push("すし", 6); // Word `push`ed twice uses last value.
builder.push("🍣", 7);
let mut trie = builder.build();
// exact_match(): Find a word exactly match to query.
assert_eq!(trie.exact_match("すし"), Some(&6));
assert_eq!(trie.exact_match("🍣"), Some(&7));
assert_eq!(trie.exact_match("🍜"), None);
// Values can be modified.
let v = trie.exact_match_mut("🍣").unwrap();
*v = 8;
assert_eq!(trie.exact_match("🍣"), Some(&8));
增量搜索
对于交互式应用,可以使用增量搜索以获得最佳性能。请参阅IncSearch。
use std::str;
use trie_rs::{TrieBuilder, inc_search::Answer};
let mut builder = TrieBuilder::new(); // Inferred `TrieBuilder<u8, u8>` automatically
builder.push("ab");
builder.push("すし");
builder.push("すしや");
builder.push("すしだね");
builder.push("すしづめ");
builder.push("すしめし");
builder.push("すしをにぎる");
let trie = builder.build();
let mut search = trie.inc_search();
// Query by the byte.
assert_eq!(search.query(&b'a'), Some(Answer::Prefix));
assert_eq!(search.query(&b'c'), None);
assert_eq!(search.query(&b'b'), Some(Answer::Match));
// Reset the query to go again.
search.reset();
// For unicode its easier to use .query_until().
assert_eq!(search.query_until("す"), Ok(Answer::Prefix));
assert_eq!(search.query_until("し"), Ok(Answer::PrefixAndMatch));
assert_eq!(search.query_until("や"), Ok(Answer::Match));
assert_eq!(search.query(&b'a'), None);
assert_eq!(search.query_until("a"), Err(0));
search.reset();
assert_eq!(search.query_until("ab-NO-MATCH-"), Err(2)); // No match on byte at index 2.
功能
- 泛型类型支持:如上述示例所示,trie-rs不仅可以用于搜索UTF-8字符串,还可以用于其他数据类型。
- 基于louds-rs,该库快速、并行化且内存高效。
- 最新基准测试结果始终可访问:trie-rs使用Criterion.rs在Travis CI上持续进行基准测试。图形基准测试结果发布在此。
map::Trie
将每个条目与一个Value
相关联。Value
不需要任何特质。Label: Clone
不是创建Trie<Label>
所必需的,但对于许多实现具体化搜索操作(如predictive_search()
)非常有用。- 许多搜索操作通过迭代器实现,这些迭代器是懒加载的、占用更少的内存,并且可以短路。
- 增量搜索适用于“在线”应用,即一次搜索一个
Label
。
Cargo功能
- "rayon"
启用rayon数据并行库。
- "mem_dbg"
可以确定嵌套数据结构(如trie本身)的字节数。
- "serde"
可以序列化和反序列化trie。
致谢
edict.furigana
用于基准测试。此文件按以下步骤构建
- 从EDICT下载
edict.gz
。 - 将其从原始EUC转换为UTF-8。
- 使用edict-to-csv将其转换为CSV文件。
- 提取字段$1用于平假名/片假名单词,以及字段$3用于其他(如汉字)单词。
- 使用kana2hira将片假名转换为平假名。
非常感谢这些字典和工具。
版本
trie-rs使用语义版本控制。
由于当前主版本是0,次版本更新可能会涉及破坏公共API更改(尽管会小心避免)。
Rust版本支持
trie-rs使用github CI对这些Rust版本进行持续测试
- 1.75.0带有所有功能
- 1.67.0不带功能
- 最新稳定版本
因此,预计它可以与Rust 1.75.0及其任何新版本一起使用。
较旧版本也可能可以工作,但未进行测试或保证。
更早的Rust版本支持
如果需要支持1.67.0之前的Rust版本,trie-rs 0.2.0支持Rust 1.33.0及更高版本。
贡献
欢迎任何类型的pull请求。
许可
MIT OR Apache-2.0
依赖项
~1–27MB
~393K SLoC