Skip to content

Conversation

@francoischalifour
Copy link
Contributor

@francoischalifour francoischalifour commented Mar 11, 2019

This is the 1st PR in the series "Merchandized Query Rules".

Summary

This creates the connectQueryRules connector, responsible for handling Algolia Query Rules features.

Motivation

Implementing Query Rules inside InstantSearch allows users to promote results and translate search intent with minimal setup and configuration.

Query Rules is a powerful feature in the Algolia engine that is complex to implement with InstantSearch. This feature is often used on E-commerce websites but requires developers to use low-level primitives in our libraries.

Users often need to adapt the search experience based on specific queries (e.g. showing a banner to promote a brand new MacBook). This is possible by creating new rules (either on the Algolia dashboard, via the API clients or the REST endpoints). These rules can return custom data as JSON format. The Algolia API returns this data as userData.

Banner

Banner promoting results on Amazon

Query Rules offer a custom experience based on rule contexts. You might want to customize the users' experience based on the filters of the search (e.g. you're visiting the "Mobile" category). This is achieved by setting a context when creating a rule and providing the API parameter ruleContexts when searching. Specifying ruleContexts at search time creates a lot of friction without dedicated API for the developer (this is doable via the internal helper or with the configure widget).

Implementation

The connector gets the results from the helper and passes the userData array to the widgets. I decided to keep the name userData in the connector, and not items in case we want to expose more objects that could also be called items. If you think this is safe enough, we can rename userData to items.

The connector is also responsible for manipulating the ruleContexts with the helper to configure search parameters.

Connector usage

Two widgets will be based on this connector:

Related

@francoischalifour francoischalifour requested a review from a team March 11, 2019 15:50
@algobot
Copy link
Contributor

algobot commented Mar 11, 2019

Deploy preview for instantsearchjs ready!

Built with commit c8d8390

https://deploy-preview-3597--instantsearchjs.netlify.com

@francoischalifour francoischalifour force-pushed the feat/mqr-connectQueryRules branch from 68a0095 to 57eaa60 Compare March 11, 2019 16:06
const previousRuleContexts = helper.getQueryParameter('ruleContexts');

