(Swift) 如何对 Core Data 进行模糊搜索?

Posted

技术标签:

【中文标题】(Swift) 如何对 Core Data 进行模糊搜索?【英文标题】:(Swift) How to do a fuzzy search of Core Data? 【发布时间】:2015-02-02 09:30:50 【问题描述】:

我正在尝试在 Swift 中通过 Core Data 键实现搜索。我想取回相关结果,包括精确的和近似的,按距离排序(从最近的匹配到最远的匹配)。

例如,如果有人搜索“朋友”,我希望搜索结果类似于以下内容:“朋友”、“朋友”、“友好”和“朋友”。

我已尽力实现这样的搜索,但我对这种代码还很陌生,而且我尝试的实现目前对我来说不太有效。这是我的代码:

var request = NSFetchRequest(entityName: "db")
request.returnsObjectsAsFaults = false
request.predicate = NSPredicate(format: "dbKey MATCHES %@", ".*" + searchString + ".*")
var results: Array = context.executeFetchRequest(request, error: nil)!

if (results.count > 100) 
    results.removeRange(Range(start: 100, end: results.count-1))


var sortedResults: Array = [results[0]]

for (var i = 1; i < results.count; ++i) 
        if (countElements(results[i].valueForKey("dbKey") as String) < countElements(sortedResults[i-1].valueForKey("dbKey") as String)) 
        var j = i-1
        while (countElements(results[i].valueForKey("dbKey") as String) < countElements(sortedResults[j].valueForKey("dbKey") as String)) 
            if (j != 0) 
                --j
             else 
                break
            
        
        sortedResults.insert(results[i], atIndex: j)
     else     
        sortedResults.append(results[i])
    


results = sortedResults

问题是双重的:

首先,返回的结果没有特定的顺序,所以如果我搜索“a”,我会在得到完全匹配之前很久就得到大量包含“a”的单词。由于我是在前 100 个结果之后切断的,所以我从来没有在我的结果中显示完全匹配的结果。 其次,排名是近似的。这可能是我的一个数学错误,但目前,许多较长的单词会出现在较短的单词之前,因此您不会在结果列表的顶部看到完全匹配或接近完全匹配的结果,正如您应该看到的那样。

我试图找到一个包含我正在寻找的那种搜索功能的库(类似于Fuse.js),但我没有运气。任何帮助将不胜感激。

【问题讨论】:

我实际上正在创建一个 Swift 版本的 Fuse。那会有帮助吗? (完全披露,我创建了 Fuse.js) @krisk — 你创建了 Swift 版本吗?太棒了:) @jeff-h,这里是 Swift 版本:github.com/krisk/fuse-swift 是的,太棒了:D 【参考方案1】:

不是对您的问题的实际答案,而是您仍在尝试做的事情的解决方案:看看PermissiveResearch。

看起来像这样:

extension UIViewController: PermissiveResearchDelegate 
    // Call this once
    func rebuildDatabase() 
        PermissiveResearchDatabase.sharedDatabase().delegate = self
        for db in allDbs  // Assuming allDbs is your array of DB objects
            PermissiveResearchDatabase.sharedDatabase().addManagedObject(db, forKey: "dbKey")
        
    

    // A basic search method
    func search(searchString: String) 
        PermissiveResearchDatabase.sharedDatabase().searchString(searchString, withOperation: ScoringOperationTypeExact)
    

    // PermissiveResearchDelegate method
    func searchCompletedWithResults(results: [AnyObject]!) 
        let pResults = results as! [PermissiveCoreDataObject]
        for result in pResults 
            let db = try! self.managedObjectContext.existingObjectWithID(result.objectID) as! DB
            print("\(result.score) - \(db.dbKey)")
        
    

【讨论】:

【参考方案2】:

您可以使用不同的谓词过滤结果并决定使用哪一个;

let result = NSPredicate(format: "dbKey CONTAINS[cd] %@", searchString) let result = NSPredicate(format: "dbKey startsWith[cd] %@", searchString) let result = NSPredicate(format: "dbKey LIKE '%@'", searchString)

对于特定顺序,您应该使用 NSSortDescriptor

【讨论】:

以上是关于(Swift) 如何对 Core Data 进行模糊搜索?的主要内容,如果未能解决你的问题,请参考以下文章

Swift Core Data:Core Data 中的枚举 [重复]

如何使用 Swift 在 Core Data 中组合属性?

如何在 Swift 中将 Core Data 与 Cloudkit 和许多设备同步

如何在 Swift 中的 Core Data 中保存多个项目

Swift:当 didSelectRowAtIndexPath 时如何更新 Core Data 中的数据?

Swift 3 Core Data - 如何同步保存上下文?