如何在iOS应用中更快地搜索本地数据?

时间:2012-12-03 20:01:39

标签: ios ipad uitableview

我有一个预先填充的Coredata文件,我想在iOS应用中搜索。该文件已经索引了这样的词〜(70,000行)~10 MB文件。

ad
adam
arm
apple
..
..
zen
zener

我已经从文件中构建了Coredata并且我查询了SQLLite例如:给我所有以“a”开头的单词。在模拟器上搜索需要大约300毫秒,但在iPad设备上大约需要2秒或更长时间?我怎样才能让它更快?其他搜索引擎类型的应用程序如何在设备上执行此操作?

//////////////////////////////////////////////////////////////////////
//This will get list of words begining with letters from search word
//////////////////////////////////////////////////////////////////////
-(void) FetchWords
{
NSString *entityName=@"KeyWord";
NSString *sortKey = @"word";
NSArray *fetchColumns = [[NSArray alloc] initWithObjects:@"word", nil];

//init fetch request
NSFetchRequest *req = [[NSFetchRequest alloc] init];

NSString *query = self.searchBar.text;

//
//split search phrase into words - searches words with any order and not case senitive - remove last space if any
//
NSMutableArray *words = [[query componentsSeparatedByString:@" "] mutableCopy];
if([words[words.count-1] isEqualToString:@""])
    [words removeObjectAtIndex:[words count]-1];

if(query.length)
{

    NSMutableArray *subpredicates = [NSMutableArray array];

    if(words.count >1)
    {
       [self GetMatchingCategoryCodes];
      //  NSLog(@"%@",categories);


        for (NSString *code in categories)
        {
            //intersection between last word and previous categories already filtered for previous words in search

           NSPredicate *pred = [NSPredicate predicateWithFormat:@"word BEGINSWITH[cd] %@ AND code BEGINSWITH [cd] %@",words[words.count-1],code]; 
           [subpredicates addObject:pred];
        }

      req.predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];

    }
    else
    {
       for(NSString *token in words)
       {
           NSPredicate *pred = [NSPredicate predicateWithFormat:@"word BEGINSWITH[cd] %@",token];
          [subpredicates addObject:pred]; 
       }
       req.predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];

    }
}


//setup request
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
[req setEntity:entity];
[req setFetchBatchSize:100];

//sort descriptors
NSSortDescriptor *desc = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:YES];
NSArray *descriptors = [NSArray arrayWithObject:desc];
[req setSortDescriptors:descriptors];

//for unique values - ignore repeatition
req.propertiesToFetch = fetchColumns;
req.returnsDistinctResults = YES;
req.resultType = NSDictionaryResultType;


//execute request
NSError *error;
Codes = [context executeFetchRequest:req error:&error];

//  NSLog(@"Fetched=%d",Codes.count);

}

3 个答案:

答案 0 :(得分:0)

您可以尝试延迟加载并将输出限制为50或更少的项目,因为它们无论如何都不会在屏幕上显示。当用户在结果列表中滚动时,您可以根据需要获取更多内容。

答案 1 :(得分:0)

如果在表视图中显示这些单词,您当然应该考虑使用NSFetchedResultsController并启用缓存。

答案 2 :(得分:0)

有多种优化方法。

例如,使用CONTAINS可以减慢搜索速度。 Apple建议对搜索词使用单独的实体 - 称为searchWords(或其他),并在该商店中搜索您要搜索的所有单词,小写并删除重音。这些单独的实体具有将它们链接回原始对象的关系。确保单词字段已编入索引。

此外,只有输入搜索字段的第一个字母才能到达磁盘。在第一个字母之后,你应该只是改进已经在内存中的搜索结果。

您应该使用已有的谓词过滤内存中的数组(来自第一个字母搜索),并避免执行获取请求,因为它是不必要的。

此外,如果要搜索已经在内存中的数据(例如生活在NSFetchedResultsController中),那么整个搜索应该只搜索内存中的对象。走向磁盘是不必要的,非常浪费。如果不使用ResultsController,您可以将数据自己缓存在一个数组中,只在首次点击后执行内存搜索。这也可以加快你的要求。

因此,使用批量大小和缓存启用的FetchedResultsController也可以改善您的搜索。

BTW:您可以在后台线程上执行那些“激烈”搜索,以避免键盘滞后。但您必须确保一次只执行一个后台请求并仅获取最新结果。以较低优先级标记线程可确保UI运行良好。

有一个wwdc在这里用示例代码提高coredata搜索的速度:
Apple WWDC Core Data
Optimizing Core Data Performance on iPhone OS (Slides)
Optimizing Core Data Performance on iPhone OS (Video)