首页 > 解决方案 > FireStore getDocuments() 函数在第一次搜索查询时运行速度极慢

问题描述

背景

我正在使用 Firebase Firestore 使用该getDocuments()功能检索英文单词数据。这是检索数据的数据模型。

struct WordModel: Codable {

    let id: String
    let number: Int
    var partOfSpeech: [String]?
    var ipa: [String?]
    var audio: [String?]

    private enum CodingKeys: String, CodingKey {
        case id
        case number
        case partOfSpeech
        case ipa
        case audio
    }
}

查询是一个单词或句子,它被分解为一个单词数组,其中每个单词数组的块大小最多为 10。然后我使用.whereField("id", in: wordChunk)来查询这些单词。wordChunk 是一个最多包含 10 个单词的数组。这是运行查询并返回结果的函数:

    func readEnglishDocumentByWord(words: [String], completion: @escaping(_ result: [WordModel?]) -> Void) {

        var results = [WordModel?]()
        var finalResult = [WordModel?]()
        var data: WordModel?
        let lowerCaseWords = words.map { $0.lowercased() }
        let wordChunks = lowerCaseWords.chunked(into: 10)

        start = CFAbsoluteTimeGetCurrent() //start timer
        for wordChunk in wordChunks {

            let docRefs = db.collection(K.FBConstants.dictionaryCollectionName).whereField("id", in: wordChunk)

            docRefs.getDocuments { (querySnapshot, err) in
                self.first = CFAbsoluteTimeGetCurrent() // first time check
                print("First: \(self.first! - self.start!)")
                if let err = err {
                    print("Error getting documents: \(err)")
                    completion(finalResult)
                } else {
                    for document in querySnapshot!.documents {
                        do {
                            data = try document.data(as: WordModel.self)
                            results.append(data)
                        } catch {
                            results.append(nil)
                        }
                    }
                    for word in words {
                        let tempWordModel = results.filter { $0?.id == word.lowercased() }

                        if tempWordModel.count == 0 {finalResult.append(nil)}
                        else {finalResult.append(tempWordModel[0])}
                    }
                }
                completion(finalResult)
            }
        }
    }

问题

假设我搜索句子:“今天将是美好的一天”

这意味着wordChunk = [today, will, be, a, good, day]

如果以前从未搜索过这句话,则查询将花费30s。这个号码是从 中检索的print("First: \(self.first! - self.start!)")。如果我再次搜索同样的东西,最多需要1s。这发生在任何搜索中,无论大小。我做了一些研究,发现有些人提到了有关云功能冷启动时间的内容,以及其他人有类似问题,但我无法找到解决此问题的优质解决方案。我尝试禁用持久性settings.isPersistenceEnabled = true,但没有奏效。有解决办法吗?我是在错误地实现某些东西还是 Firestore 的问题。非常感谢任何帮助或建议。谢谢!

标签: iosswiftfirebaseperformancegoogle-cloud-firestore

解决方案


我最终只是使用而不是使用 where 子句单独拉出每个文档getDocument(),并使用 Dispatch 组来告诉我所有查询何时完成。

    func readEnglishDocumentByWord(words: [String], completion: @escaping(_ result: [WordModel?]) -> Void) {

        var results = [WordModel?]()
        var finalResults = [WordModel?]()
        let lowerCaseWords = words.map { $0.lowercased() }
        let dispatchGroup = DispatchGroup()

        start = CFAbsoluteTimeGetCurrent() //start timer
        for word in lowerCaseWords {

            let docRef = db.collection(K.FBConstants.dictionaryCollectionName).document(word)
            dispatchGroup.enter()
            docRef.getDocument { (document, error) in
                self.first = CFAbsoluteTimeGetCurrent() // first time check
                print("First: \(self.first! - self.start!)")

                let result = Result {
                    try document.flatMap {
                        try $0.data(as: WordModel.self)
                    }
                }
                switch result {
                case .success(let wordModel):
                    if let wordModel = wordModel {
                        results.append(wordModel)
                    } else {
                        results.append(nil)
                        print("Document does not exist")
                    }
                case .failure(let error):
                    results.append(nil)
                    print("Error decoding city: \(error)")
                }
                dispatchGroup.leave()
            }
        }
        dispatchGroup.notify(queue: .main) {
            for word in words {
                let temp = results.filter{$0?.id == word.lowercased()}
                if temp.count == 0 {finalResults.append(nil)}
                else {
                    finalResults.append(temp[0])
                }

            }
            completion(finalResults)
            print("Finished with results: \(results.count)")
        }
    }

推荐阅读