Need help speeding up search results (Algolia + personalized data)

I’ve integrated Algolia to power my search results successfully (results are fast and accurate) but there is an edge case I’m not sure how to solve.

When I integrate the results from Algolia and filter them with data in the Bubble DB it gets slowed down a lot. I’m not sure if the solution is trying to push all the data to Algolia…

Structure

Object: Product

Metrics: Width, height, stock, list price, etc…. (these are all sent to Algolia)

Object: User

Metrics: Discount rate

A use can filter by width, height, in stock, etc and results get filtered in Algolia quickly. However, each user also has a personalized discount rate (some get a 5% discount, others get a 15% discount, etc). A core feature of the product is users are able to filter products based on the price AFTER the discount is applied.

Currently I do this filtering in an inefficient way, I apply the filters (width, height in stock) in Algolia. I then filter products in the Bubble DB (list price x Discount rate) that are under the price the user has filtered. I check the results of this filtering against the results from Algolia and show the remaining products.

Doing this price filter in Bubble is inefficient and slow but I’m unsure how else to do it. If I did it all in Algolia I would need to send discounted prices for each product (for hundreds and eventually thousands) of users to Algolia, which seems inefficient as well……

Any help is appreciated.

If the user is only able to see prices based on their discount rate, couldn’t you fetch from algolia as normal, then conditionally display the prices with their discount? Or do certain items have different discounts / some are not discounted

Sorry, I just realized I missed out a core piece of data.

Products are from multiple brands. Each user has a specific discount for each brand.

User 1 discounts: Brand A - 5%, Brand B - 15%, Brand C - 8%.

In other words I can’t filter base don the Algolia ‘List Price’ since the discount will be different for every brands.

E.g if someone said the want to see products < $80 after their discount, I can’t filter products by a List price of <$100 in Algolia since not every brand would have a 20% discount.

Without fully understanding the product and how the user is interacting with the items, I would probably suggest that you would need a backend API workflow in bubble to handle this which would call algolia itself, and deliver its own api payload back to the front-end with the discounted items based on the user’s specific discounts.

The backend API workflow would have a list of brand discounts for the user, and in the ‘return data from API’ action you would have to recalculate the ‘amount’ of that product based on the ‘brand discount’. You would then call this from the api connector in order to retrieve back a data type you can map into your front-end.

That’s the first thing that popped into my mind but I don’t know how your data is structured exactly and I probably wouldn’t duplicate a bunch of prices into algolia for different discounts.

Does this look correct:

  1. Call API connector (sending filters user has selected)
  2. API connector sends filters to Backend Workflow (BWF)
  3. BWF calls Algolia using filter data
  4. BWF receives Algolia results
  5. BWF runs recursive workflow (maybe in second BWF) running over each Algolia result to see if it matches the discount $ (?)
  6. Compile list in BWF of Algolia results that match discount $
  7. Return successful Algolia results to front end

Without having a deeper insight into the exact way you have your data structured this would be my high level approach.

Everything looks good up until step 5, by calling and returning your data via the API connector, you have the opportunity to essentially structure it any way you’d like. That would include modifying the returned data.

On Step 5. I would suggest having a ‘return data from API’ action. Inside of this you can specify a JSON schema which you can build from the response from Algolia. What is nice here, is that you can modify the price based on the Brand, and calculate the new price all without having to do a recursive workflow.

Below is an example of how I’m using the return data from API action.

In my example I’m returning an list of objects which consist of form IDs and form names, when called from the API connector, it allows me to map the data nicely so I can use it in my front-end as a list of things.

What I would try on your end is having your data source something like

[Result of Step X Algolia Search :formatted as text]

Then within your :formatted as text you can structure exactly how you’d like your product object to appear to the front-end. When you get to the price key value pair, this is where you would contain the logic to change the price based on the brand.

Do you know what the data looks like when it comes from Algolia? If the Brand is just a textthen it does change things, if it’s recognized as a database thing from bubble (your Brand table) then it’s a bit simpler.

If it’s recognized as a database object:
"Price”: This Product’s Brand: converted to list: intersect with User’s Discount’s: each item’s Brand: first item’s Discount: defaulting to 1 * This Product’s Price

What this logic is doing is it’s looking at your Brand object (derived from the Algolia product), and it’s converting that object into a list (only 1 thing), then it’s comparing your Brand list and User Discount Brand’s List and returning any values that appear in both lists. If it does, it returns the corresponding matching Brands (in this case it would be only 1 brand), we then return the discount percentage (Assuming it’s a decimal), otherwise it returns 1 if there is no Brand returned. It then multiplies that number by the Product Price (returned from Algolia).

This way you either get a discount if the user has a discount for that Brand, or they see the original price. The reason for this strange logic is that bubble doesn’t allow us to fetch the ‘This Product’s Brand’ within an additional nested ‘Formatted as text’ or ‘filtered’ modifiers which we’d need, so I resorted to doing everything in one statement.

Not sure if this helps but if you provide more info on how the data from Algolia comes back you can message me. Not sure if I totally understood what you were trying to do, however with this workflow you can filter down the results based on the total price.

Firstly, thanks for taking the time to create such a detailed response. I’m learning about a new skill set with ‘Return data from API’.

I’ve taken a pass at it but have some extra constraints that seem to be breaking it.

  1. I can’t call Algolia from the backend workflow (the plugin I’m using doesn’t have that functionality and I’d prefer to keep using the plugin rather than using the API directly for consistency). So I’m calling Algolia via the plugin in the front end and passing the response to the API connector. Below you can see what I’m passing to the workflow. Is calling Algolia from the backend a necessity?

objectID = Product unique ID in Bubble DB

  1. ‘Manufacturer’ (Brand) is being returned as a text rather than database object. Due to this I get the ‘Manufacturer’ by searching for the product using objectID (this equates to the products’ Unique ID), and each product is tied to a Manufacturer data type in the DB.

  2. I’m using the :filtered function as the logic on whether to return this objectID to the front end. Is that the correct way to do it? I’m filtering by asking - (products list price * discount) < Net price limit. As you can see below, I’m having to use a few Do a search for which seems inefficient.

  3. In terms of returning the data, is there a way to return ObjectID, Hero Image, List Price Min? My initial thought was I could treat it like a recursive workflow: If objectID (#20 in the list that is passed to the workflow) passes the :filtered, then also return Hero Image and List Price Minat #20 in their lists. This doesn’t seem to work though (I presume I can’t think about this process like a recursive workflow with an iteration number). Currently I’m sending the objectID back, which I can then use to search for the product in the bubble DB and get the product details I need but this is inefficient.