Buy-It-Again Recommendation

View as Markdown

Solution Background and Business Value

Buy-it-again recommendations enhance customer experience by making relevant products easily accessible while also driving business growth. These recommendations:

  • Increase repeat purchases by reminding users of past buys.

  • Boost customer retention by keeping users engaged.

  • Optimize marketing campaigns by personalizing push notifications, in-app recommendations, and emails.

By implementing this approach, businesses ensure they remain top-of-mind for customers, maximizing conversion rates and brand loyalty.

Data Requirements and Schema

To develop an effective Buy-It-Again recommendation model, we need three core tables: Users, Items, and Transactions. While this is the minimum dataset, Kumo AI allows us to enhance the model by incorporating additional signals.

Core Tables

  1. Users Table

    • Stores user details.

    • Key attributes:

      • user_id: Unique identifier (Primary Key).

      • join_timestamp: When the user joined.

      • age, location, other_features: Optional user attributes.

  2. Items Table

    • Stores product details.

    • Key attributes:

      • item_id: Unique identifier (Primary Key).

      • item_name, category: Product metadata.

      • start_timestamp / end_timestamp: Item availability.

      • price, color, other_features: Additional item features.

  3. Transactions Table

    • Stores user purchase history.

    • Key attributes:

      • transaction_id: Unique identifier (Primary Key).

      • user_id: Foreign Key linking to Users.

      • item_id: Foreign Key linking to Items.

      • timestamp: Purchase date.

      • total_amount, payment_method, other_features: Transaction metadata.

Entity Relationship Diagram (ERD)

Predictive Queries

One challenge in buy-it-again recommendations is differentiating repeat purchases from one-time buys. A simple model using only past repeat purchases misses out on important behavioral signals.

We train a general item-to-user recommendation model and apply filters at prediction time, ensuring:

  • The model learns overall user-item affinity.

  • The user receives only buy-it-again recommendations.

PREDICT LIST_DISTINCT(transactions.item_id, 0, X, days) RANK TOP 50
FOR EACH users.user_id
WHERE COUNT(transactions.*, -D, 0, days) >= N

This query:

  • Predicts the top 50 distinct items a user is likely to buy again.

  • Looks at a future X-day window.

  • To avoid empty recommendation sets after filtering, we limit predictions to active users who have made at least N purchases in the last D days.

Filtering Out Newly Introduced Items

To exclude newly launched items (which users haven’t had time to re-purchase), we apply post-processing in SQL:

1SELECT *
2FROM (
3 PREDICTIONS
4 JOIN (
5 SELECT entity_id, item_id
6 FROM <ORDERS>
7 WHERE timestamp <= PREDICTION_ANCHOR_TIME
8 ) AS CANDIDATES
9 ON PREDICTIONS.entity_id = CANDIDATES.entity_id
10 AND PREDICTIONS.item_id = CANDIDATES.item_id
11);

Building models in Kumo SDK

This problem can be efficiently solved using Kumo AI, which simplifies ML modeling on relational data.

1. Initialize the Kumo SDK

1import kumoai as kumo
2
3kumo.init(url="https://<customer_id>.kumoai.cloud/api", api_key=API_KEY)

2. Create a Connector for Data Storage

1connector = kumo.S3Connector("s3://your-dataset-location/")

3. Select tables

1users = kumo.Table.from_source_table(
2 source_table=connector.table('users'),
3 primary_key='user_id',
4).infer_metadata()
5
6items = kumo.Table.from_source_table(
7 source_table=connector.table('items'),
8 primary_key='item_id',
9).infer_metadata()
10
11transactions = kumo.Table.from_source_table(
12 source_table=connector.table('transactions'),
13 time_column='timestamp',
14).infer_metadata()

4. Create graph schema

1graph = kumo.Graph(
2 tables={
3 'users': users,
4 'items': items,
5 'transactions': transactions,
6 },
7 edges=[
8 dict(src_table='transactions', fkey='user_id', dst_table='users'),
9 dict(src_table='transactions', fkey='item_id', dst_table='items'),
10 ],
11)
12
13graph.validate(verbose=True)

5. Train the model

1pquery = kumo.PredictiveQuery(
2 graph=graph,
3 query=(
4 "PREDICT LIST_DISTINCT(transactions.item_id, 0, X, days) RANK TOP 50\n"
5 "FOR EACH users.user_id"
6 ),
7)
8pquery.validate(verbose=True)
9
10model_plan = pquery.suggest_model_plan()
11trainer = kumo.Trainer(model_plan)
12training_job = trainer.fit(
13 graph=graph,
14 train_table=pquery.generate_training_table(non_blocking=True),
15 non_blocking=False,
16)
17print(f"Training metrics: {training_job.metrics()}")

6. Run the model

1prediction_job = trainer.predict(
2 graph=graph,
3 prediction_table=pquery.generate_prediction_table(non_blocking=True),
4 output_types={'predictions', 'embeddings'},
5 output_connector=connector,
6 output_table_name='buy_it_again_predictions',
7 training_job_id=training_job.job_id,
8 non_blocking=False,
9)
10print(f'Batch prediction job summary: {prediction_job.summary()}')