Быстрая и минимальная встроенная полнотекстовая библиотека индексации, написанная в Objective-C, построенная на вершине объективного уровня.
Безусловно, самый простой способ интегрировать эту библиотеку в ваш проект - использование кокопод.
Установить кокопод, если вы еще этого не сделаете
В вашем Podfile добавьте линию
pod 'MHTextSearch'
Запустите pod install
Добавьте в свой проект libc++.dylib Framework.
MHTextIndex *index = [MHTextIndex textIndexInLibraryWithName: @" my.awesome.index " ]; Вы можете сказать экземпляр MHTextIndex для индексации ваших объектов (любой объект)
[ index indexObject: anyObjectYouWant];
[ index updateIndexForObject: anotherPreviousIndexedObject];
[ index removeIndexForObject: anotherPreviousIndexedObject]; Но чтобы это работало, вам нужно сказать нам, какой идентификатор как NSData * может быть использован для однозначного обращения к этому объекту.
[ index setIdentifier: ^ NSData *(MyCustomObject *object){
return object. indexID ; // a NSData instance
}];Вам также необходимо дать нам подробную информацию об объектах, например, какие части текста в индексе
[ index setIndexer: ^MHIndexedObject *(MyCustomObject *object, NSData *identifier){
MHIndexedObject *indx = [MHIndexedObject new ];
indx. strings = @[ object.title, object.description ]; // Indexed strings
indx. weight = object. awesomenessLevel ; // Weight given to this object, when sorting results
indx. context = @{ @" title " : object. title }; // A NSDictionary that will be given alongside search results
return indx;
}];Наконец, если вы хотите иметь возможность получить легкую ссылку на ваш исходный объект, когда вы получаете результаты поиска, вы можете сказать нам, как это сделать для вас
[ index setObjectGetter: ^MyCustomObject *( NSData *identifier){
return [MyCustomObject customObjectFromIdentifier: identifier];
}];И это все! Это все, что вам нужно, чтобы получить полнотекстовый индекс. MhtextSearch позаботится о том, чтобы разделить текст на слова, учебность по диаклитике и капитализации, все в отношении локали, как и следовало ожидать (ну, фонд делает большую часть работы здесь).
Затем вы можете начать поиск:
[ index enumerateObjectsForKeyword: @" duck " options: 0 withBlock: ^(MHSearchResultItem *item,
NSUInteger rank,
NSUInteger count,
BOOL *stop){
item. weight ; // As provided by you earlier
item. rank ; // The effective rank in the search result
item. object ; // The first time it is used, it will use the block
// you provided earlier to get the object
item. context ; // The dictionary you provided in the "indexer" block
item. identifier ; // The object identifier you provided in the "identifier" block
NSIndexPath *token = item. resultTokens [ 0 ];
/* This is an NSArray of NSIndexPath instances, each containing 3 indices:
* - mh_string : the string in which the token occured
* (here, 0 for the object's title)
* - mh_word : the position in the string where the word containing
* the token occured
* - mh_token : the position in the word where the token occured
*/
NSRange tokenRange = [item rangeOfToken: token];
/* This gives the exact range of the matched token in the string where it was found.
*
* So, according to the example setup I've been giving from the start,
* if token.mh_string == 0, that means the token was found in the object's "title",
* and [item.object.title substringWithRange:tokenRange] would yield "duck" (minus
* capitalization and diacritics).
*/
}]; Вы также можете получить весь массив экземпляров MHSearchResultItem одновременно, используя
NSArray *resultSet = [ index searchResultForKeyword: @" duck "
options: NSEnumerationReverse];Если предоставление блоков для определения поведения не является вашей вещью, вы также можете переопределить следующие методы:
-[MHTextIndex getIdentifierForObject:] , который по умолчанию использует блок identifier-[MHTextIndex getIndexInfoForObject:andIdentifier:] , который, по умолчанию, использует блок indexer-[MHTextIndex compareResultItem:withItem:reversed:] , который используется для заказа набора результатов поиска Вы можете использовать методы жизненного цикла NSManagedObject для запуска изменения текстового индекса. Следующий пример был взят с http://www.adevelopingstory.com/blog/2013/04/adding-full-text-search-to-core-data.html и адаптировано для использования с этим проектом:
- ( void )prepareForDeletion
{
[ super prepareForDeletion ];
if (self. indexID . length ) {
[textindex deleteIndexForObject: self .indexID];
}
}
+ ( NSData *)createIndexID {
NSUUID *uuid = [ NSUUID UUID ];
uuid_t uuidBytes;
[uuid getUUIDBytes: uuidBytes];
return [ NSData dataWithBytes: uuidBytes length: 16 ];
}
- ( void )willSave
{
[ super willSave ];
if (self. indexID . length ) {
[textindex updateIndexForObject: self .indexID];
} else {
self. indexID = [[ self class ] createIndexID ];
[textindex indexObject: self .indexID];
}
} MHTextIndex использует NSOperationQueue под капюшоном для координации операций индексации. Он выставлен как свойство с именем indexingQueue . Таким образом, вы можете установить его свойство maxConcurrentOperationCount , чтобы контролировать, насколько одновременно может быть индексация. Поскольку базовая библиотека баз данных, выполняющая ввод-вывод, безопасен для потока, параллелизм не является проблемой. Это также означает, что вы можете явно подождать, пока операции индексации завершат использование:
[ index .indexingQueue waitUntilAllOperationsAreFinished ]; Три метода индексации -[MHTextIndex indexObject:] , -[MHTextIndex updateIndexForObject:] , -[MHTextIndex removeIndexForObject:] Все экземпляры возврата NSOperation , которые вы можете использовать, если вам необходимо, используя его свойство completionBlock или -[NSOperation waitUntilFinished] .
Поиск также является одновременным, но он использует dispatch_queue_t (еще не открытый или настраиваемый).
Есть несколько ручек, с которыми вы можете сыграть, чтобы сделать MHTextSeach лучше соответствовать вашим потребностям.
Экземпляр MHTextIndex имеет логическое свойство skipStopWords , которое по умолчанию истинности и избегает индексации очень распространенных английских слов. ( Тодо : Сделайте это работать с другими языками)
Он также имеет minimalTokenLength , которая равна 2 по умолчанию. Это устанавливает минимум для количества букв, которые должны быть в его токене, чтобы он был проиндексирован. Это также значительно сводит к минимуму размер индекса, а также индексацию и время поиска. Он пропускает индексацию однобуквенных слов и последнюю букву каждого слова, когда установлено на 2 .
При индексации текстов длинных форм (документы, а не, скажем, простые имена), вы можете включить логическое свойство discardDuplicateTokens на MHTextIndex . Это заставляет индекс рассматривать только первое событие каждого индексированного токена для данного фрагмента текстов. Если вы в порядке, только знаете, появляется ли токен в тексте, а не с тем, где появляется все происшествия, вы можете получить скорость скорости во время индексации , в течение 3-5.
Следующие графики показывают время индексации и поиска (в секундах) в зависимости от размера индексированного текста, в диапазоне от 500 т до 10 МБ. Цитрицы были запускаются на iPhone 5.
Если вы хотите запустить тесты, вам понадобится Xcode 5, так как в тестовом наборе используется новый xctest.
Клонировать это хранилище и, однажды в нем,
$ cd MHTextSearch iOS Tests
$ pod install
$ cd .. && open * .xcworkspaceВ настоящее время все тесты были настроены для работы с набором тестов iOS.
Распределено по лицензии MIT