if (!isEqual(previousRuleContexts, ruleContexts)) {
helper.setQueryParameter('ruleContexts', ruleContexts).search();
Copy link
Contributor Author

@francoischalifour francoischalifour Mar 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When refining an item in a refinement list for example, this will trigger 2 network requests because of this implementation.

  1. Send request to refine the filter (see connectRefinementList implementation)
  2. Send request with the new ruleContexts (this line)

I'm not aware of any current way of batching this kind of requests in InstantSearch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now there is none. It's fine for now, we can add the batch to the list of things that the helper can do for us.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually after talking a bit with Marie & Julien it might be problematic. We can have a blink:

  1. select the refinement -> a request is triggered
  2. render with the results, context is applied -> a new request is triggered
  3. a query rule is triggered based on the context that set a new filter
  4. render with other results, which means that at the step 2 we get stalled results

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that an acceptable tradeoff for now? (I would say so)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It worth trying with a query rule that alter the results to see the actual impact. We can decide then if it's a tradeoff that is acceptable or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I promoted the movie "Gone girl" to position 2 in this movie demo when you click on the genre "Drama".

There's indeed a flash, which is noticeable.

@Haroenv
Copy link
Contributor

Haroenv commented Mar 11, 2019

The connector gets the results from the helper and passes the userData array to the widgets. I decided to keep the name userData in the connector, and not items in case we want to expose more objects that could also be called items. If you think this is safe enough, we can rename userData to items.

Makes sense to me!

@francoischalifour francoischalifour force-pushed the feat/mqr-connectQueryRules branch from 57eaa60 to eae2a06 Compare March 12, 2019 10:23
@francoischalifour francoischalifour changed the base branch from chore/instantsearch-types to feat/merchandized-query-rules March 12, 2019 10:23
const previousRuleContexts = helper.getQueryParameter('ruleContexts');

if (!isEqual(previousRuleContexts, ruleContexts)) {
helper.setQueryParameter('ruleContexts', ruleContexts).search();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now there is none. It's fine for now, we can add the batch to the list of things that the helper can do for us.

@francoischalifour francoischalifour force-pushed the feat/mqr-connectQueryRules branch from 5eb1dcb to d074247 Compare March 12, 2019 13:34
@francoischalifour francoischalifour requested a review from a team March 15, 2019 09:17
const previousRuleContexts = helper.getQueryParameter('ruleContexts');

if (!isEqual(previousRuleContexts, ruleContexts)) {
helper.setQueryParameter('ruleContexts', ruleContexts).search();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually after talking a bit with Marie & Julien it might be problematic. We can have a blink:

  1. select the refinement -> a request is triggered
  2. render with the results, context is applied -> a new request is triggered
  3. a query rule is triggered based on the context that set a new filter
  4. render with other results, which means that at the step 2 we get stalled results

@francoischalifour francoischalifour force-pushed the feat/mqr-connectQueryRules branch from 89949e1 to b0557d6 Compare March 20, 2019 12:31
@francoischalifour
Copy link
Contributor Author

The queryRuleContext widget, responsible for setting ruleContexts based on tracked filters, reaches a technical limitation right now that might be problematic.

We internally need to trigger two requests because of the way the JS helper is designed, as explained in #3597 (comment).

I reproduced the behavior in the Query Rules demo. To reproduce:

  1. Click on the genre "Drama"
  2. See two different result sets loading one after the other

This is an unwanted behavior because:

  • There's a flash in the UI (even more noticeable on slow networks)
  • It triggers two requests → undesirable for customers

Some work is being done on the helper because of the needs of Federated Search. We could add "batching requests" in the features that we want the helper to support.

The release of the queryRuleContext widget will therefore be postponed until the "batching request" feature lands in the helper.

The queryRuleCustomData widget can still be shipped without this.

We can either keep or temporarily remove the ruleContexts-related feature from the Query Rules connector.

@francoischalifour
Copy link
Contributor Author

⬆️ I removed the ruleContexts-related features from the connector and only commented the tests so that we can reuse them when we're ready to reimplement these features (I didn't skip the tests because TypeScript was complaining about the now non-existant trackedFilters and transformRuleContexts options).

@francoischalifour francoischalifour requested a review from a team March 21, 2019 09:17
@francoischalifour francoischalifour changed the base branch from feat/merchandized-query-rules to develop March 22, 2019 14:41
@francoischalifour francoischalifour merged commit 924cd99 into develop Mar 22, 2019
@francoischalifour francoischalifour deleted the feat/mqr-connectQueryRules branch March 22, 2019 14:43
francoischalifour added a commit that referenced this pull request Apr 11, 2019
# [3.3.0](v3.2.1...v3.3.0) (2019-04-11)

### Bug Fixes

* **connectQueryRules:** improve tracked refinement type ([#3648](#3648)) ([e16ad57](e16ad57))
* **currentRefinements:** don't rely on  ([#3672](#3672)) ([cd64bcf](cd64bcf))
* **queryRuleCustomData:** add default template ([#3650](#3650)) ([83e9eaa](83e9eaa))
* **QueryRuleCustomData:** pass data as object to templates ([#3647](#3647)) ([b8f8b4e](b8f8b4e))
* **queryRules:** fix types and stories ([#3670](#3670)) ([ba6e2e6](ba6e2e6))
* **routing:** apply windowTitle on first load ([#3669](#3669)) ([d553502](d553502)), closes [#3667](#3667)
* **routing:** support parsing URLs with up to 100 refinements ([#3671](#3671)) ([6ddcfb6](6ddcfb6))
* **RoutingManager:** avoid stale uiState ([#3630](#3630)) ([e1588aa](e1588aa))
* **types:** improve InstantSearch types ([#3651](#3651)) ([db9b91e](db9b91e))
* **ua:** Update the User-Agent to use the new format ([#3616](#3616)) ([ab84c57](ab84c57))

### Features

* **infiniteHits:** add previous button ([#3645](#3645)) ([2c9e38d](2c9e38d))
* **queryRules:** add connectQueryRules connector ([#3597](#3597)) ([924cd99](924cd99)), closes [#3599](#3599) [#3600](#3600)
* **queryRules:** add context features to Query Rules ([#3617](#3617)) ([922879e](922879e)), closes [#3602](#3602)

### Reverts

* feat(infiniteHits): add previous button ([214c0fc](214c0fc))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants