Buy-It-Again Recommendation

View as Markdown

Solution Background and Business Value

Buy-it-again recommendations make it easy for customers to repurchase products they already know and trust. These recommendations:

  • Increase repeat purchases by surfacing past buys at the right moment.

  • Improve customer retention by keeping users engaged with relevant products.

  • Personalize marketing campaigns, including push notifications, in-app recommendations, and emails.

Data Requirements and Schema

To build a buy-it-again recommendation model, you need three core tables: Users, Items, and Transactions. Kumo AI can incorporate additional signals beyond this minimum dataset to improve model quality.

Core Tables

  1. Users Table

    Stores user details.

    • 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.

    • item_id: Unique identifier (Primary Key).
    • item_name, category: Product metadata.
    • start_timestamp / end_timestamp: Item availability window.
    • price, color, other_features: Additional item features.
  3. Transactions Table

    Stores user purchase history.

    • 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 model trained only on past repeat purchases misses important behavioral signals from non-repeat interactions.

Kumo trains a general item-to-user recommendation model and applies filters at prediction time, ensuring:

  • The model learns overall user-item affinity.
  • Users receive 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 Predictive Query Language (PQL) query:

  • Predicts the top 50 distinct items a user is likely to buy again within a future X-day window.
  • Limits predictions to active users who have made at least N purchases in the last D days, which avoids empty recommendation sets after filtering.

Filtering Out Newly Introduced Items

To exclude newly launched items that users have not had time to re-purchase, 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 Fine-Tune SDK

Kumo AI simplifies ML modeling on relational data, making it well suited for this problem.

1. Initialize the Kumo Fine-Tune 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()}')