DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Amazon EC2 Deep Dive: Optimizing Workloads With Hardware Insights
  • The Future of Cloud Computing: Unleashing the Power of the Cloud
  • Stop Running Two Data Systems for One Agent Query
  • Mastering SwiftUI Gestures: Basic to Advanced

Trending

  • From APIs to Event-Driven Systems: Modern Java Backend Design
  • Modernization Is Not Migration
  • Building a Reusable Framework to Standardize API Ingestion in an On-Prem Lakehouse
  • Architecting Petabyte-Scale Hyperspectral Pipelines on AWS
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. Real-Time Recommendations Powered by Spanner, BigQuery, and Vector Embeddings

Real-Time Recommendations Powered by Spanner, BigQuery, and Vector Embeddings

Through vector embeddings, this BigQuery and Spanner-powered system delivers real-time, personalized recommendations by capturing nuanced user and product similarities.

By 
Yogesh Tewari user avatar
Yogesh Tewari
·
Aug. 12, 25 · Analysis
Likes (3)
Comment
Save
Tweet
Share
3.3K Views

Join the DZone community and get the full member experience.

Join For Free

Product recommendation systems are an integral part of a wide range of industries like e-commerce, retail, media and entertainment, financial services, etc. Product recommendation is crucial for both providers and consumers as it improves the overall consumer experience and increases sales.

Businesses collect and analyze a ton of consumer usage and behavior data to optimize their  recommendations for purchase and user satisfaction. They strive to deliver these recommendations as soon as possible with the most up-to-date insights. Delays in showing relevant recommendations can result in lost sales and a bad experience for the consumer.

In this article, I would like to present a real-time recommendation system that operates on user and product vector embeddings and is powered by BigQuery (Google Cloud's fully managed, petabyte-scale data warehouse) and Spanner (Google Cloud's fully managed, mission-critical, global-scale database).

Real-time personalized recommendation


Vector Embeddings

Vector embeddings play a crucial role in generating recommendations. They capture user behavior, preferences, and intents based on their interaction with products or services. They also represent various features and attributes of a product or service. Vector embeddings do so by representing both users and products as high-dimensional numerical vectors. By computing distances between these vectors, we can measure similarities among products, among users, and between products and users.

Let's look at an example of vector embeddings. Below, we see two images: a baseball setup and a fishing setup. Feeding these images into Gemini and prompting something similar to "Generate a 64-dimensional vector embedding for these two images, keeping the dimensions the same for both embeddings" generates JSON arrays for two images with the same dimensions as described with the dimension labels in the images below.

The generated JSON arrays for the two images

Now, let's say that the user interacts with the baseball images first. As part of this interaction, we update the user embedding by aggregating the baseball embeddings with the user's existing embeddings (assuming the user embedding has the same dimensions). In this example, we aggregate with a simple average, but based on your business rules and requirements, this can be either a weighted average or any other complex function. After interacting with the fishing image, the system averages out the two embedding vectors and applies that to the user embedding. The updated vector is shown below.

Updated vector


Batch With BQ

Depending on the user traffic on the website or app, the amount of data flowing through the pipeline can be huge. Based on their interactions, most users may not need immediate product recommendations. We collect and batch-process these high-volume, high-velocity user interaction feeds in BigQuery with target (website and app elements like images, banners, buttons, etc.) embeddings. We then perform rolling aggregations with previously computed user embeddings and update the final user embeddings. These user embeddings are then pushed out to Spanner (via reverse ETL mechanisms) for real-time product recommendations for a given user ID.

Batch embeddings

Batch processing steps:

  1. For the given batch duration, get distinct user IDs. This is to reduce the amount of data scanned from the user table in later steps.
  2. For the given batch duration, join the events table with the targets table to map the target embeddings to individual user-target interactions.
  3. Union all mapped embeddings with the respective user IDs from the users table.
  4. Calculate the rolling average of the embeddings across each dimension for the respective users.
  5. Append the updated embeddings to the users table.
SQL
 
---------------------------------------------------------------------------------------------
-- BQ Schema :
---------------------------------------------------------------------------------------------
-- dataset.events
--		user_id			String,
--		target_id		String,
-- 		ts			Timestamp

-- dataset.targets
--		target_id		String,
--		target_emb		String

