2011-12-11 37 views
5

Tôi đang cố triển khai tìm kiếm trong ứng dụng của mình. Có hai thực thể Core Data, "Tag" và "DvarTorah". Thẻ chỉ có một chuỗi. "DvarTorah" có tiêu đề, nội dung văn bản và một số thuộc tính khác. Tôi đang cố gắng tìm ra cách tốt nhất để tìm kiếm chúng một cách nhanh chóng. Các ứng dụng tàu với khoảng 1200 thực thể DvarTorah, và thậm chí nhiều thẻ hơn. Ngay bây giờ, tôi tải lên một NSFetchedResultsController khi bộ điều khiển xem tìm kiếm của tôi gọi viewDidLoad. Sau đó, khi người dùng nhập vào hộp tìm kiếm hoặc thay đổi phạm vi, tôi gọi một phương thức nhận cả giá trị thanh phạm vi và cụm từ tìm kiếm và lọc mảng đối tượng của tôi. Dưới đây là cách hiển thị:Làm cách nào để tối ưu hóa tìm kiếm dựa trên Dữ liệu cốt lõi này?

- (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]; 
} 

Vấn đề là phương pháp tìm kiếm của tôi rất chậm. Tôi biết rằng CONTAINS là một thủ phạm có khả năng, nhưng ngay cả sau khi lưu trữ một phiên bản chuẩn của nội dung (như searchableContent) và cố gắng tối ưu hóa hơn nữa, việc tìm kiếm là khủng khiếp chậm. Làm thế nào tôi có thể thực hiện điều này nhanh hơn?

Edit:

Dựa trên lời đề nghị ban đầu của Gia-cốp, đây là phương pháp mới của tôi:

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:

Không sao chép mảng nữa, vẫn còn chậm:

- (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

Có phải tất cả bốn phiên bản đều chậm? Các kết quả được đặt mà bạn đang lọc là bao nhiêu? Bạn có thể lấy đi bằng cách sử dụng một cái gì đó khác hơn là chứa? –

+0

@ DavidRönnqvist - Tập kết quả là khoảng 1200 đối tượng. Có lẽ tôi hiểu lầm UISearchResultsController hoàn toàn ... Theo như chậm so sánh, tôi là profiling bằng mắt, không sử dụng một công cụ, vì vậy tôi không chắc chắn. Có vẻ như tôi cũng thế. – Moshe

Trả lời

6

Có nhiều thứ đang nhai chu kỳ CPU và bộ nhớ ở đây:

Một, bạn đang tạo bản sao có thể thay đổi được kết quả được tìm nạp từ NSFetchedResultsController. Tại sao?

Hai, bạn đang sử dụng một cấu trúc for..in dựa trên kết quả của việc nêu trên và gọi -[NSPredicate evaluateWithObject:] trên mỗi thiết bị. Bạn có thể sửa đổi chuỗi tìm kiếm vị ngữ của mình để làm việc với -[NSArray filteredArrayUsingPredicate:] thay vào đó, rất có thể nhanh hơn cách tiếp cận của bạn.

Ba, có một vấn đề khá tinh tế với biến số predicate của bạn - bạn luôn gán lại cho một thứ khác không phải là tự động phát hành trống lúc đầu. Đặt giá trị mặc định là nil.

Bốn, chuỗi vị ngữ của bạn khá kém hiệu quả, như bạn đã đề cập. Tôi nghĩ bạn cần phải làm điều gì đó được gọi là lập chỉ mục hoặc một cái gì đó tương tự.

Thông tin thêm về toàn văn tìm kiếm với 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

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

Tôi có thể gọi 'filterArrayUsingPredicate' trên NSFetchedResultsController không? Nếu không, tôi có thể sử dụng nó như là một phương thức lớp> Nếu không, tôi cần thêm mảng. Xem mã cập nhật của tôi. Và có, CONTAINS là vấn đề lớn nhất của tôi ở đây. – Moshe

Các vấn đề liên quan