Skip to content

Commit

Permalink
- query added
Browse files Browse the repository at this point in the history
- example added
  • Loading branch information
julfikar committed Apr 18, 2023
1 parent c7362e4 commit e62d3cc
Show file tree
Hide file tree
Showing 9 changed files with 408 additions and 26 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@ rayon = "1.7.0"
serde = { version="1.0.159", features=["derive"] }
serde_json = "1.0.95"
chrono = "0.4.24"
lazy_static = "1.4.0"
thiserror = "1.0.40"
uuid = { version="1.3.1", features = ["v4","fast-rng","macro-diagnostics"] }
44 changes: 41 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,52 @@
<img src="./assets/flinch.png" alt="Flinch">
<img src="assets/flinch.png">

[![Rust](https://github.com/mjm918/flinch/actions/workflows/rust.yml/badge.svg)](https://github.com/mjm918/flinch/actions/workflows/rust.yml)

Flinch is an in-memory, real-time document database designed for fast and efficient full-text search. It comes with a built-in full-text search engine that enables both "search-as-you-type" and wildcard search capabilities. Flinch was created with the goal of providing a high-performance search solution that can be integrated into various applications.
Flinch is an in-memory, real-time document database designed for fast, efficient full-text search and querying. It comes with a built-in full-text search engine that enables both "search-as-you-type" and like search capabilities. Flinch was created with the goal of providing a high-performance search solution that can be integrated into various applications.

# Features
- In-memory database: Flinch stores documents in memory, allowing for ultra-fast search performance.
- Real-time updates: Flinch supports real-time updates, enabling users to add, update, and delete documents in real-time.
- Full-text search: Flinch has a built-in full-text search engine that provides powerful search capabilities, including search-as-you-type and wildcard search.
- Lightweight and easy to use: Flinch is designed to be lightweight and easy to use, with a simple API that allows developers to quickly integrate it into their applications.
- Document-oriented: Flinch is document-oriented, allowing users to store and retrieve documents as JSON objects.
- Highly scalable: Flinch is designed to be highly scalable, allowing users to handle large volumes of documents and queries efficiently.
- Highly scalable: Flinch is designed to be highly scalable, allowing users to handle large volumes of documents and queries efficiently.\
- Query: Document query faster than ⚡️
- Open source: Flinch is an open-source project, allowing users to contribute to its development and customize it to suit their needs.

# How to use

Refer to [lib.rs](src%2Flib.rs)

# Query Example

```
{
product_status: { gt: 0 },
cust_code: { like: "Abs-001" },
salesperson_id: { eq: "19982" },
uom_price: {
prop: "price",
lt: 10
}
}
```
assume `document` is something like below:
```
{
product_code: "",
product_name: "",
product_status: 1 OR 0,
cust_code: [
"A12390",
"A89900"
],
salesperson_id: [
19928,
18320
],
uom_price:[
{id: 1, price: 9}
]
}
```
Binary file modified assets/flinch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 17 additions & 3 deletions src/col.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::err::QueryError;
use crate::hdrs::{Event, ActionType, SessionRes, QueryResult, QueryType};
use crate::hidx::HashIndex;
use crate::ividx::InvertedIndex;
use crate::qry::Query;
use crate::range::Range;
use crate::sess::Session;
use crate::utils::ExecTime;
Expand Down Expand Up @@ -305,11 +306,24 @@ where K: Serialize
self.kv.clear();
}

pub fn query(&self, cmd: &str) -> Result<SegQueue<RefMulti<K, D>>, QueryError> {
pub fn query(&self, cmd: &str) -> Result<QueryResult<SegQueue<(K, D)>>, QueryError> {
let exec = ExecTime::new();
let qry = Query::new(cmd);
if qry.is_err() {
return Err(qry.err().unwrap());
}
let qry = qry.unwrap();
let mut res = SegQueue::new();
self.iter().for_each(|it|{
let chk = it.value().document().pointer(cmd);
let is_ok = qry.filter(it.value());
if is_ok {
res.push((it.key().clone(), it.value().clone()));
}
});
Ok(res)
Ok(QueryResult {
query: QueryType::Query(cmd.to_string()),
data: res,
time_taken: exec.done(),
})
}
}
4 changes: 3 additions & 1 deletion src/ividx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use serde::de::DeserializeOwned;
use serde::Serialize;
use tokio::io::AsyncReadExt;
use tokio::task::JoinHandle;
use crate::utils::tokenize;

pub struct InvertedIndex<K> {
pub kv: Arc<DashMap<String, DashSet<K>>>
Expand Down Expand Up @@ -35,7 +36,8 @@ impl<K> InvertedIndex<K>
pub fn put(&self, k: K, v: String) -> JoinHandle<()> {
let rf = self.kv.clone();
tokio::spawn(async move {
for w in v.split_whitespace() {
let separated = tokenize(&v);
for w in separated {
let token = w.to_lowercase();
let key = &k;
match rf.get_mut(&token) {
Expand Down
57 changes: 49 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,23 @@ pub mod db;
mod qry;
mod utils;

///
/// Examples
/// 1M records
/// insert:: 61.118093292s
/// single:: 3.25µs
/// multi:: 6.458µs
/// search index:: 27.209µs result count 1
/// search:: 2.494042417s result count 402130
/// view:: 45.084µs result count 1
/// query:: 438.283791ms result count 10 with query {"age":{"$lt":10}}
///
#[cfg(test)]
mod tests {
use std::fmt::format;
use std::sync::Arc;
use std::time::{Instant};
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc::channel;
use crate::doc::{Document, FromRawString, ViewConfig};
use crate::db::{Database, CollectionOptions};
use crate::hdrs::{Event, ActionType};
Expand Down Expand Up @@ -54,8 +63,11 @@ mod tests {
let collection = instance.value();
assert_eq!(collection.len(),0);

let (sx, mut rx) = tokio::sync::mpsc::channel(30000);
collection.sub(sx).await.expect("subscribe to channel");

let insert = Instant::now();
let record_size = 100_000;
let record_size = 10_000;
for i in 0..record_size {
collection.put(format!("P_{}",&i), FromRawString::new(
serde_json::to_string(
Expand All @@ -73,20 +85,49 @@ mod tests {
assert!(single.data.is_some());
println!("single:: {:?}", single.time_taken);

let multi = collection.multi_get(vec![&format!("P_100"),&format!("P_1999")]);
assert_eq!(multi.data.len(),2);
let multi = collection.multi_get(vec![&format!("P_1"),&format!("P_0")]);
assert_ne!(multi.data.len(),0);
println!("multi:: {:?}",multi.time_taken);

let search = collection.search("Julfikar9999");
let search = collection.search("Julfikar0");
assert_ne!(search.data.len(),0);
println!("search:: {} res {}",search.time_taken, search.data.len());
println!("search index:: {} res {}",search.time_taken, search.data.len());

let like_search = collection.like_search("Julfikar 99 11");
let like_search = collection.like_search("Julfikar 0");
assert_ne!(like_search.data.len(),0);
println!("search:: {} res {}",like_search.time_taken, like_search.data.len());

let view = collection.fetch_view("ADULT");
assert_ne!(view.data.len(),0);
println!("view:: {} res {}",view.time_taken, view.data.len());

let query = collection.query(r#"{"age":{"$lt":10}}"#);
assert!(query.is_ok());
let query = query.unwrap();
println!("query:: {} {}", query.time_taken,query.data.len());

let mut i = 0;
loop {
let event = rx.recv().await.unwrap();
match event {
Event::Data(d) => {
match d {
ActionType::Insert(k, v) => {
println!("inserted :watcher: {}",k)
}
ActionType::Remove(k) => {

}
};
}
Event::Subscribed(s) => {

}
};
i += 1;
if i == 10 { // for demo, listen till 10 message only
break;
}
}
}
}
Loading

0 comments on commit e62d3cc

Please sign in to comment.