2011-12-11 43 views
5

我試圖在我的應用程序中實現搜索。有兩個核心數據實體「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)並嘗試進一步優化之後,搜索速度也非常緩慢。我怎樣才能讓這個更快?

編輯:

基於雅各布的初步建議,這是我的新方法:

​​

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]]; 
} 
+0

是否所有四個版本同樣慢?您篩選的結果集有多大?你可以使用除包含以外的東西嗎? –

+0

@DavidRönnqvist - 結果集約1200個對象。也許我完全誤解了UISearchResultsController ...至於比較慢,我用眼睛來描繪,不使用工具,所以我不確定。對我來說似乎也一樣。 – Moshe

回答

6

有很多東西在咀嚼CPU循環和內存:

其中一個,你正在從NSFetchedResultsController取得結果的可變副本。爲什麼?

二,您對上述結果使用for..in構造,並分別調用-[NSPredicate evaluateWithObject:]。你可以修改你的謂詞搜索字符串來代替-[NSArray filteredArrayUsingPredicate:],這很可能比你的方法更快。

三,您的predicate變量存在一個相當微妙的問題 - 您總是將其重新分配給除開始時自動釋放的空白之外的其他內容。給它默認值nil

四,您的謂詞字符串效率相當低,就像您提到的那樣。 我認爲你需要做一些叫索引或類似的東西。

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

+1

我可以在NSFetchedResultsController上調用'filteredArrayUsingPredicate'嗎?如果沒有,我可以使用它作爲類方法>如果沒有,我需要額外的數組。查看我更新的代碼。是的,CONTAINS是我最大的問題。 – Moshe