Une simple recherche en mémoire de collections ( Vec , HashMap , BTreeMap , etc.) et les magasins de valeurs clés. Caractéristiques automatique et correspondance floue.
Il existe de nombreux moteurs de recherche incroyables disponibles pour la rouille. Beaucoup semblent nécessiter de compiler un binaire de serveur séparé. Je voulais quelque chose de simple et de poids léger - une caisse facile à utiliser qui pourrait commodément des structures et des collections dans mon propre binaire. J'ai donc indicium .
Bien que indicium ait été fait avec les applications Web à l'esprit, il s'agit d'une recherche en mémoire et elle ne s'allonge pas indéfiniment ou à la taille du cloud (c'est-à-dire Facebook ou Google Taille). Même dans un tel environnement, ce serait toujours un moyen pratique de rechercher de grandes listes (telles que les devises, les langues, les pays, etc.), il est également idéal pour les applications où il y a une limite d'échelle prévue (c'est-à-dire la recherche d'une liste des actifs de l'entreprise, de la liste des utilisateurs dans un intranet d'entreprise, etc.)
Indicium peut facilement gérer des millions de disques sans transpirer grâce au btreemap de Rust. Cette caisse est principalement limitée par la mémoire disponible. Cependant, selon la nature, votre ensemble de données et s'il existe des mots clés qui sont répétés plusieurs fois, les performances peuvent commencer à se dégrader en un point.
Configurez les dépendances dans le fichier Cargo.toml de votre projet:
[ dependencies ]
indicium = " 0.6 "Les notes de sortie sont disponibles sur GitHub.
Le journal de changement complet est disponible sur github.
Pour notre exemple de guide rapide , nous rechercherons à l'intérieur de la struct suivante:
struct MyStruct {
title : String ,
year : u16 ,
body : String ,
} Pour commencer, nous devons rendre notre record indexable. Nous le ferons en implémentant le trait Indexable pour notre struct . L'idée est de renvoyer une String pour chaque champ que nous aimerions être indexé. Exemple:
use indicium :: simple :: Indexable ;
impl Indexable for MyStruct {
fn strings ( & self ) -> Vec < String > {
vec ! [
self .title.clone ( ) ,
self .year.to_string ( ) ,
self .body.clone ( ) ,
]
}
} N'oubliez pas que vous pouvez faire des nombres, des identifiants numériques, des énumérations et d'autres types de votre struct (ou d'autres types complexes) indexable en les convertissant en une String et en les incluant dans le Vec<String> renvoyé.
Pour indexer une collection existante, nous pouvons parcourir la collection. Pour chaque enregistrement, nous l'insérerons dans l'index de recherche. Cela devrait ressembler à ces deux exemples:
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 )
) ; 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 )
) ; Tant que le trait Indexable a été implémenté pour votre type de valeur, les exemples ci-dessus indexeront un Vec ou HashMap précédemment peuplé. Cependant, la méthode préférée pour les grandes collections est d' insert dans le SearchIndex lorsque vous insérez dans votre collection (VEC, hashmap, etc.)
Il est recommandé d'envelopper votre collection cible (votre Vec , HashMap , etc.) et cette SearchIndex dans un nouveau type struct . Ensuite, implémentez les méthodes insert , replace , de remove , etc. pour ce nouveau type struct qui mettra à jour à la fois l'index de la collection et de la recherche. Cela garantira que votre collection et votre index sont toujours synchronisés.
Une fois l'index rempli, vous pouvez utiliser les méthodes search et autocomplete .
La méthode search renvoie les touches à mesure que les résultats de recherche. Chaque clé résultante peut ensuite être utilisée pour récupérer l'enregistrement complet de sa collection.
Utilisation de base:
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 ] ) ; La recherche prend uniquement en charge les correspondances de mots clés exacts. Pour les recherches Live , la correspondance floue n'est appliquée qu'au dernier mot-clé. Envisagez de fournir la fonctionnalité autocomplete à vos utilisateurs comme une alternative ergonomique à la correspondance floue.
La méthode autocomplete fournira plusieurs options de complétion automatique pour le dernier mot-clé dans la chaîne fournie.
Utilisation de base:
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" ]
) ;Cette caisse est maintenue passivement. Cette caisse fait ce qu'elle devrait faire et le fait assez bien, à mon avis. Les mises à jour fréquentes ne sont pas attendues.