核心数据 — 高效查找或创建



根据Apple的文档(链接)—

在许多情况下,您可能需要查找现有对象 (已保存在存储中的对象)的一组离散输入值。 一个简单的解决方案是创建一个循环,然后依次为每个值创建一个循环 执行提取以确定是否存在匹配的持久 对象等。此模式不能很好地缩放。如果您个人资料 具有此模式的应用程序,您通常会发现提取是 循环中成本较高的操作之一(与仅 循环访问项目集合)。更糟糕的是,这种模式发生了变化 一个O(n)问题变成一个O(n^2)问题。

如果可能,创建所有托管 对象,然后修复 第二遍。例如,如果您导入的数据,则知道不会 包含任何重复项(例如,因为您的初始数据集为空), 您可以只创建托管对象来表示您的数据,而不执行 任何搜索。或者,如果您导入没有的"平面"数据 关系,您可以为整个集合创建托管对象,并且 在使用单个大IN保存之前清除(删除)任何重复项 谓语。

问题 1:考虑到我要导入的数据没有任何关系,如何实现最后一行中描述的内容。

如果您确实需要遵循查找或创建模式 - 例如因为您 导入混合关系信息的异构数据 在"包含属性信息"中 - 您可以优化查找现有信息的方式 对象,方法是将执行的读取次数减少到最低限度。 如何完成此操作取决于您的参考数据量 必须与之合作。如果要导入 100 个潜在的新对象,并且 您的数据库中只有 2000 个,获取所有现有的和 缓存它们可能不代表重大损失(特别是如果 您必须多次执行该操作)。但是,如果您 您的数据库中有 100,000 个项目,内存压力保持 那些缓存的可能令人望而却步。

可以使用 IN 谓词和排序的组合来减少 您将核心数据用于单个抓取请求。

示例代码:

// 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];

您最终会得到两个排序数组 — 一个数组传递了员工 ID 加入 fetch 请求,以及一个包含匹配的托管对象的请求 他们。要处理它们,您需要按照这些顺序浏览排序列表 步骤:

获取下一个 ID 和员工。如果 ID 与员工 ID 不匹配, 为该 ID 创建一个新员工。 获取下一个员工:如果 ID 匹配,移动到下一个 ID 和员工。

问题 2:在上面的例子中,我得到了两个如上所述的排序数组。考虑到所有要插入的对象都存在于商店中的最坏情况,无论如何我都看不到我可以在O(n)时间内解决问题。Apple将这两个步骤描述为上述,但这是一项O(n^2)工作。对于输入数组中的任何kth元素,在输出数组的前 k 个元素中可能存在也可能不存在与其匹配的元素。因此,在最坏的情况下,复杂性将O(nC2) = O(n^2)

所以,我相信苹果正在做的是确保获取只处理一次,即使需要O(n^2)检查。如果是这样,那么我会选择这个;但是有没有其他方法可以有效地做到这一点。

请理解,我不想一次又一次地获取 - 为大小为 100 的标识符的输入数组获取一次。

Ad. 1 在这里,建立关系的事实并不重要。这种解释只是说,如果您从远程服务器下载数据并且您的项目有一些 ID,那么您可以在一个请求中从持久存储中获取所有数据,而不是在单独的请求中获取每个对象。

广告 2

Apple 将这两个步骤描述为上述,但这是一个 O(n^2) 作业。

不是。请仔细阅读以下行:

要处理它们,请按照以下步骤浏览排序列表:

获取下一个 ID 和员工。如果 ID 与员工 ID 不匹配, 为该 ID 创建一个新员工。 获取下一个员工:如果 ID 匹配,移动到下一个 ID 和员工。

您同时遍历数组/列表,因此您永远不必进行此检查:"在输出数组的前 k 个元素中可能存在也可能不存在与之匹配的元素。您不需要检查以前的元素,因为它们已排序,并且它们肯定不会包含您感兴趣的对象。

如果有人正在寻找原始的Apple文档,这里有快照:

http://web.archive.org/web/20150908024050/https://developer.apple.com/library/mac/documentation/cocoa/conceptual/coredata/articles/cdimporting.html

最新更新