【问题标题】:How can I optimize this Core Data based search?如何优化这个基于核心数据的搜索?
【发布时间】:2011-12-11 14:38:32
【问题描述】:

我正在尝试在我的应用中实现搜索。有两个核心数据实体,“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];
}

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

编辑:

根据 Jacob 的初步建议,这是我的新方法:

    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]];

}

编辑2:

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

- (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]];
}

【问题讨论】:

  • 四个版本都一样慢吗?您要过滤的结果集有多大?你能不使用包含以外的东西吗?
  • @DavidRönnqvist - 结果集大约有 1200 个对象。也许我完全误解了 UISearchResultsController ...就相对缓慢而言,我是通过眼睛进行分析,而不是使用工具,所以我不确定。对我来说似乎差不多。

标签: iphone objective-c ios optimization core-data


【解决方案1】:

这里有很多东西会占用 CPU 周期和内存:

第一,您正在制作从NSFetchedResultsController 获取的结果的可变副本。为什么?

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

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

四,正如您所提到的,您的谓词字符串效率很低。 我认为您需要做一些称为 indexing 或类似的事情。

有关使用 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

Is SQLite FTS3 still the best way to go for rolling out your full text search?

sqlite Indexing Performance Advice

Full Text Searching in Apple's Core Data Framework

【讨论】:

  • 我可以在 NSFetchedResultsController 上调用 filteredArrayUsingPredicate 吗?如果没有,我可以将它用作类方法吗> 如果没有,我需要额外的数组。查看我更新的代码。是的,CONTAINS 是我最大的问题。
猜你喜欢
  • 2011-10-05
  • 2012-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-22
相关资源
最近更新 更多