Eine schnelle und minimale eingebettete Volltext-Indexierungsbibliothek, geschrieben in Objective-C, die auf objektiven LevelDB erstellt wurde.
Der mit Abstand einfachste Weg, diese Bibliothek in Ihr Projekt zu integrieren, ist die Verwendung von Cocoapods.
Lassen Sie Cocoapods installieren, wenn Sie es noch nicht tun
Fügen Sie in Ihrer Podfile die Linie hinzu
pod 'MHTextSearch'
pod install ausführen
Fügen Sie Ihrem Projekt das libc++.dylib hinzu.
MHTextIndex *index = [MHTextIndex textIndexInLibraryWithName: @" my.awesome.index " ]; Sie können eine MHTextIndex -Instanz erkennen, um Ihre Objekte (jedes Objekt) zu indizieren (jedes Objekt)
[ index indexObject: anyObjectYouWant];
[ index updateIndexForObject: anotherPreviousIndexedObject];
[ index removeIndexForObject: anotherPreviousIndexedObject]; Damit dies funktioniert, müssen Sie uns jedoch sagen, welchen Kennung als NSData * verwendet werden kann, um auf dieses Objekt einzigartig zu verweisen.
[ index setIdentifier: ^ NSData *(MyCustomObject *object){
return object. indexID ; // a NSData instance
}];Sie müssen uns auch Details zu den Objekten geben, z.
[ 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;
}];Wenn Sie in der Lage sein möchten, bei der Erzielung von Suchergebnissen eine einfache Bezugnahme auf Ihr ursprüngliches Objekt zu erhalten, können Sie uns sagen, wie das für Sie zu tun ist
[ index setObjectGetter: ^MyCustomObject *( NSData *identifier){
return [MyCustomObject customObjectFromIdentifier: identifier];
}];Und das war's! Das ist alles, was Sie brauchen, um einen Volltext-Index in Gang zu bringen. MhTextSearch kümmert sich um die Aufteilung von Text in Wörter, die Diakritik und Kapitalisierung in Bezug auf das Gebietsschema, wie Sie es erwarten würden, auf, (nun, die Foundation macht den größten Teil des Jobs hier).
Sie können dann anfangen zu suchen:
[ 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).
*/
}]; Sie können auch die gesamte Reihe von MHSearchResultItem -Instanzen gleichzeitig abrufen
NSArray *resultSet = [ index searchResultForKeyword: @" duck "
options: NSEnumerationReverse];Wenn das Geben von Blöcken zum Angeben von Verhalten nicht Ihr Ding ist, können Sie auch die folgenden Methoden überschreiben:
-[MHTextIndex getIdentifierForObject:] , was standardmäßig den identifier verwendet-[MHTextIndex getIndexInfoForObject:andIdentifier:] Was standardmäßig den indexer -Block verwendet-[MHTextIndex compareResultItem:withItem:reversed:] , das verwendet wird, um das Suchergebnissatz zu bestellen Sie können NSManagedObject -Lebenszyklusmethoden verwenden, um Änderungen am Textindex auszulösen. Das folgende Beispiel stammte von http://www.adevelopingstory.com/blog/2013/04/adding-full-text-search-to-core-data.html und adaptiert für dieses Projekt:
- ( 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 verwendet eine NSOperationQueue unter der Haube, um die Indexierungsvorgänge zu koordinieren. Es wird als Eigenschaft namens indexingQueue entlarvt. Sie können somit seine Eigenschaft maxConcurrentOperationCount festlegen, um zu steuern, wie gleichzeitig die Indizierung sein kann. Da die zugrunde liegende Datenbankbibliothek, die E/A durchführt, thread-sicher ist, ist die Parallelität kein Problem. Dies bedeutet auch, dass Sie explizit darauf warten können, dass die Indizierungsvorgänge mit:
[ index .indexingQueue waitUntilAllOperationsAreFinished ]; Die drei Indexierungsmethoden -[MHTextIndex indexObject:] , -[MHTextIndex updateIndexForObject:] , -[MHTextIndex removeIndexForObject:] Alle Rückkehr NSOperation -Instanzen, die Sie nutzen können, wenn Sie benötigen, unter Verwendung der completionBlock -Eigenschaft oder -[NSOperation waitUntilFinished] -Methode.
Die Suche ist ebenfalls gleichzeitig, verwendet jedoch einen dispatch_queue_t (noch nicht freigelegt oder abstimmbar).
Es gibt ein paar Knöpfe, mit denen Sie spielen können, um MhTextseach besser zu Ihren Bedürfnissen zu machen.
Eine MHTextIndex -Instanz hat eine skipStopWords -Boolesche Eigenschaft, die standardmäßig wahr ist und die die Indexierung von sehr häufigen englischen Wörtern vermeidet. ( TODO : Machen Sie das mit anderen Sprachen arbeiten)
Es hat auch eine minimalTokenLength , die standardmäßig 2 entspricht. Dies legt ein Minimum für die Anzahl der Buchstaben fest, die ein Token für die Indexierung sein muss. Dies minimiert auch die Größe des Index sowie die Indexierungs- und Suchzeit erheblich. Es überspringt die indizierenden Einzelhandelswörter und den letzten Buchstaben jedes Wortes, wenn sie auf 2 gesetzt sind.
Wenn Sie Langformtexte (Dokumente anstatt beispielsweise einfache Namen) indizieren, können Sie die Boolean -Eigenschaft von discardDuplicateTokens auf MHTextIndex einschalten. Dadurch wird der Index nur das erste Vorkommen jedes indizierten Tokens für ein bestimmtes Stück Texte berücksichtigt. Wenn Sie nur in Ordnung sind, wenn Sie nur wissen , ob ein Token in einem Text erscheint, anstatt wo erscheint jedes Ereignis, können Sie um den Faktor von 3 bis 5 eine Geschwindigkeitssteigerung in der Indizierungszeit gewinnen.
Die folgenden Grafiken zeigen die Indexierung und Suchzeit (in Sekunden) als Funktion der indexierten Textgröße von 500 kb bis etwa 10 MB. Die Benchmarks wurden auf einem iPhone 5 ausgeführt.
Wenn Sie die Tests ausführen möchten, benötigen Sie Xcode 5, da die Testsuite die neue XCTest verwendet.
Klonen Sie dieses Repository und einmal drin.
$ cd MHTextSearch iOS Tests
$ pod install
$ cd .. && open * .xcworkspaceDerzeit wurden alle Tests eingerichtet, um mit der iOS -Testsuite zu arbeiten.
Unter der MIT -Lizenz verteilt