Parallel requests strategy
Use the parallel requests strategy if your retail media platform (RMP) can return complete product information. This guide explains how the strategy works, its requirements, and how to implement it.
How the parallel requests strategy works
- A user submits a search (for example, “running shoes”).
- Your app makes two requests in parallel: one to Algolia to get the regular search results and one to the RMP to get sponsored product results.
- The backend waits for both responses and then combines the results.
- The combined list of regular and sponsored results is sent to the frontend for display.
Requirements
To effectively implement the parallel requests strategy, you need:
- Full RMP product data. The RMP’s API must provide all the necessary product data for display. This may include a unique product identifier (ideally one that aligns with your Algolia
objectID
), product name, image URL, price, and stock status. - Up-to-date product information. The RMP’s product information must align with your product catalog. Discrepancies in attributes like price or stock levels between the RMP data and your Algolia index can lead to inconsistencies on the frontend, negatively affecting the user experience. Regular synchronization between the RMP and your product catalog is crucial.
- Backend data merging capability. Your backend or integration layer must be capable of making two asynchronous API requests (one to Algolia and one to the RMP) and efficiently merging the resulting datasets. This typically involves a server-side component or cloud function to orchestrate the API calls and process the responses.
- Duplicate handling. It’s common for sponsored products to also appear in the Algolia search results, if they’re a good match for the user’s query. Your data merging logic must identify and remove duplicate entries, ensuring that sponsored products appear only once in the blended results.
If the RMP only returns basic information like product IDs or minimal details, choose the RMP first strategy which retrieves the full product information from Algolia.
Pros
- Fastest response time. Compared to the other strategies, calling both requests in parallel improves performance. The slower of the two API calls dictates search time, rather than the combined duration.
- Direct use of RMP data. If the RMP provides complete product information, there’s no need to call Algolia to fetch details for the sponsored items. You can also display sponsored products that aren’t in an Algolia index.
Cons
- Impact on result counts. Since sponsored results aren’t part of the Algolia query, Algolia’s total results count (
nbHits
) and facet filter counts don’t include these sponsored items. This can lead to a discrepancy between the number of results reported by Algolia and the total number of products displayed. You can mitigate this by using “fuzzy” ranges (10+, 100+) in the UI to reduce user perceptions of inconsistency.
Example
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import algoliasearch from 'algoliasearch';
// Constants
const RETAIL_MEDIA_TIMEOUT_MS = 500;
const RETAIL_MEDIA_API_ENDPOINT = 'https://api.retailmediaplaform.com/search/v1/products/';
const SPONSORED_PRODUCT_POSITIONS = [0, 1, 8, 12];
const ALGOLIA_INDEX_NAME = 'prod_products';
const ALGOLIA_APP_ID = '';
const ALGOLIA_API_KEY = '';
// Algolia setup
const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_API_KEY);
const index = client.initIndex(ALGOLIA_INDEX_NAME);
/* -------------------------------------------------------------------------- */
/**
* Fetches sponsored products from the Retail Media Platform with a timeout mechanism.
* If the request takes longer than RETAIL_MEDIA_TIMEOUT_MS, it will be aborted.
* @param {string} searchQuery - The search term to find sponsored products
* @param {string} filters - Filtering criteria in Algolia format (for example 'size:10 AND color:"blue"')
* @param {Array} organicObjectIds - Array of objectIDs from Algolia's organic hits (only for the Algolia first strategy)
* @returns {Promise} Returns the JSON response from RMP if successful, null if the request times out or fails
*/
async function fetchRetailMediaWithTimeout(searchQuery, filters, organicObjectIds) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), RETAIL_MEDIA_TIMEOUT_MS);
try {
const { statusCode, body } = await request(RETAIL_MEDIA_API_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
signal: controller.signal,
body: JSON.stringify({
keyword: searchQuery,
filters: filters,
organicResults: organicObjectIds || [] // Pass regular results to RMP
})
});
clearTimeout(timeout);
if (statusCode === 200) {
return await body.json();
}
throw new Error(`Request failed with status ${statusCode}`);
} catch (error) {
if (error.name === 'AbortError') {
console.error('Retail Media Platform request timeout');
} else {
console.error('Retail Media Platform request failed:', error);
}
return null;
}
}
/**
* Injects sponsored products into regular hits at specific positions defined by SPONSORED_PRODUCT_POSITIONS.
* Removes any duplicate products that exist in both regular and sponsored hits.
* @param {Array} regularHits - The array of regular product hits from Algolia
* @param {Array} sponsoredHits - The array of sponsored product hits from RMP
* @returns {Array} Combined array of regular and sponsored hits with sponsored products at specified positions
*/
function injectSponsoredProducts(regularHits, sponsoredHits) {
if (!sponsoredHits?.length) return regularHits;
// Remove duplicates
const sponsoredIds = new Set(sponsoredHits.map(hit => hit.objectID));
const finalHits = regularHits.filter(hit => !sponsoredIds.has(hit.objectID));
// Insert sponsored products
SPONSORED_PRODUCT_POSITIONS.forEach((position, index) => {
if (index < sponsoredHits.length) {
const sponsoredHit = { ...sponsoredHits[index], sponsored: true };
const insertPosition = Math.min(position, finalHits.length);
finalHits.splice(insertPosition, 0, sponsoredHit);
}
});
return finalHits;
}
/**
* Performs parallel search requests to Algolia and RMP
* then combines the results with sponsored products injected at specific positions.
* @param {string} searchQuery - The search term to find products
* @param {Object|string} filters - Filtering criteria for both searches
* @returns {Promise<Array>} Combined array of regular and sponsored hits
*/
async function searchProducts(searchQuery, filters) {
const [algoliaResult, retailMediaResult] = await Promise.allSettled([
index.search(searchQuery, {
filters: filters,
hitsPerPage: 48
}),
fetchRetailMediaWithTimeout(searchQuery, filters)
]);
const algoliaHits = algoliaResult.status === 'fulfilled' ? algoliaResult.value.hits : [];
const retailMediaHits = retailMediaResult.status === 'fulfilled' ? retailMediaResult.value?.hits : [];
// Merge results by removing hits duplicates
return injectSponsoredProducts(algoliaHits, retailMediaHits);
}
// Usage
const searchQuery = 'running shoes';
const filters = 'size:10 AND color:"blue"';
const results = await searchProducts(searchQuery, filters);
render(results);
How the code works
- Trigger parallel API calls. Uses server-side code to simultaneously call the Algolia search and the RMP fetch. The Algolia search queries the primary index (with relevant filters applied). This search returns an array of product objects, stored in
algoliaHits
. Simultaneously, thefetchRetailMediaWithTimeout
function calls the RMP’s API. - Apply a timeout to the RMP request.
fetchRetailMediaWithTimeout
ensures you don’t wait longer thanRETAIL_MEDIA_TIMEOUT_MS
for the RMP response. This search stores its results inretailMediaHits
. If the request times out or there are no results,retailMediaHits
is empty. - Merge results and remove duplicates. Once both responses are back (or the RMP call times out), the
injectSponsoredProducts
function mergesalgoliaHits
andretailMediaHits
. It also removes any regular search results that are duplicates of sponsored products. - Return merged results. The frontend receives the merged list, where sponsored products are appropriately labeled.
Before your strategy goes live, ensure you’ve considered the regulatory requirements and the influence of sponsored results on your analytics, ranking, and UI.