2013-10-15 3 views
4

эффективно Согласно документации Apple, (link) -Основные данные - Найти или Создать-

There are many situations where you may need to find existing objects (objects already saved in a store) for a set of discrete input values. A simple solution is to create a loop, then for each value in turn execute a fetch to determine whether there is a matching persisted object and so on. This pattern does not scale well. If you profile your application with this pattern, you typically find the fetch to be one of the more expensive operations in the loop (compared to just iterating over a collection of items). Even worse, this pattern turns an O(n) problem into an O(n^2) problem.

It is much more efficient—when possible—to create all the managed objects in a single pass, and then fix up any relationships in a second pass. For example, if you import data that you know does not contain any duplicates (say because your initial data set is empty), you can just create managed objects to represent your data and not do any searches at all. Or if you import "flat" data with no relationships, you can create managed objects for the entire set and weed out (delete) any duplicates before save using a single large IN predicate.

Вопрос 1: Учитывая, что мои данные я импортирования не имеет отношения, как я реализовать то, что описано в последней строке.

If you do need to follow a find-or-create pattern—say because you're importing heterogeneous data where relationship information is mixed in with attribute information—you can optimize how you find existing objects by reducing to a minimum the number of fetches you execute. How to accomplish this depends on the amount of reference data you have to work with. If you are importing 100 potential new objects, and only have 2000 in your database, fetching all of the existing and caching them may not represent a significant penalty (especially if you have to perform the operation more than once). However, if you have 100,000 items in your database, the memory pressure of keeping those cached may be prohibitive.

You can use a combination of an IN predicate and sorting to reduce your use of Core Data to a single fetch request.

Пример кода:

// Get the names to parse in sorted order. 
NSArray *employeeIDs = [[listOfIDsAsString componentsSeparatedByString:@"\n"] 
     sortedArrayUsingSelector: @selector(compare:)]; 

// create the fetch request to get all Employees matching the IDs 
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
[fetchRequest setEntity: 
     [NSEntityDescription entityForName:@"Employee" inManagedObjectContext:aMOC]]; 
[fetchRequest setPredicate: [NSPredicate predicateWithFormat: @"(employeeID IN %@)", employeeIDs]]; 

// Make sure the results are sorted as well. 
[fetchRequest setSortDescriptors: 
    @[ [[NSSortDescriptor alloc] initWithKey: @"employeeID" ascending:YES] ]]; 
// Execute the fetch. 
NSError *error; 
NSArray *employeesMatchingNames = [aMOC executeFetchRequest:fetchRequest error:&error]; 

You end up with two sorted arrays—one with the employee IDs passed into the fetch request, and one with the managed objects that matched them. To process them, you walk the sorted lists following these steps:

Get the next ID and Employee. If the ID doesn't match the Employee ID, create a new Employee for that ID. Get the next Employee: if the IDs match, move to the next ID and Employee.

Вопрос 2: В приведенном выше примере, я получаю двух отсортированных массивов, как описано выше. Учитывая худший сценарий, когда все объекты, которые должны быть вставлены, присутствуют в магазине, я все равно не вижу, что я могу решить проблему в O(n) времени. Apple описывает два шага, как указано выше, но это задание O(n^2). Для любого элемента kth во входном массиве может существовать или не существовать элемент, который соответствует ему в первых k элементах в выходном массиве. Так что в худшем случае сложность будет O(nC2) = O(n^2).

Итак, что я считаю, Apple делает это, чтобы убедиться, что только при получении только процессов, хотя есть O(n^2) требует чеков. Если да, то я пойду с этим; но есть ли другой способ сделать это эффективно.

Пожалуйста, поймите, что я не хочу получать снова и снова - выбор один раз для входного массива из 100 идентификаторов размера.

ответ

2

Объявление. 1 Факт наличия отношений здесь не важен. В этом объяснении говорится, что если вы загружаете свои данные, например, на удаленном сервере и ваших элементах есть несколько идентификаторов, то вы можете извлечь их из хранилища в одном запросе вместо того, чтобы извлекать каждый объект в отдельный запрос.

Объявление. 2

Apple describes the two steps as above but that is an O(n^2) job.

Это не так. Пожалуйста, прочтите эти строки внимательно:

To process them, you walk the sorted lists following these steps:

Get the next ID and Employee. If the ID doesn't match the Employee ID, create a new Employee for that ID. Get the next Employee: if the IDs match, move to the next ID and Employee.

Идут Массивы/списки одновременно, так что вы никогда не должны делать эту проверку: «там может или не может существовать элемент, который соответствует его в первые к элементам в выходной массив. " Вам не нужно проверять предыдущие элементы по мере их сортировки, и они, конечно же, не будут содержать интересующий вас объект.

+0

Хорошо, я понимаю это, и я ошибся. Это в основном процесс O (n). Но это все еще оставляет часть 1. Как это сделать? > Или, если вы импортируете «плоские» данные без каких-либо связей, вы можете создавать управляемые объекты для всего набора и отсеивать (удалять) любые дубликаты перед сохранением с помощью одного большой IN предикат. – p0lAris

+1

@ flippex17: Я думаю, что они имеют в виду это. Вы вставляете управляемые объекты в контекст. Затем вы захватываете идентификаторы (или другие идентификаторы) этих объектов, помещаете их в предикат 'IN' и извлекаете массив объектов из постоянного хранилища (объекты, которые вы только что вставили, не будут извлекаться, потому что они еще не созданы сохранены). Затем вы перебираете «вставленные объекты» NSManagedObjectContext' и удаляете объекты, найденные в постоянном хранилище. Это в основном то, что я написал в своем ответе, только что реализованный в другом порядке. –

+1

@ flippex17: Это не соответствовало моему предыдущему комментарию: вам также нужно преобразовать массив ('fetch array of the objects') в' NSDictionary', индексированный вашими идентификаторами '' ', чтобы получить амортизированный O (1) поиск. –

Смежные вопросы