From 7d43d2a86b067008264e192472eebc62ea941bc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Provost?= Date: Thu, 8 Dec 2016 14:38:14 +0100 Subject: [PATCH 1/2] =?UTF-8?q?Leverage=20the=20new=20=E2=80=9Csearch=20fo?= =?UTF-8?q?r=20facet=20values=E2=80=9D=20feature=20(WIP)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not satisfied with this first version, as it doesn’t have the sequencing logic that is one of the big advantages of the `Searcher`. --- Sources/Searcher.swift | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Sources/Searcher.swift b/Sources/Searcher.swift index 9176b858..bbca34d8 100644 --- a/Sources/Searcher.swift +++ b/Sources/Searcher.swift @@ -415,6 +415,37 @@ import Foundation } } + // MARK: - Search for facet values + + /// Search for values of a given facet. + /// + /// This is a convenience shortcut for Algolia Search's `Index.searchForFacetValues(...)` method that will + /// automatically use the current search `params` as the refining query, also taking into account the + /// conjunctive/disjunctive status of the targeted facet (i.e. refinements for the targeted facet will be discarded + /// when the facet is disjunctive). + /// + /// Unlike a regular `search()`: + /// + /// - The searched text has to be passed as an argument to the method, as it differs in purpose from `params.query`. + /// - Result handlers or the delegate are not called; instead, the provided completion handler is called. + /// Notifications are not issued either. + /// + /// - parameter facetName: Name of the facet to search. It must have been declared in the index's + /// `attributesForFaceting` setting with the `searchable()` modifier. + /// - parameter text: Text to search for in the facet's values. + /// - parameter completionHandler: Completion handler to be notified of the request's outcome. + /// - returns: A cancellable operation. + /// + @objc @discardableResult + public func searchForFacetValues(of facetName: String, matching text: String, completionHandler: @escaping CompletionHandler) -> Operation { + let facetSearchParams = SearchParameters(from: self.params) + // If the searched facet is disjunctive, clear any refinements that it may have. + if facetSearchParams.isDisjunctiveFacet(name: facetName) { + facetSearchParams.clearFacetRefinements(name: facetName) + } + return index.searchForFacetValues(of: facetName, matching: text, query: facetSearchParams, completionHandler: completionHandler) + } + // MARK: - Managing requests /// Indicates whether there are any pending requests. From 0776ef7f1e567725b0a84d3ad786f02135d4d6c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Le=20Provost?= Date: Wed, 14 Dec 2016 18:56:48 +0100 Subject: [PATCH 2/2] Limit the number of pending requests per searcher The main goal is to avoid filling up the request queue when the network is too slow, which could bring the entire search to a stall. --- Sources/Searcher.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Sources/Searcher.swift b/Sources/Searcher.swift index e971c303..0b0eeebe 100644 --- a/Sources/Searcher.swift +++ b/Sources/Searcher.swift @@ -207,6 +207,12 @@ import Foundation /// All currently ongoing requests. private var pendingRequests: [Int: Operation] = [:] + /// Maximum number of pending requests allowed. + /// If many requests are made in a short time, this will keep only the N most recent and cancel the older ones. + /// This helps to avoid filling up the request queue when the network is slow. + /// + @objc public var maxPendingRequests: Int = 3 + // MARK: - Initialization, termination /// Create a new searcher targeting the specified index. @@ -339,6 +345,12 @@ import Foundation Searcher.notificationSeqNoKey: currentSeqNo ] + // Cancel too old requests. + let tooOldRequests = pendingRequests.filter({ $0.0 <= currentSeqNo - maxPendingRequests }) + for (seqNo, _) in tooOldRequests { + cancelRequest(seqNo: seqNo) + } + // Run request // ----------- var operation: Operation!