Простой поиск в памяти коллекций ( Vec , HashMap , BTreeMap и т. Д.) И магазины ключей. Особенности автозаполнения и нечеткое сопоставление.
Есть много невероятных поисковых систем, доступных для ржавчины. Многие, кажется, требуют составления отдельного двоичного сервера. Я хотел что-то простое и легкое-простой в использовании ящик, который мог бы удобно искать структуры и коллекции в моем собственном бинарном. Итак, я сделал indicium .
В то время как indicium был сделан с учетом веб-приложений, это поиск в памяти, и он не масштабируется на неопределенный срок или к размеру облаков (то есть размером Facebook или Google). Даже в такой среде это по -прежнему будет удобным способом поиска больших списков (таких как валюты, языки, страны и т. Д.), Это также отлично подходит для приложений, где существует ожидаемый предел масштаба (т.е. поиск списка активов компании, список пользователей в корпоративной интранете и т. Д.)
Indicium легко может справиться с миллионами записей, не разжигая пот благодаря Btreemap's Rust. Этот ящик в основном ограничен доступной памятью. Однако, в зависимости от природы вашего набора данных, и если есть ключевые слова, которые повторяются много раз, производительность может начать ухудшаться в точке.
Настройте зависимости в файле Cargo.toml вашего проекта:
[ dependencies ]
indicium = " 0.6 "Примечания к выпуску доступны на GitHub.
Полный журнал изменений доступен на GitHub.
Для нашего примера быстрого начала мы будем искать внутри следующей struct :
struct MyStruct {
title : String ,
year : u16 ,
body : String ,
} Для начала мы должны сделать нашу запись индексацией. Мы сделаем это, внедрив Indexable черту для нашей struct . Идея состоит в том, чтобы вернуть String для каждого поля, которое мы хотели бы быть проиндексированным. Пример:
use indicium :: simple :: Indexable ;
impl Indexable for MyStruct {
fn strings ( & self ) -> Vec < String > {
vec ! [
self .title.clone ( ) ,
self .year.to_string ( ) ,
self .body.clone ( ) ,
]
}
} Не забывайте, что вы можете сделать цифры, числовые идентификаторы, перечисления и другие типы в вашей struct (или других сложных типах), индексируемые, преобразуя их в String и включив их в возвращаемый Vec<String> .
Чтобы индексировать существующую коллекцию, мы можем перевернуть за коллекцию. Для каждой записи мы вставим его в индекс поиска. Это должно выглядеть примерно так, как эти два примера:
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 )
) ; До тех пор, пока для вашего типа значения была реализована Indexable черта, приведенные выше примеры будут индексировать ранее заполненную Vec или HashMap . Тем не менее, предпочтительным методом для больших коллекций является insert в SearchIndex , когда вы вставляете в свою коллекцию (VEC, Hashmap и т. Д.)
Рекомендуется завершить вашу целевую коллекцию (ваш Vec , HashMap и т. Д.) И этот SearchIndex вместе в новом типе struct . Затем реализуйте методы insert , replace , remove и т. Д. Для этого нового типа struct , которые будут обновлять индекс сбора и поиска. Это гарантирует, что как ваша коллекция, так и индекс всегда синхронизированы.
Как только индекс заполнен, вы можете использовать методы search и autocomplete .
Метод search вернет ключи в качестве результатов поиска. Каждый полученный ключ можно использовать для получения полной записи из его коллекции.
Основное использование:
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 ] ) ; Поиск поддерживает только точные ключевые совпадения. Для Live поисков нечеткое сопоставление применяется только к последнему ключевому слову. Подумайте о предоставлении функции autocomplete вашим пользователям в качестве эргономичной альтернативы нечеткому сопоставлению.
Метод autocomplete предоставит несколько параметров автозаполнения для последнего ключевого слова в поставленной строке.
Основное использование:
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" ]
) ;Этот ящик пассивно поддерживается. Этот ящик делает то, что ожидается, и делает это довольно хорошо, на мой взгляд. Частые обновления не ожидаются.