核心数据任何多内部联接

时间:2013-10-04 01:44:11

标签: ios core-data nspredicate

我有一个CoreData模型,其中包含一系列可搜索的“配方”对象。为了提高搜索效率,我有一个名为“关键字”的引用模型,它只具有“term”属性(已编入索引)。该术语是一个单词,由'食谱名称处理和标准化。

因此,例如,如果一个食谱叫做CrèmeBrûlée,它会有两个关键词'creme'和'brulee',那么我也会规范用户的搜索,这样他们就可以用重音词找到非重音词,副词反之亦然。

当用户搜索我接受字符串时,规范化然后按空格分割。搜索配方结果必须包含以所有拆分搜索组件开头的关键字。

我创建了一个动态谓词,它根据用户搜索的单词数量而增长。

如果您正在搜索'crem',谓词就会变成:

[NSPredicate predicateWithFormat:@"ANY keywords.term BEGINSWITH %@", @"crem"]

如果你搜索'crem bru':

[NSPredicate predicateWithFormat:@"ANY keywords.term BEGINSWITH %@ AND ANY keywords.term BEGINSWITH %@", @"crem", @"bru"]

现在,我面临的问题。

用一个字来说,这是非常快速的。我可以在3GS上运行它,并且没有明显的滞后现场搜索建议。当您在搜索中添加后续单词时会出现问题。我查看了SQL输出,我认为问题是CoreData正在按照“ANY keywords.term BEGINSWITH”进行INNER JOIN,但如果我自己重写查询,我只需用一个INNER JOIN即可。

在3GS上运行:

单字(0.0262秒):

  

CoreData:sql:SELECT DISTINCT t0.Z_ENT,t0.Z_PK,t0.ZID,t0.ZNAME   从ZCDRECIPE t0 JOIN Z_4RECIPES t1 ON t0.Z_PK = t1.Z_5RECIPES 加入   ZCDKEYWORD t2 ON t1.Z_4KEYWORDS = t2.Z_PK WHERE   NSCoreDataStringSearch(t2.ZTERM,?,8,0)ORDER BY t0.ZNAME

     

CoreData:注释:sql连接获取时间: 0.0262s

多字(0.2996秒):

  

CoreData:sql:SELECT DISTINCT t0.Z_ENT,t0.Z_PK,t0.ZID,t0.ZNAME   从ZCDRECIPE t0 JOIN Z_4RECIPES t1 ON t0.Z_PK = t1.Z_5RECIPES 加入   ZCDKEYWORD t2 ON t1.Z_4KEYWORDS = t2.Z_PK JOIN Z_4RECIPES t3 ON   t0.Z_PK = t3.Z_5RECIPES JOIN ZCDKEYWORD t4 ON t3.Z_4KEYWORDS = t4.Z_PK   WHERE(NSCoreDataStringSearch(t2.ZTERM,?,8,0)AND   NSCoreDataStringSearch(t4.ZTERM,?,8,0))ORDER BY t0.ZNAME

     

CoreData:注释:sql连接获取时间: 0.2996s

你可以看到即使它正在查看同一个表,但CoreData与ZCDKEYWORD的INNER JOINing不仅仅是一次。

在我的谓词中有没有办法让它只将关键字表加载到连接中一次?

由于

1 个答案:

答案 0 :(得分:2)

尝试使用复合谓词语法。在类似的情况下,这个设置我得到了非常好的结果。

for (NSString *s in words) {
   finalPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:
     @[finalPredicate, [NSPredicate predicateWithFormat:
         @"ANY keywords.term BEGINSWITH %@", s]]];
}

修改

在查找旧解决方案之后,我意识到你可能会以错误的方式进行查找。这说得通。您有多个keywords查找,因此会有两个连接。

从关系中的其他实体派生您想要的数据可能更好。谓词应直接引用关键字实体:

[NSPredicate predicateWithFormat:@"term BEGINSWITH %@", s];

导出最终结果应该只是一个内存中查找:

searchResults = [searchResults filteredArrayUsingPredicate:
    [NSPredicate predicateWithFormat:@"ANY keywords IN %@", fetchedKeywords]];