← Back to labs
Case study · ML engineering

najdiavto-ml

An end-to-end ML service for a car marketplace — price intelligence, hybrid search, learning to rank, and MLOps. Built to demonstrate real ML engineering, not just LLM API orchestration.

0.86MRR (LTR, held-out)
62eval queries
3retrieval channels
4MLOps phases
The problem

Helping buyers answer three questions

Car buyers on najdiavto.com need help with three things: is this listing fairly priced? Can I find cars using natural language? Are results ranked by relevance, not just recency? This project answers all three as a separate ML service that the app calls over HTTP.

Architecture

Four phases, one service

Phase 1

Price intelligence

A price-check API that tells buyers whether a listing is fairly priced. Built on a public AutoScout24 DE dataset (~45k listings) with a feature pipeline, segment benchmarks, and a Random Forest model.

  • Feature pipeline + hierarchical mileage imputation
  • Compared Linear Regression, Random Forest, LightGBM
  • Random Forest best at ~25% MAPE (documented dataset limitation)
  • POST /check-price returns suggested price + check/warning icon
Phase 2

Hybrid search

Natural-language search over live listings. Three retrieval channels fused by Reciprocal Rank Fusion (RRF) — no heavy embedding model needed at ~50 listings.

  • BM25 lexical + TF-IDF vector + structured attribute matcher
  • Explicit intent (fuel/body/price) becomes a hard filter
  • Rule-based eval set: 62 queries in Slovenian, English, German
  • Diacritics normalized so 'električni' matches 'electric'
Phase 3

Learning to rank

Replaced hand-tuned RRF weights with a learned LightGBM LambdaMART reranker that re-ranks the candidate pool by predicted relevance.

  • Features from raw channel scores + listing attributes
  • Honest query-grouped holdout (no language leakage)
  • MRR 0.79 → 0.86 on unseen query intents
  • Serving auto-attaches the reranker with graceful fallback
Phase 4

MLOps

Made the running service observable and safe to retrain — monitoring, drift detection, and a publish-only-if-better promotion gate.

  • GET /metrics: per-endpoint latency + error stats
  • Data-drift detection via PSI + category-share shift
  • retrain-all: one command retrains price + search + rank
  • Candidate vs incumbent promotion (never silently degrade)
Stack

Tools used

Pythonscikit-learnLightGBMMLflowFastAPIpandaspydanticDockerpytest