Objective-cで記述された高速で最小限の埋め込みフルテキストインデックスライブラリは、Objective-LeveldBの上に構築されています。
このライブラリをプロジェクトに統合する最も簡単な方法は、ココアポッドを使用することです。
まだ存在しない場合は、cocoapodをインストールしてください
Podfileに、ラインを追加します
pod 'MHTextSearch'
pod installを実行します
libc++.dylibフレームワークをプロジェクトに追加します。
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 Lifecycleメソッドを使用して、テキストインデックスへの変更をトリガーできます。次の例は、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プロパティを設定して、インデックスがどれほど同時にできるかを制御できます。 I/Oを実行する基礎となるデータベースライブラリはスレッドセーフであるため、並行性は問題ではありません。これは、インデックス操作が使用を終了することを明示的に待つことができることを意味します。
[ index .indexingQueue waitUntilAllOperationsAreFinished ]; 3つのインデックス作成方法-[MHTextIndex indexObject:] 、 -[MHTextIndex updateIndexForObject:] 、 -[MHTextIndex removeIndexForObject:]すべてのreturn NSOperationインスタンス、必要に応じて、 completionBlockプロパティまたは-[NSOperation waitUntilFinished]方法を使用します。
検索も同時ですが、 dispatch_queue_t (まだ露出または調整可能ではありません)を使用します。
MHTextSeachをよりよく適合させるために、一緒に遊ぶことができるいくつかのノブがあります。
MHTextIndexインスタンスには、デフォルトで真であり、非常に一般的な英語の単語のインデックス作成を回避するskipStopWordsブールのプロパティがあります。 ( TODO :他の言語でそれを機能させる)
また、デフォルトでは2に等しいminimalTokenLengthもあります。これにより、トークンがインデックス化されるために必要な文字の数に対して最小限を設定します。これにより、インデックスのサイズとインデックス作成時間と検索時間も大幅に最小限に抑えられます。 2に設定した場合、シングルレターの単語とすべての単語の最後の文字のインデックス作成をスキップします。
長いフォームのテキスト(たとえば、単純な名前ではなくドキュメント)をインデックス作成する場合、 MHTextIndexのdiscardDuplicateTokens Booleanプロパティをオンにすることができます。これにより、インデックスは、特定のテキストのすべてのインデックス付きトークンの最初の発生のみを考慮します。すべての発生がどこに表示されるかではなく、テキストにトークンが表示されるかどうかを知っているだけで大丈夫な場合は、インデックス時間のスピードバンプを3〜5倍にすることができます。
次のグラフは、500 kbから約10 Mbの範囲のテキストインデックスのサイズの関数として、インデックスと検索時間(秒単位)を示しています。ベンチマークはiPhone 5で実行されました。
テストを実行する場合は、テストスイートが新しいXctestを使用するため、Xcode 5が必要になります。
このリポジトリをクローンし、その中に一度、
$ cd MHTextSearch iOS Tests
$ pod install
$ cd .. && open * .xcworkspace現在、すべてのテストは、iOSテストスイートで動作するように設定されています。
MITライセンスの下で配布されます