A simple search engine for collections (Vec, HashMap, BTreeMap, etc) and key-value stores. Includes capability for autocomplete.
There are many incredible search engines available for Rust but many seem to
require compiling a separate server binary or are too heavy for my use-case. I
also couldn't find options for searching structs and collections, hence
indicium
.
For our Quick Start Guide example, we will be searching inside of the
following struct
:
rust
struct MyStruct {
title: String,
description: String,
}
To begin, we must make our record indexable. We'll do this by implementing the
Indexable
trait for our struct
. The idea is to return a String
for every
field that we would like to be indexed. Example:
```rust use indicium::simple::Indexable;
impl Indexable for MyStruct {
fn strings(&self) -> Vec
Don't forget that you may make numbers, numeric identifiers, enums, and other
types indexable by converting them to a String
and including them in the
returned Vec<String>
.
To index an existing collection, we can iterate over the collection. For each record, we will insert it into the search index. This should look something like these two examples:
```rust use indicium::simple::SearchIndex;
let mut search_index: SearchIndex
myvec .iter() .enumerate() .foreach(|(index, element)| search_index.insert(&index, element) ); ```
```rust use indicium::simple::SearchIndex;
let mut search_index: SearchIndex
myhashmap .iter() .foreach(|(key, value)| search_index.insert(&key, value) ); ```
The above examples will index a previously populated Vec
or HashMap
.
However, the preferred method for large collections is to insert
into the
SearchIndex
as you insert into your collection (Vec, HashMap, etc.)
Once the index has been populated, you can use the autocomplete
and search
functions.
The autocomplete
function will provide several autocompletion options for the
last partial keyword in the supplied string. The results are returned in
lexographic order. Example usage:
```rust
let autocompleteoptions: Vec
asserteq!(autocompleteoptions, vec!["big bird", "big birthday"]); ```
With a bit of imagination you could create a typeahead microservice for your web
application using a crate like actix-web
or rocket
.
The search
function will return keys as the search results. Each resulting
key can then be used to retrieve the corresponding record from its collection.
Search keywords must be an exact match. The logical conjuction for multiple
keywords is or
. The results are returned in order of descending relevance.
Example usage:
```rust
let resultingkeys: Vec
asserteq!(resultingkeys, Some(vec![1])); ```
Since search only supports exact keyword matches and does not fuzzy matching,
consider implementing autocomplete
for your search.
The keyword_autocomplete
and keyword_search
methods work on strings that are
expected to contain only a single keyword (as opposed to strings containing
multiple keywords.) For small collections, these methods might be a
lighter-weight alternative to their big brothers.
The keyword_autocomplete
function will return several keywords that begin with
the partial keyword provided by the caller. Example usage:
```rust
let autocompleteoptions: Vec
asserteq!(autocompleteoptions, vec!["assassin", "assistance"]); ```
The keyword_search
function will return keys for indexed records that match
the keyword provided by the caller. Each resulting key can then be used to
retrieve the corresponding record from its collection. The search keyword must
be an exact match. The results are returned in undefined order. Example usage:
```rust
let resultingkeys: Vec
asserteq!(resultingkeys, Some(vec![&1])); ```
Since search only supports exact keyword matches and does not fuzzy matching,
consider implementing autocomplete
for your search.