Uma biblioteca de indexação de texto completo incorporado rápido e mínimo, escrito no Objective-C, construído sobre o nível de objetivo.
De longe, a maneira mais fácil de integrar esta biblioteca em seu projeto é usando Cocoapods.
Tem cocoapods instalados, se você ainda não
No seu podfile, adicione a linha
pod 'MHTextSearch'
Execute pod install
Adicione a estrutura libc++.dylib ao seu projeto.
MHTextIndex *index = [MHTextIndex textIndexInLibraryWithName: @" my.awesome.index " ]; Você pode dizer a uma instância MHTextIndex para indexar seus objetos (qualquer objeto)
[ index indexObject: anyObjectYouWant];
[ index updateIndexForObject: anotherPreviousIndexedObject];
[ index removeIndexForObject: anotherPreviousIndexedObject]; Mas, para que isso funcione, você precisa nos dizer qual identificador como NSData * pode ser usado para se referir exclusivamente a esse objeto.
[ index setIdentifier: ^ NSData *(MyCustomObject *object){
return object. indexID ; // a NSData instance
}];Você também precisa nos dar detalhes sobre os objetos, como quais são as peças de texto para indexar
[ 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;
}];Por fim, se você quiser obter uma referência fácil ao seu objeto original quando obtiver resultados de pesquisa, pode nos dizer como fazer isso por você
[ index setObjectGetter: ^MyCustomObject *( NSData *identifier){
return [MyCustomObject customObjectFromIdentifier: identifier];
}];E é isso! É tudo o que você precisa para obter um índice de texto completo. O MHTextSearch cuida da divisão de texto em palavras, considerando diacríticas e capitalização, tudo em relação ao local, como seria de esperar (bem, a fundação faz a maior parte do trabalho aqui).
Você pode começar a pesquisar:
[ 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).
*/
}]; Você também pode buscar toda a variedade de instâncias MHSearchResultItem
NSArray *resultSet = [ index searchResultForKeyword: @" duck "
options: NSEnumerationReverse];Se você gosta de fornecer blocos para especificar o comportamento, você também pode substituir os seguintes métodos:
-[MHTextIndex getIdentifierForObject:] que, por padrão, usa o bloco identifier-[MHTextIndex getIndexInfoForObject:andIdentifier:] que, por padrão, usa o bloco indexer-[MHTextIndex compareResultItem:withItem:reversed:] que é usado para ordenar o conjunto de resultados de pesquisa Você pode usar os métodos do ciclo de vida NSManagedObject para desencadear alterações no índice de texto. O exemplo a seguir foi retirado de http://www.adevelopstory.com/blog/2013/04/adding-full-text-search-to-core-data.html e adaptado para usar com este projeto:
- ( 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 usa um NSOperationQueue sob o capô para coordenar operações de indexação. É exposto como uma propriedade chamada indexingQueue . Assim, você pode definir sua propriedade maxConcurrentOperationCount para controlar como a indexação pode ser concorrente. Como a biblioteca de banco de dados subjacente que executa a E/S é segura para threads, a simultaneidade não é um problema. Isso também significa que você pode aguardar explicitamente o fim das operações de indexação usando:
[ index .indexingQueue waitUntilAllOperationsAreFinished ]; Os três métodos de indexação -[MHTextIndex indexObject:] , -[MHTextIndex updateIndexForObject:] , -[MHTextIndex removeIndexForObject:] Todos retornam instâncias NSOperation , que você pode aproveitar, se precisar, usando sua propriedade completionBlock ou -[NSOperation waitUntilFinished] o método.
A pesquisa também é simultânea, mas usa um dispatch_queue_t (ainda não exposto ou ajustável).
Existem alguns botões com os quais você pode brincar para melhorar o MHTextSeach.
Uma instância MHTextIndex possui uma propriedade booleana skipStopWords que é verdadeira por padrão e evita a indexação de palavras em inglês muito comuns. ( TODO : faça isso funcionar com outros idiomas)
Ele também possui um minimalTokenLength que é igual a 2 por padrão. Isso define um mínimo para o número de letras que um token precisa ser indexado. Isso também minimiza muito o tamanho do índice, bem como o tempo de indexação e pesquisa. Ele ignora as palavras de indexação de uma letra única e a última letra de cada palavra, quando definida como 2 .
Ao indexar textos de formulário longo (documentos em vez de, digamos, nomes simples), você pode ativar a propriedade booleana discardDuplicateTokens no MHTextIndex . Isso faz com que o índice considere apenas a primeira ocorrência de cada token indexado para uma determinada peça de textos. Se você está bem em saber apenas se um token aparece em um texto, em vez de onde todas as ocorrências aparecem, você pode obter uma lombada no tempo de indexação , por um fator de 3 a 5.
Os gráficos a seguir mostram o tempo de indexação e pesquisa (em segundos), em função do tamanho do texto indexado, variando de 500 kb a cerca de 10 MB. Os benchmarks foram executados em um iPhone 5.
Se você deseja executar os testes, precisará do Xcode 5, pois o conjunto de testes usa o novo XCTest.
Clonar este repositório e, uma vez nele,
$ cd MHTextSearch iOS Tests
$ pod install
$ cd .. && open * .xcworkspaceAtualmente, todos os testes foram configurados para trabalhar com a suíte de teste iOS.
Distribuído sob a licença do MIT