8 个重大版本发布
| 0.9.0 | 2020年11月6日 | 
|---|---|
| 0.7.0 | 2020年8月28日 | 
| 0.5.0 | 2020年7月31日 | 
#8 in #lucene
36 每月下载量
2.5MB
 2.5K  SLoC
JSON-Surf
搜索/分析 JSON 和 Rust 结构
功能
- 全文/术语搜索 (sqlish!!!)
- 易于读取、写入和删除 API
- 序列化 扁平 JSON/Struct
- 一次写入多个文档
- 支持模糊词搜索(见示例)
- 无需运行时
- 无不安全块
- 在 rust stable 上运行
- 即将推出:双词建议 & TF-IDF 支持
动机
- 允许您的现有扁平 rust 结构可搜索
- 当 tantivy 支持任意字节流时,该包将支持任意字节流(见此处)
- 这可以仅作为数据库中实际数据的容器,保持索引轻量
- 创建可能更新/删除的时间感知容器
- 为请求/响应创建临时存储
- 这可以与任何 Web 服务器集成以实时索引和搜索
- 该包将主要关注与用户工作流程相关的问题
- 底层使用 tantivy。
待办事项
- 添加更多示例
- 删除任何进一步的复制
- 引入更多的维护 API(如果需要)
快速入门
先决条件
 [dependencies]
 json-surf = "*"
示例
use std::convert::TryFrom;
use std::hash::{Hash, Hasher};
use std::cmp::{Ord, Ordering, Eq};
use std::fs::remove_dir_all;
use serde::{Serialize, Deserialize};
use json_surf::prelude::*;
// Main struct
#[derive(Serialize, Debug, Deserialize, PartialEq, PartialOrd, Clone)]
struct UserInfo {
    first: String,
    last: String,
    age: u8,
}
impl UserInfo {
    pub fn new(first: String, last: String, age: u8) -> Self {
        Self {
            first,
            last,
            age,
        }
    }
}
impl Default for UserInfo {
    fn default() -> Self {
        let first = "".to_string();
        let last = "".to_string();
        let age = 0u8;
        UserInfo::new(first, last, age)
    }
}
fn main() {
    // Specify home location for indexes
    let home = ".store".to_string();
    // Specify index name
    let index_name = "usage".to_string();
    // Prepare builder
    let mut builder = SurferBuilder::default();
    builder.set_home(&home);
    let data = UserInfo::default();
    builder.add_struct(index_name.clone(), &data);
    // Prepare Surf
    let mut surf = Surf::try_from(builder).unwrap();
    // Prepare data to insert & search
    // User 1: John Doe
    let first = "John".to_string();
    let last = "Doe".to_string();
    let age = 20u8;
    let john_doe = UserInfo::new(first, last, age);
    // User 2: Jane Doe
    let first = "Jane".to_string();
    let last = "Doe".to_string();
    let age = 18u8;
    let jane_doe = UserInfo::new(first, last, age);
    // See examples for more options
    let users = vec![john_doe.clone(), jane_doe.clone()];
    let _ = surf.insert(&index_name, &users).unwrap();
    block_thread(1);
    // See examples for more options
    // Similar to SELECT * FROM users WHERE (age = 20 AND last = "Doe") OR (first = "Jane")
    let conditions = vec![
        OrCondition::new(
           // (age = 20 AND last = "Doe")
            vec![
                AndCondition::new("age".to_string(), "20".to_string()),
                AndCondition::new("last".to_string(), "doe".to_string())
            ]),
        OrCondition::new(
           // (first = "Jane")
            vec![
                AndCondition::new("first".to_string(), "jane".to_string())
            ])
    ];
    // Validate John and Jane Doe
    let mut computed = surf.select::<UserInfo>(&index_name, &conditions).unwrap().unwrap();
    let mut expected = vec![john_doe.clone(), jane_doe.clone(), ];
    expected.sort();
    computed.sort();
    assert_eq!(expected, computed);
    // Validated John's record - Alternate shortcut for query using one field only
    let computed = surf.read_all_structs_by_field(&index_name, "age", "20");
    let computed: Vec<UserInfo> = computed.unwrap().unwrap();
    assert_eq!(vec![john_doe], computed);
    // Delete John's record
    let result = surf.delete(&index_name, "age", "20");
    assert!(result.is_ok());
    // John's was removed
    let computed = surf.read_all_structs_by_field(&index_name, "age", "20");
    let computed: Vec<UserInfo> = computed.unwrap().unwrap();
    assert!(computed.is_empty());
    // Clean-up
    let path = surf.which_index(&index_name).unwrap();
    let _ = remove_dir_all(&path);
    let _ = remove_dir_all(&home);
}
/// Ignore all of this
/// Convenience method for sorting & likely not required in user code
impl Ord for UserInfo {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.first == other.first && self.last == other.last {
            return Ordering::Equal;
        };
        if self.first == other.first {
            if self.last > other.last {
                Ordering::Greater
            } else {
                Ordering::Less
            }
        } else {
            if self.first > other.first {
                Ordering::Greater
            } else {
                Ordering::Less
            }
        }
    }
}
/// Ignore all of this
/// Convenience method for sorting & likely not required in user code
impl Eq for UserInfo {}
/// Ignore all of this
/// Convenience method for sorting & likely not required in user code
impl Hash for UserInfo {
    fn hash<H: Hasher>(&self, state: &mut H) {
        for i in self.first.as_bytes() {
            state.write_u8(*i);
        }
        for i in self.last.as_bytes() {
            state.write_u8(*i);
        }
        state.write_u8(self.age);
        state.finish();
    }
}
依赖项
~19–30MB
~454K SLoC