Una simple búsqueda en memoria de colecciones ( Vec , HashMap , BTreeMap , etc.) y tiendas de valor clave. Cuenta con autocompleto y coincidencia difusa.
Hay muchos motores de búsqueda increíbles disponibles para Rust. Muchos parecen requerir compilar un servidor binario separado. Quería algo simple y liviano, una caja fácil de usar que pudiera buscar convenientemente estructuras y colecciones dentro de mi propio binario. Entonces, hice indicium .
Si bien indicium se hizo teniendo en cuenta las aplicaciones web, es una búsqueda en memoria y no se escala indefinidamente ni al tamaño de la nube (es decir, el tamaño de Facebook o Google). Incluso en este entorno, aún sería una forma conveniente de buscar listas grandes (como monedas, idiomas, países, etc.), también es excelente para aplicaciones donde hay un límite de escala anticipado (es decir, buscar en una lista de activos de la compañía, lista de usuarios en una intranet corporativa, etc.)
Indicium fácilmente puede manejar millones de registros sin sudar gracias a Breementap de Rust. Esta caja está limitada principalmente por la memoria disponible. Sin embargo, dependiendo de la naturaleza su conjunto de datos y si hay palabras clave que se repiten muchas veces, el rendimiento puede comenzar a degradarse en un punto.
Configure las dependencias en el archivo Cargo.toml de su proyecto.
[ dependencies ]
indicium = " 0.6 "Las notas de lanzamiento están disponibles en GitHub.
El registro de cambio completo está disponible en GitHub.
Para nuestro ejemplo de guía de inicio rápido , buscaremos dentro de la siguiente struct :
struct MyStruct {
title : String ,
year : u16 ,
body : String ,
} Para comenzar, debemos hacer que nuestro registro sea indexable. Lo haremos implementando el rasgo Indexable para nuestra struct . La idea es devolver una String para cada campo que nos gustaría ser indexado. Ejemplo:
use indicium :: simple :: Indexable ;
impl Indexable for MyStruct {
fn strings ( & self ) -> Vec < String > {
vec ! [
self .title.clone ( ) ,
self .year.to_string ( ) ,
self .body.clone ( ) ,
]
}
} No olvide que puede hacer números, identificadores numéricos, enumines y otros tipos en su struct (u otros tipos complejos) indexables convirtiéndolos en una String e incluyendo los Vec<String> devuelto.
Para indexar una colección existente, podemos iterar sobre la colección. Para cada registro, lo insertaremos en el índice de búsqueda. Esto debería parecerse a estos dos ejemplos:
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 )
) ; Mientras se implementara el rasgo Indexable para su tipo de valor, los ejemplos anteriores indexarán un Vec o HashMap previamente poblado. Sin embargo, el método preferido para grandes colecciones es insert en el SearchIndex a medida que inserta en su colección (VEC, Hashmap, etc.)
Se recomienda envolver su colección de objetivos (su Vec , HashMap , etc.) y este SearchIndex juntos en un nuevo tipo struct . Luego, implementa los métodos insert , replace , remove , etc. para este nuevo tipo struct que actualizará tanto el índice de colección como de búsqueda. Esto asegurará que tanto su colección como su índice estén siempre sincronizados.
Una vez que el índice se ha poblado, puede usar los métodos search y autocomplete .
El método search devolverá las claves como resultados de búsqueda. Cada clave resultante se puede usar para recuperar el registro completo de su colección.
Uso básico:
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 búsqueda solo admite coincidencias de palabras clave exactas. Para las búsquedas Live , la coincidencia difusa solo se aplica a la última palabra clave. Considere proporcionar la función autocomplete a sus usuarios como una alternativa ergonómica a la coincidencia difusa.
El método autocomplete proporcionará varias opciones de autocompleto para la última palabra clave en la cadena suministrada.
Uso básico:
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" ]
) ;Esta caja se mantiene pasivamente. Esta caja hace lo que se espera que haga y lo hace bastante bien, en mi opinión. No se esperan actualizaciones frecuentes.