我有一个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不仅仅是一次。
在我的谓词中有没有办法让它只将关键字表加载到连接中一次?
由于
答案 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]];