Concepts / Building Search UI / Multi index search
May. 10, 2019

Multi Index Search

Overview

Sometimes a single search interface is not enough to fit your use case. Maybe you want to display a single search bar, but search in multiple indices at the same time. Maybe you just want to show a minimal search interface on your home page, and a more detailed view in a second screen.

For all those use-cases where a single interface would not work, we provide a feature: Multi-Index.

Implementation

In order to specify to InstantSearch which index you want to target, go to your AppDelegate and then inside your application(_:didFinishLaunchingWithOptions:) method, replace what is in it with:

1
2
let searcherIds = [SearcherId(index: "bestbuy_promo"), SearcherId(index: "store_index")]
InstantSearch.shared.configure(appID: ALGOLIA_APP_ID, apiKey: ALGOLIA_API_KEY, searcherIds: searcherIds)

In that way, InstantSearch is aware of the indices that it has to deal with. Next, go to your ViewController and replace all of it with the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import UIKit
import InstantSearch
import InstantSearchCore

class HitsViewController: MultiHitsTableViewController {

    @IBOutlet weak var tableView: MultiHitsTableWidget!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        hitsTableView = tableView
        
        InstantSearch.shared.registerAllWidgets(in: self.view)
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath, containing hit: [String : Any]) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "hitCell", for: indexPath)
        
        if indexPath.section == 0 { // bestbuy
            cell.textLabel?.highlightedTextColor = .blue
            cell.textLabel?.highlightedBackgroundColor = .yellow
            cell.textLabel?.highlightedText = SearchResults.highlightResult(hit: hit, path: "name")?.value
        } else { // store_index
            cell.textLabel?.highlightedTextColor = .white
            cell.textLabel?.highlightedBackgroundColor = .black
            cell.textLabel?.highlightedText = SearchResults.highlightResult(hit: hit, path: "name")?.value
        }
        
        return cell
    }

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 30))
        
        let view = UIView()
        view.addSubview(label)
        view.backgroundColor = UIColor.gray
        return view
    }
}

Things to note:

First, from previous single-index implementations, we changed some classes from HitsXYZ to MultiHitsXYZ. These are MultiHitsTableViewController and MultiHitsTableWidget, Nothing changed in the ViewDidLoad, and in the cellForRowAt method, we now have to deal with 2 sections since we’ll have one for bestbuy, and one for store_index. Finally, we specify a viewForHeaderInSection to put a separator between these 2 sections.

Storyboard

Now, head into the Main.Storyboard, select your stat widget (if you want one), and then in the property inspector, add store_index to the index field. This specifies that the stats label shows number of results for store_index products. Next, click on the tableView which shows the hits, and then in the identity inspector, change the class to MultiHitsTableWidget. Then, head to the identity inspector and specify the following:

  • Indices: bestbuy_promo,store_index
  • Hits Per Section: 5,10

Here, we are saying that we want to show the bestbuy_promo index in the first section and the store_index index in the second. We also specify that we want 5 hits to appear for the bestbuy_promo index and 10 for the store_index index.

Now run your app, search in the search bar and you should see results appearing from the indices!

Refinement List

If you want a refinement list, then you need to specify which index it is targeting. This is because we are in “multi-index” mode and the refinement list doesn’t have a clue what index to target: is it bestbuy_promo or store_index?

In order to specify this, go to your main.storyboard class, then click on the refinement list. In the attribute inspector, specify bestbuy_promo as the index.

Now go ahead and run your app again. When selecting a filter in your refinement list, you’ll notice in the main screen that the refinements are only being applied to the bestbuy_promo index.

Notes

You might have seen Variant or Variants attributes in the identity inspector (variants example: main,details). These are used in case you want 2 widgets to use the same index but with different configurations. You also have to specify those variants when configuring InstantSearch using the SearcherId(index:variant) constructor instead of SearcherId(index:). Concerning the SearchBarWidet: by not specifying any index there, InstantSearch will conclude that the Search bar should search in all index. If an index was specified, then the SearchBarWidget would only trigger a search in that particular widget.

Did you find this page helpful?