本文介绍了如何优化基于核心数据的搜索?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我想在我的应用程式中执行搜寻。有两个核心数据实体,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]]; } 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]]; } 解决方案在这里抓取CPU周期和内存: 一个,你正在做一个可变的副本从 NSFetchedResultsController 。为什么? 两个,你使用 for..in - [NSPredicate evaluateWithObject:] 。您可以修改谓词搜索字符串以使用 - [NSArray filteredArrayUsingPredicate:] ,这很可能比您的方法更快。 三,你的谓词变量有一个相当微妙的问题 - 你总是将它重新分配给除了autoreleased empty之外的其他东西。给它默认值 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的核心数据框架中搜索 I'm trying to implement search in my app. There are two Core Data entities, "Tag" and "DvarTorah". A tag has just a string. A "DvarTorah" has a title, textual content, and some other properties. I'm trying to figure out the best way to search them quickly. The app ships with about 1200 DvarTorah entities, and even more tags. Right now, I load up an NSFetchedResultsController when my search view controller calls viewDidLoad. Then, when the user types into the search box or changes the scope, I call a method which takes in both the scope bar value and a search term, and filters my array of objects. Here's how that looks:- (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];}The problem is that my search method is terribly slow. I know that CONTAINS is a likely culprit, but even after storing a canonical version of the content (as searchableContent) and attempting to optimize further, the search is horrendously slow. How can I make this faster?Edit:Based on Jacob's initial suggestions, here's my new method: 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]];}Edit2: Not copying the array anymore, still slow:- (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]];} 解决方案 There are many things that are chewing up CPU cycles and memory here:One, you're making a mutable copy of the results fetched from the NSFetchedResultsController. Why?Two, you're using a for..in construct on the result of the above and calling -[NSPredicate evaluateWithObject:] on each. You can revise your predicate search string to work with -[NSArray filteredArrayUsingPredicate:] instead, which is most likely faster than your approach.Three, there is a rather subtle issue with your predicate variable - you always re-assign it to something else other than the autoreleased empty at the beginning. Give it the default value of nil.Four, your predicate strings are rather inefficient, as you mentioned.I think you need to do something called indexing or something like it. More information on full-text searching with Core Data:http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/CoreData/Articles/cdPerformance.htmlhttp://cocoawithlove.com/2008/03/testing-core-data-with-very-big.htmlhttp://cocoawithlove.com/2009/11/performance-tests-replacing-core-data.htmlhttp://www.mlsite.net/blog/?page_id=1194Is SQLite FTS3 still the best way to go for rolling out your full text search?sqlite Indexing Performance AdviceFull Text Searching in Apple's Core Data Framework 这篇关于如何优化基于核心数据的搜索?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-27 01:28