بحث بسيط في الذاكرة عن المجموعات ( Vec ، HashMap ، BTreeMap ، إلخ) ومتاجر القيمة الرئيسية. ميزات الإكمال التلقائي والمطابقة الغامضة.
هناك العديد من محركات البحث المذهلة المتاحة للصدأ. يبدو أن العديد منهم يتطلبون تجميع خادم منفصل ثنائي. كنت أرغب في شيء بسيط وخفيف الوزن-صندوق سهل الاستخدام يمكن أن يبحث بشكل مريح من هياكل ومجموعات في ثنائي. لذلك ، لقد صنعت indicium .
على الرغم من أن indicium تم صنعه مع وضع تطبيقات الويب في الاعتبار ، إلا أنه بحث في الذاكرة ولا يتوسع إلى أجل غير مسمى أو إلى حجم السحابة (أي فيسبوك أو حجم Google). حتى في مثل هذه البيئة ، ستظل طريقة مريحة للبحث عن قوائم كبيرة (مثل العملات واللغات والبلدان ، وما إلى ذلك) ، إنها رائعة أيضًا للتطبيقات التي يوجد فيها الحد المتوقع للمجموعة (أي البحث في قائمة من أصول الشركة ، وقائمة المستخدمين في إنترانت الشركات ، إلخ).
يمكن لـ Indistium بسهولة التعامل مع ملايين السجلات دون كسر العرق بفضل Btreemap من Rust. هذا الصندوق يقتصر بشكل أساسي على الذاكرة المتاحة. ومع ذلك ، اعتمادًا على الطبيعة ، إذا كانت هناك كلمات رئيسية تتكرر عدة مرات ، فقد يبدأ الأداء في التدهور عند نقطة ما.
تكوين التبعيات في ملف Cargo.toml لمشروعك:
[ dependencies ]
indicium = " 0.6 "ملاحظات الإصدار متوفرة على جيثب.
سجل التغيير الكامل متاح على جيثب.
للحصول على مثال على دليل البدء السريع لدينا ، سنبحث داخل 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 ( ) ,
]
}
} لا تنس أنك قد تصنع أرقامًا ، ومعرفات رقمية ، و inums ، وأنواع أخرى في 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" ]
) ;يتم الحفاظ على هذا الصندوق بشكل سلبي. هذا الصندوق يفعل ما يتوقع فعله ويفعله بشكل جيد ، في رأيي. التحديثات المتكررة غير متوقع.