-- dataset.users
--		user_id			String,
--		emb			String,
-- 		last_updated_ts		Timestamp
---------------------------------------------------------------------------------------------
WITH
  -- STEP 1
  dist_user_ids AS (
  SELECT
    DISTINCT events.user_id,
  FROM
    dataset.events
  WHERE
    events.ts >= $curr_batch_ts),
  -- STEP 2
  user_target_emb AS (
  SELECT
    events.user_id,
    1 AS target_count,
    targets.target_emb AS emb,
  FROM
    dataset.events events
  JOIN
    dataset.targets targets
  ON
    events.target_id = targets.target_id
  WHERE
    events.ts >= $curr_batch_ts
    -- STEP 3
  UNION ALL
  SELECT
    usres.user_id,
    users.target_count,
    users.emb,
  FROM
    dataset.users users
  JOIN
    dist_user_ids
  ON
    users.user_id = dist_user_ids.user_id),
  -- STEP 4
  emb_average AS (
  SELECT
    user_target_emb.user_id,
    idx,
    SUM(user_target_emb.target_count) AS target_count,
    SUM(user_target_emb.target_count * emb_val)/SUM(user_target_emb.target_count) new_emb_val
  FROM
    user_target_emb,
    UNNEST(user_target_emb.emb) emb_val
  WITH
  OFFSET
    AS idx
  GROUP BY
    1,
    2),
  updated_user_embeddings AS (
  SELECT
    user_id,
    ANY_VALUE(target_count) AS target_count,
    ARRAY_AGG(new_emb_val
    ORDER BY
      idx) AS new_emb
  FROM
    emb_average
  GROUP BY
    1 )
  -- STEP 5
SELECT
  user_id,
  target_count,
  new_emb AS emb,
  CURRENT_TIMESTAMP() AS last_updated_ts
FROM
  updated_user_embeddings;


Real-Time With Spanner

The updated user embeddings for the latest batch are pushed out to the corresponding Spanner table via Reverse ETL. The corresponding table for target embeddings is also maintained in Spanner. 

Event streams data in Spanner is needed only for the timestamps that are newer than the current batch being processed in BigQuery. We can schedule a job or assign TTL markers to periodically clean up this table.

In addition to the events, users, and targets tables, we also maintain the assets table, which holds the prediction assets for personalized recommendations. These assets have their own embeddings that match the dimensionality of the user and target embeddings.

Real-time embeddings

When the prediction call comes in from the frontend for a given user:

  1. All the latest events for that user are joined with the targets table to map the target embeddings to individual user-target interactions.
  2. Union all mapped embeddings with the respective user IDs from the users table.
  3. Calculate the final rolling average of the embeddings across each dimension for the given user.
  4. The final user embedding is then used to calculate the distance from the assets.
  5. The n closest assets are returned as part of the personalized recommendation prediction.
SQL
 
  ---------------------------------------------------------------------------------------------
  -- Spanner Schema :
  ---------------------------------------------------------------------------------------------
  -- events
  --		user_id			String,
  --		target_id		String,
  -- 		ts			Timestamp
  -- targets
  --		target_id		String,
  --		target_emb		String
  -- users
  --		user_id			String,
  --		emb			String,
  -- 		last_updated_ts		Timestamp
  -- assets
  --		asset_id		String,
  --		asset_emb		String,
  ---------------------------------------------------------------------------------------------
WITH
  -- STEP 1
  user_target_emb AS (
  SELECT
    events.user_id,
    1 AS target_count,
    targets.target_emb AS emb,
  FROM
    events
  JOIN
    targets
  ON
    events.target_id = targets.target_id
  WHERE
    events.user_id = "$user_id"
    -- STEP 2
  UNION ALL
  SELECT
    usres.user_id,
    users.target_count,
    users.emb,
  FROM
    users
  WHERE
    users.user_id = "$user_id" ),
  -- STEP 3
  emb_average AS (
  SELECT
    idx,
    SUM(user_target_emb.target_count * emb_val)/SUM(user_target_emb.target_count) new_emb_val
  FROM
    user_target_emb,
    UNNEST(user_target_emb.emb) emb_val
  WITH
  OFFSET
    AS idx
  GROUP BY
    1),
  updated_user_embeddings AS (
  SELECT
    ARRAY_AGG(new_emb_val
    ORDER BY
      idx) AS new_emb
  FROM
    emb_average ),
  -- STEP 4
  distances AS (
  SELECT
    asset_id,
    EUCLIDEAN_DISTANCE((
      SELECT
        new_emb
      FROM
        updated_user_embeddings),
      assets.asset_emb) AS distance,
  FROM
    assets)
  -- STEP 5
SELECT
  asset_id,
  distance
FROM
  distances
ORDER BY
  2 DESC
LIMIT
  $n


Conclusion

Based on the business requirements and guidelines, the front-end system will decide which product to show to the user as a final recommendation. This can be as simple as one with the shortest distance or a complex decision process with re-ranking of the predictions.

Putting it all together: 

Putting it together


As seen above, with this combination of real-time and batch processes, we take into account each and every user interaction and are able to recommend products and services that are relevant to the users in the context of their current 'space and time'!

This architecture is also elastic in nature and can scale depending on the user traffic and application requirements.

Data structure Spanner (database) Cloud computing

Opinions expressed by DZone contributors are their own.

Related

  • Amazon EC2 Deep Dive: Optimizing Workloads With Hardware Insights
  • The Future of Cloud Computing: Unleashing the Power of the Cloud
  • Stop Running Two Data Systems for One Agent Query
  • Mastering SwiftUI Gestures: Basic to Advanced

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook