E-commerce Recommendation Engine with VelesDB

July 15, 2026 · View on GitHub

Difficulty: Advanced | Showcases: Vector search (HNSW), hybrid search (Vector + BM25), metadata filtering, co-purchase relationships

A comprehensive example demonstrating VelesDB's Vector + Hybrid + Metadata filtering capabilities for building a product recommendation system.

What This Example Demonstrates

CapabilityUsageBenefit
Vector SearchProduct embeddings for semantic similarity"Find products similar to what I'm viewing"
Hybrid SearchVector + BM25 tag matching via RRF fusionCombines semantic and keyword relevance
Metadata FilterPrice, category, brand, stock, ratings (post-filter)"Only show in-stock items under $500 with 4+ stars"
Co-purchase Lookuprelated_products stored per product"People who bought this also bought..."

Data Model

Products (5,000 items)

Product struct fields (src/main.rs):

  id: u64                 (unique identifier)
  name: String            ("TechPro Premium Smartphones 42")
  category: String        ("Electronics")
  subcategory: String     ("Smartphones")
  brand: String           ("TechPro")
  price: f64              (599.99)
  rating: f32             (4.5)
  review_count: u32       (1234)
  in_stock: bool          (true)
  stock_quantity: u32     (50)
  tags: Vec<String>       (["electronics", "smartphones", "premium", "top-rated"])
  related_products: Vec<u64>  (co-purchase IDs, 2-5 per product)

Embeddings are generated externally via generate_product_embedding() (128 dimensions) and stored as the Point vector. The Product struct itself does not hold the embedding.

Co-purchase Relationships

Each product has a related_products field containing 2-5 random product IDs, simulating co-purchase patterns. These are stored as metadata in the VelesDB payload and looked up directly -- no separate graph collection is used.

Prerequisites

  • Rust 1.90+ with Cargo
  • Node.js 18+ and npm (required only for E2E tests)

Running the Example

cd examples/ecommerce_recommendation
cargo run --release

Expected Output

==================================================================
     VelesDB E-commerce Recommendation Engine Demo
     Vector + Graph-like + MultiColumn Combined Power
==================================================================

--- Step 1: Generating E-commerce Data ---

  Generated 5000 products
  Generated NNNNN co-purchase relationships
  Time: ...

--- Step 2: Building Vector Index (Product Embeddings) ---

  Indexed 5000 product vectors (128 dimensions)
  Stored 11 metadata fields per product
  Time: ...

--- Step 3: Recommendation Queries ---

  User is viewing: <product name> (ID: 42)
  [... detailed query results for 4 query types ...]

--- Performance Summary ---

  Products indexed:          5000
  Co-purchase relations:    NNNNN
  Vector dimensions:          128
  Metadata fields/product:     11

  Demo completed! VelesDB powers your recommendations.

Note: The exact banner uses Unicode box-drawing characters. Step counts, relation totals, and timings vary per run.

Query Examples

Query 1: Pure Vector Similarity

Find products semantically similar to the current product.

// Generate embedding for the sample product
let query_embedding = generate_product_embedding(sample_product, 128);

// Search the VelesDB collection
let results = collection.search(&query_embedding, 10)?;

collection.search() takes a &[f32] query vector and a k count, returning Vec<SearchResult> where each result has a .point (with .payload) and a .score.

Query 2: Vector + Post-Filter

Find similar products that are in-stock and under $500. The code first runs a vector search, then filters results in Rust:

let filtered_results: Vec<_> = results
    .iter()
    .filter(|r| {
        if let Some(p) = &r.point.payload {
            let in_stock = p.get("in_stock").and_then(|v| v.as_bool()).unwrap_or(false);
            let price = p.get("price").and_then(|v| v.as_f64()).unwrap_or(f64::MAX);
            in_stock && price < 500.0
        } else {
            false
        }
    })
    .take(5)
    .collect();

Note: This example applies filters as a post-processing step on vector search results, not via VelesQL execution.

Query 3: Co-purchase Lookup

Find products frequently bought together, using the related_products metadata:

let related_ids: &Vec<u64> = &sample_product.related_products;
// Look up each related product from the in-memory product list
for &related_id in related_ids.iter().take(5) {
    if let Some(product) = products.iter().find(|p| p.id == related_id) {
        // display product
    }
}

