我正在尝试在我的应用中实施搜索。有两个核心数据实体,“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)并尝试进一步优化,搜索也非常缓慢。我怎样才能让它更快?
修改
基于雅各布的初步建议,这是我的新方法:
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]];
}
答案 0 :(得分:6)
这里有很多东西可以扼杀CPU周期和内存:
一,你正在对NSFetchedResultsController
提取的结果进行可变复制。为什么呢?
其中两个,你在上面的结果上使用for..in
构造,并在每个上调用-[NSPredicate evaluateWithObject:]
。您可以修改谓词搜索字符串以使用-[NSArray filteredArrayUsingPredicate:]
代替,这很可能比您的方法更快。
三,你的predicate
变量存在一个相当微妙的问题 - 你总是将它重新分配给开头时自动释放空的其他东西。将其设为默认值nil
。
四,正如你所提到的,你的谓词字符串效率很低。 我认为你需要做一些叫做索引之类的东西。
有关使用核心数据进行全文搜索的更多信息:
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?