28个版本

0.6.2 2024年5月4日
0.6.1 2024年3月29日
0.6.0 2023年11月18日
0.4.3 2023年2月13日
0.3.4 2021年10月30日

#3 in 数据库实现

Download history 756/week @ 2024-05-03 634/week @ 2024-05-10 692/week @ 2024-05-17 624/week @ 2024-05-24 675/week @ 2024-05-31 979/week @ 2024-06-07 640/week @ 2024-06-14 701/week @ 2024-06-21 877/week @ 2024-06-28 1080/week @ 2024-07-05 610/week @ 2024-07-12 1233/week @ 2024-07-19 6568/week @ 2024-07-26 8110/week @ 2024-08-02 10667/week @ 2024-08-09 8679/week @ 2024-08-16

每月34,502次下载
用于 oma-pm

MIT/Apache

380KB
3K SLoC

indicium

Docs Crates.io msrv

🔎 针对集合(Vec、HashMap、BTreeMap等)和键值存储的简单内存搜索。具有自动补全功能。

目前有许多令人惊叹的Rust搜索引擎。许多似乎需要编译单独的服务器二进制文件。我希望有一个简单轻量级的库,可以方便地在自己的二进制文件中搜索结构和集合。因此,我制作了indicium

alt text

尽管indicium是为Web应用程序而设计的,但它是一种内存搜索,并且不会无限扩展或扩展到云规模(即Facebook或Google规模)。即使在这样的环境中,它仍然是一种方便搜索大量列表(如货币、语言、国家等)的方法。它也非常适用于预期规模有限的应用程序(例如,搜索公司资产列表、企业内联网中用户列表等)。

Indicium可以轻松处理数百万条记录而无需费劲,这得益于Rust的BTreeMap。这个库主要受可用内存的限制。然而,根据数据集的性质以及是否存在多次重复的关键字,性能可能会开始下降。

有什么新功能?

  • 发布说明可在GitHub上找到。

  • 完整的变更日志可在GitHub上找到。

  • 0.6.1:由于潜在的问题,已移除默认的字符串相似性库eddie

  • 0.6.0:针对 Live 交互式搜索的上下文模糊匹配修复。在某些情况下,Live 搜索会返回全局结果,而没有正确地观察到 maximum_search_results 设置。这个问题已经修复。这将提高性能和用户体验。

  • 0.6.0:新增可选的、默认开启的 eddie 功能。当此功能启用时,此库将利用 Ilia Schelokoveddie crate 进行更快的 UTF-8 字符串距离和字符串相似度计算。

  • 0.6.0:新增可选的 gxhash 功能。虽然 ahash 仍然是默认的哈希器,但启用此功能后,此库将利用 Olivier Giniaux 的前沿 gxhash crate 进行更快的 HashMapHashSet 哈希。

快速入门指南

在我们的 快速入门指南 示例中,我们将搜索以下 struct

struct MyStruct {
    title: String,
    year: u16,
    body: String,
}

1. 实现索引功能

首先,我们必须使我们的记录可索引。我们将通过为我们的 struct 实现索引功能。想法是返回我们希望索引的每个字段的字符串。示例

use indicium::simple::Indexable;

impl Indexable for MyStruct {
    fn strings(&self) -> Vec<String> {
        vec![
            self.title.clone(),
            self.year.to_string(),
            self.body.clone(),
        ]
    }
}

别忘了,您可以通过将数字、数字标识符、枚举和其他类型(或其他复杂类型)转换为字符串并将它们包含在返回的 Vec<String> 中来使您的 struct(或其他复杂类型)可索引。

2. 索引集合

要索引现有集合,我们可以遍历该集合。对于每条记录,我们将将其插入到搜索索引中。这应该类似于以下两个示例

Vec

use indicium::simple::SearchIndex;

let my_vec: Vec<MyStruct> = Vec::new();

// In the case of a `Vec` collection, we use the index as our key. A
// `Vec` index is a `usize` type. Therefore we will instantiate
// `SearchIndex` as `SearchIndex<usize>`.

let mut search_index: SearchIndex<usize> = SearchIndex::default();

my_vec
    .iter()
    .enumerate()
    .for_each(|(index, element)|
        search_index.insert(&index, element)
    );

HashMap

use std::collections::HashMap;
use indicium::simple::SearchIndex;

let my_hash_map: HashMap<String, MyStruct> = HashMap::new();

// In the case of a `HashMap` collection, we use the hash map's key as
// the `SearchIndex` key. In our hypothetical example, we will use
// MyStruct's `title` as a the key which is a `String` type. Therefore
// we will instantiate `HashMap<K, V>` as HashMap<String, MyStruct> and
// `SearchIndex<K>` as `SearchIndex<String>`.

let mut search_index: SearchIndex<String> = SearchIndex::default();

my_hash_map
    .iter()
    .for_each(|(key, value)|
        search_index.insert(key, value)
    );

只要为您的值类型实现了 Indexable trait,上述示例将索引先前填充的 VecHashMap。然而,对于大型集合,建议在将数据插入您的集合(Vec、HashMap 等)的同时将数据插入 SearchIndex

建议将目标集合(您的 Vec、HashMap 等)和此 SearchIndex 一起包裹在一个新的 struct 类型中。然后,为这个新的 struct 类型实现 insertreplaceremove 等方法,这将更新集合和搜索索引。这将确保您的集合和索引始终同步。

一旦索引被填充,您就可以使用 searchautocomplete 方法。

3. 搜索

search 方法将返回键作为搜索结果。然后可以使用每个结果键从其集合中检索完整记录。

基本用法

let mut search_index: SearchIndex<usize> = SearchIndex::default();

search_index.insert(&0, &"Harold Godwinson");
search_index.insert(&1, &"Edgar Ætheling");
search_index.insert(&2, &"William the Conqueror");
search_index.insert(&3, &"William Rufus");
search_index.insert(&4, &"Henry Beauclerc");

let resulting_keys: Vec<&usize> = search_index.search("William");

assert_eq!(resulting_keys, vec![&2, &3]);

// Demonstrating fuzzy matching:

let resulting_keys: Vec<&usize> = search_index.search("Harry");

assert_eq!(resulting_keys, vec![&0]);

搜索只支持精确关键词匹配。对于 Live 搜索,模糊匹配仅应用于最后一个关键词。考虑为用户提供 autocomplete 功能,作为模糊匹配的人性化替代方案。

4. 自动完成

autocomplete 方法将为提供的字符串中的最后一个关键词提供几个自动完成选项。

基本用法

let mut search_index: SearchIndex<usize> =
    SearchIndexBuilder::default()
        .autocomplete_type(&AutocompleteType::Global)
        .build();

search_index.insert(&0, &"apple");
search_index.insert(&1, &"ball");
search_index.insert(&3, &"bird");
search_index.insert(&4, &"birthday");
search_index.insert(&5, &"red");

let autocomplete_options: Vec<String> =
    search_index.autocomplete("a very big bi");

assert_eq!(
    autocomplete_options,
    vec!["a very big bird", "a very big birthday"]
);

// Demonstrating fuzzy matching:

let autocomplete_options: Vec<String> =
    search_index.autocomplete("a very big birf");

assert_eq!(
    autocomplete_options,
    vec!["a very big bird", "a very big birthday"]
);

依赖项

~1.1–1.6MB
~24K SLoC