This is a direct metadata lookup, not a VelesDB graph traversal.

Query 4: Hybrid Search (Vector + BM25)

Engine-level hybrid search combining vector similarity (60%) and BM25 tag matching (40%) via RRF fusion, then post-filtered by business rules.

// Build a text query from product tags for BM25 signal
let tag_query = sample_product.tags.join(" ");

// Hybrid search: engine-level RRF fusion of vector + BM25
// alpha=0.6 means 60% vector signal, 40% BM25 signal
let hybrid_candidates = collection
    .hybrid_search(&query_embedding, &tag_query, 20, Some(0.6))?;

// Post-filter by business rules
let final_recommendations: Vec<_> = hybrid_candidates
    .into_iter()
    .filter_map(|result| {
        products.iter().find(|p| p.id == result.point.id).and_then(|p| {
            if p.in_stock && p.rating >= 4.0 && p.price < price_threshold {
                Some((p, result.score))
            } else {
                None
            }
        })
    })
    .collect();

collection.hybrid_search() signature: (&[f32], &str, usize, Option<f32>) -> Result<Vec<SearchResult>>.

Performance Characteristics

MetricValue
Products indexed5,000
Vector dimensions128
Co-purchase relations~17,000-20,000 (seeded RNG)
Metadata fields/product11

Latency numbers depend on hardware and are printed at runtime via Instant::elapsed(). They are not deterministic. On an i9-14900KF, typical values observed during development:

QueryTypical LatencyNotes
Vector search~100-300usHNSW search + payload retrieval
Post-filter~1-10usIn-memory filter on vector results
Co-purchase lookup~1-10usDirect metadata access
Hybrid search~200-500usVector + BM25 + RRF fusion + post-filter

Performance Context

VelesDB's raw HNSW index-only benchmark is ~55µs for 10K/768D vectors (k=10, Balanced mode); end-to-end p50 is ~450µs (10K/384D, WAL ON). The demo latencies are higher because:

  • The demo includes payload deserialization and result construction
  • Hybrid search adds BM25 indexing overhead and RRF fusion
  • Timings include all post-processing, not just the HNSW kernel

Architecture

+----------------------------------------------------------+
|                 E-commerce Application                    |
|----------------------------------------------------------|
|                                                          |
|  +--------------+  +--------------+  +--------------+    |
|  |   Vector     |  |   Hybrid     |  |  Metadata    |    |
|  |   Index      |  |   Search     |  |  Post-filter |    |
|  |  (HNSW)      |  | (Vec + BM25) |  |  (in-memory) |    |
|  +------+-------+  +------+-------+  +------+-------+    |
|         |                 |                 |             |
|         +--------+--------+-----------------+             |
|                  |                                        |
|          +-------v-------+                                |
|          |   VelesDB     |                                |
|          |  Query Engine |                                |
|          +---------------+                                |
|                                                          |
+----------------------------------------------------------+

Real-World Applications

This pattern is ideal for:

  • E-commerce: Product recommendations, "Similar items", "Frequently bought together"
  • Media Streaming: Content recommendations based on viewing history + genre similarity
  • Social Networks: Friend suggestions combining profile similarity + mutual connections
  • Job Portals: Job matching using skills embeddings + company network
  • Real Estate: Property recommendations by features + location proximity

Customization

Change Vector Dimensions

// Use the Database API to create a collection with different dimensions
db.create_collection("products", 384, DistanceMetric::Cosine)?;

Add Graph Relationships via VelesDB Graph Collections

For true graph traversal (not just metadata co-purchase lists), use VelesDB's GraphCollection:

let edge = GraphEdge::new(id, source_id, target_id, "SIMILAR_CATEGORY")?;

Custom Scoring Weights

// In hybrid_search, alpha controls vector vs BM25 weight
// alpha=0.6 means 60% vector, 40% BM25
let results = collection.hybrid_search(&embedding, &text, 20, Some(0.6))?;

E2E Tests (Playwright)

The example includes Playwright E2E tests validating:

  • Data generation: 5000 products, co-purchase relationships
  • Query execution: All 4 query types complete successfully
  • Performance: All queries under 10ms threshold
  • Output format: Graph query syntax, performance summary metrics
# Install dependencies
npm install

# Run all tests
npm test

# View HTML report
npm run test:report

License

MIT License