iPhone:加快搜索17,000个核心数据对象的搜索速度

时间:2010-05-03 14:44:32

标签: iphone objective-c core-data

我有一个符合UISearchDisplayDelegate并包含UISearchBar的类。此视图负责允许用户轮询当前由Core Data管理的大约17,000个对象的存储。每次用户键入一个字符时,我都会创建一个SearchOperation(子类NSOperation)的实例,该实例查询Core Data以查找可能与搜索匹配的结果。搜索控制器中的代码类似于:

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
 // Update the filtered array based on the search text and scope in a secondary thread 
 if ([searchText length] < 3) {
  [filteredList removeAllObjects]; // First clear the filtered array.
  [self setFilteredList:NULL];
  [self.tableView reloadData];
     return;
 }
    NSDictionary *searchdict = [NSDictionary dictionaryWithObjectsAndKeys:scope, @"scope", searchText, @"searchText", nil];
 [aSearchQueue cancelAllOperations];
 SearchOperation *searchOp = [[SearchOperation alloc] initWithDelegate:self dataDict:searchdict];
 [aSearchQueue addOperation:searchOp];
}

我的搜索非常直接。 SearchOperation是NSOperation的子类。我用以下代码覆盖了main方法:

- (void)main 
{ 
 if ([self isCancelled]) {
  return;
 }

 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 NSEntityDescription *entity = 
 [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext];
 NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
 [fetchRequest setEntity:entity]; 
 NSPredicate *predicate = NULL;
    predicate = [NSPredicate predicateWithFormat:@"(someattr contains[cd] %@)", searchText];
 [fetchRequest setPredicate:predicate];
 NSError *error = NULL;
 NSArray *fetchResults = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
 [fetchRequest release];

 if (self.delegate != nil)
  [self.delegate didFinishSearching:fetchResults];

 [pool drain];
}

此代码有效,但它有几个问题。

  • 这很慢。即使我在除UI线程之外的单独线程中进行搜索,查询17,000个对象显然不是最佳的。

  • 如果我不小心,可能会发生崩溃。我将我的NSOperationQueue中的最大并发搜索数设置为1以避免这种情况。

我还能做些什么来加快搜索速度?我认为将所有17,000个对象预加载到内存中可能会有风险。必须有一种更智能的方法来进行此搜索,以便更快地将结果返回给用户。

2 个答案:

答案 0 :(得分:1)

以树形式组织数据?这样你就可以轻松检查下一个字母是否有效...

编辑:更多地思考这个问题。如果您设置一个具有指针数组的树,该指针是每个支持的输入字符,您可以轻松地跳转到树中该点的数组中的正确位置,以查看树中是否存在另一个级别。它在内存使用方面会花费更多,但会非常快......

进一步编辑:如果您想节省大量内存,那么您可以轻松设置一个非常快速扫描的文件。如果考虑到树中每个级别节点都有固定数量的可能项目,那么您可以轻松地快速搜索文件中所需的位置。对于您输入的每个字符,这是O(1)。因此,您可以在O(n)中搜索用户输入的所有内容。

答案 1 :(得分:1)

您使用什么类型的持久性商店? SQLite还是Binary?

假设SQLite,您是否正在索引要搜索的列?

我猜您最初使用NSFetchedResultsController权利显示数据?如果没有,为什么不呢? NSFetchedResultsController中的缓存将帮助极大地解决此问题。

如果您使用的是NSFetchedResultsController,那么请更改搜索,以便不是每次都点击磁盘,而是点击内存中已有的数据。通过访问[myFetchController fetchedObjects]数组,您可以使用NSPredicate来过滤结果。这是第一封信。

从那里,您可以使用已经过滤的数组,并在每次按下新键时再次过滤它。这将使您在缩小搜索范围时加快搜索速度。

更新

在这种情况下,您的初始搜索会很慢。但是,一旦你从输入的第一个字符进行了初始搜索,你就可以对该数组进行过滤,而不是回到磁盘,这应该是近乎瞬时的。

您可以通过以下方式改善初始搜索:

  • 索引搜索的列
  • 如果扩展ascii是一个问题,请创建一个展平文本列以进行搜索并将其编入索引。