如何优化基于Core Data的搜索?

Mos*_*she 5 iphone optimization core-data objective-c ios

我正在尝试在我的应用中实现搜索.有两个核心数据实体,"Tag"和"DvarTorah".标签只有一个字符串."DvarTorah"具有标题,文本内容和一些其他属性.我正试图找出快速搜索它们的最佳方法.该应用程序附带了大约1200个DvarTorah实体,甚至更多的标签.现在,当我的搜索视图控制器调用viewDidLoad时,我加载了一个NSFetchedResultsController.然后,当用户键入搜索框或更改范围时,我调用一个方法,该方法同时接收范围栏值和搜索词,并过滤我的对象数组.这是看起来如何:

- (void) filterArrayWithSearchTerm:(NSString *)searchString andScopeIndex:(NSInteger)scopeIndex{

    if ([searchString isEqualToString:@""]) {
        return;
    }    

    NSMutableArray *unfilteredResults = [[[[self.fetchedResultsController sections] objectAtIndex:0] objects] mutableCopy];

    if (self.filteredArray == nil){
        self.filteredArray = [[[NSMutableArray alloc ] init] autorelease];
    }

    [filteredArray removeAllObjects];

    NSPredicate *predicate = [[[NSPredicate alloc] init] autorelease];

    if (scopeIndex == 0) {
        predicate = [NSPredicate predicateWithFormat:@"dvarTorahTitle CONTAINS[cd] %@", searchString];
    }else if (scopeIndex == 1) {
        predicate = [NSPredicate predicateWithFormat:@"searchableContent CONTAINS[cd] %@", [searchString canonicalString]];            
    }else if (scopeIndex == 2){
        predicate = [NSPredicate predicateWithFormat:@"ANY tags.tagText CONTAINS[cd] %@", searchString];
    }else{
        predicate = [NSPredicate predicateWithFormat:@"(ANY tags.tagText CONTAINS[cd] %@) OR (dvarTorahTitle CONTAINS[cd] %@) OR (searchableContent CONTAINS[cd] %@)", searchString,searchString,searchString];
    }

    for (DvarTorah *dvarTorah in unfilteredResults) {
        if ([predicate evaluateWithObject:dvarTorah]) {
            [self.filteredArray addObject:dvarTorah];
        }
    }

    [unfilteredResults release];
}
Run Code Online (Sandbox Code Playgroud)

问题是我的搜索方法非常慢.我知道CONTAINS可能是罪魁祸首,但即使存储了内容的规范版本(作为searchableContent)并尝试进一步优化,搜索也非常缓慢.我怎样才能让它更快?

编辑:

基于雅各布的初步建议,这是我的新方法:

    if ([searchString isEqualToString:@""]) {
    return;
}

if (self.filteredArray == nil) {
    self.filteredArray = [[[NSMutableArray alloc ] init] autorelease];
}

[filteredArray removeAllObjects];

NSPredicate *predicate = nil;

if (scopeIndex == 0) {
    predicate = [NSPredicate predicateWithFormat:@"dvarTorahTitle CONTAINS[cd] %@", searchString];
}else if (scopeIndex == 1) {
    predicate = [NSPredicate predicateWithFormat:@"searchableContent CONTAINS[cd] %@", [searchString canonicalString]];            
}else if (scopeIndex == 2){
    predicate = [NSPredicate predicateWithFormat:@"ANY tags.tagText CONTAINS[cd] %@", searchString];
}else{
    predicate = [NSPredicate predicateWithFormat:@"(ANY tags.tagText CONTAINS[cd] %@) OR (dvarTorahTitle CONTAINS[cd] %@) OR (searchableContent CONTAINS[cd] %@)", searchString,searchString,searchString];
}

[self.filteredArray addObjectsFromArray:[[[[[self.fetchedResultsController sections] objectAtIndex:0] objects] mutableCopy] filteredArrayUsingPredicate:predicate]];

}
Run Code Online (Sandbox Code Playgroud)

EDIT2:

不再复制数组,仍然很慢:

- (void) filterArrayWithSearchTerm:(NSString *)searchString andScopeIndex:(NSInteger)scopeIndex{

    if ([searchString isEqualToString:@""]) {
        return;
    }

    if (self.filteredArray == nil) {
        self.filteredArray = [[[NSMutableArray alloc ] init] autorelease];
    }

    [filteredArray removeAllObjects];

    NSPredicate *predicate = nil;

    if (scopeIndex == 0) {
        predicate = [NSPredicate predicateWithFormat:@"dvarTorahTitle CONTAINS[cd] %@", searchString];
    }else if (scopeIndex == 1) {
        predicate = [NSPredicate predicateWithFormat:@"searchableContent CONTAINS[cd] %@", [searchString canonicalString]];            
    }else if (scopeIndex == 2){
        predicate = [NSPredicate predicateWithFormat:@"ANY tags.tagText CONTAINS[cd] %@", searchString];
    }else{
        predicate = [NSPredicate predicateWithFormat:@"(ANY tags.tagText CONTAINS[cd] %@) OR (dvarTorahTitle CONTAINS[cd] %@) OR (searchableContent CONTAINS[cd] %@)", searchString,searchString,searchString];
    }

    [self.filteredArray addObjectsFromArray:[[[[self.fetchedResultsController sections] objectAtIndex:0] objects] filteredArrayUsingPredicate:predicate]];
}
Run Code Online (Sandbox Code Playgroud)

Jac*_*kin 6

这里有很多东西可以扼杀CPU周期和内存:

一,你正在制作一个可变的副本,从中获取结果NSFetchedResultsController.为什么?

二,你正在使用for..in上面结果的构造并调用-[NSPredicate evaluateWithObject:]每个.您可以修改谓词搜索字符串以进行操作-[NSArray filteredArrayUsingPredicate:],这很可能比您的方法更快.

三,你的predicate变量有一个相当微妙的问题- 你总是将它重新分配给开头的自动释放空的其他东西.给它默认值nil.

四,正如你所提到的,你的谓词字符串效率很低.我认为你需要做一些称为索引或类似的东西.

有关使用Core Data进行全文搜索的更多信息:

http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/CoreData/Articles/cdPerformance.html

http://cocoawithlove.com/2008/03/testing-core-data-with-very-big.html

http://cocoawithlove.com/2009/11/performance-tests-replacing-core-data.html

http://www.mlsite.net/blog/?page_id=1194

SQLite FTS3仍然是推出全文搜索的最佳方式吗?

sqlite索引性能建议

Apple的核心数据框架中的全文搜索