Migrating from Elasticsearch to Vespa for Large-Scale Search Platform
vinted · E-commerce · 2024 · source Agentic: no · promotional bias: low · source-backed · extracted with prompt 0.5.6 (schema v2)
Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.
Problem
Domain: Large-scale marketplace search infrastructure
Vinted needed to replace an Elasticsearch search platform that had become difficult to scale, tune, and reindex while serving roughly one billion active searchable items with low latency and relevance-sensitive ranking.
Constraints:
- The old platform ran 6 Elasticsearch clusters with 20 data nodes each plus client nodes.
- Search index freshness was constrained by a 300-second Elasticsearch refresh interval.
- Shard and replica tuning, reindexing, and alias switches created operational burden.
- The system needed to support lexical, vector, and structured search with machine-learned ranking in real time.
- Migration had to preserve relevance and production performance during the switch.
Architecture
Vinted migrated item search from six Elasticsearch clusters to one Vespa deployment with 60 content nodes, 3 config nodes, 12 container nodes, HAProxy routing, and a Golang gateway exposing a stable search contract. The indexing path uses Apache Flink plus Vespa Kafka Connect to feed Vespa in real time. Querying uses custom Vespa searchers that construct YQL behind the gateway contract, while Vespa combines lexical, vector, and structured retrieval with integrated machine-learned inference. The migration used shadow traffic, amplified traffic tests, A/B relevance iterations, inactive-region testing, Prometheus metrics, and stress tests before fully switching traffic.
Diagram confidence: explicit (topology described by the source).
flowchart LR Apps["Product search applications"] --> Gateway["Golang search gateway"] Gateway --> Searchers["Custom Vespa searchers"] Searchers --> Vespa["Vespa deployment"] SIP["Search indexing pipeline"] --> Vespa HAProxy["HAProxy load balancer"] --> Vespa Gateway --> Shadow["Shadow traffic path"] Shadow --> Vespa Vespa --> Metrics["Prometheus metrics"]
Components
| Component | Role | Interacts with |
|---|---|---|
Product search applications |
Marketplace product surfaces that issue item-search requests. | Golang search gateway |
Golang search gateway |
Middleware service exposing the flat search contract and insulating product clients from the search engine migration. | Product search applications, Custom Vespa searchers, Shadow traffic path |
Custom Vespa searchers |
Vespa search components that implement query logic and construct YQL calls. | Golang search gateway, Vespa deployment |
Vespa deployment |
Single search deployment with content, config, and container nodes supporting lexical, vector, structured search, and ML inference. | Custom Vespa searchers, HAProxy load balancer, Search indexing pipeline, Prometheus metrics |
Search indexing pipeline |
Apache Flink and Vespa Kafka Connect feed path that updates Vespa in real time. | Vespa deployment |
HAProxy load balancer |
Routes production traffic to stateless Vespa container nodes. | Vespa deployment |
Shadow traffic path |
Migration safety path that mirrored and amplified traffic from Elasticsearch-era serving to Vespa before cutover. | Golang search gateway, Vespa deployment |
Prometheus metrics |
Observability surface for query latency, indexing throughput, and bottlenecks. | Vespa deployment |
Data flow
Product applications send search requests to a Golang gateway using a flat search contract. The gateway calls Vespa custom searchers, which construct YQL for a single Vespa deployment. In parallel, Apache Flink feeds item updates through Vespa Kafka Connect so the index stays near real time. HAProxy routes production traffic to stateless Vespa container nodes, and Prometheus metrics plus inactive-region tests monitor performance before and after rollout.
3 supporting quotes
Why this architecture
Vespa let Vinted consolidate search into one horizontally scalable deployment while combining lexical search, vector search, structured queries, and real-time machine-learned inference. The search-contract gateway and shadow traffic path made the engine migration safer, while Flink-based real-time feeding directly reduced feature lead time by shrinking indexing latency.
3 supporting quotes
Models used: Vespa integrated machine-learned model inference · vector search embeddings · ranking algorithms
Scale
- Vinted had about 1 billion active searchable items.“At the time of writing, we have about 1 billion active searchable items.”article, stated
- The platform peaked around 20,000 requests per second under 150 ms at p99.“We peaked at about 20,000 requests per second under 150 ms at the 99th percentile.”article, stated
- Daily Vespa indexing handled 10,300 RPS for update and remove operations.“The daily feeding rate (indexing in Vespa terms) is done in real-time at 10,300 RPS for both update/remove operations.”article, stated
- The migration reduced item-search content nodes from more than 120 Elasticsearch data nodes to 60 Vespa content nodes.“Today, for our item search, we’ve moved to 1 Vespa deployment (cluster) with 60 content nodes, 3 config nodes and 12 container nodes.”article, stated“Before migrating, we had 6 Elasticsearch clusters with 20 data nodes each, plus dozens of client nodes running on virtual machines.”article, stated
- Single-item update latency reached 4.64 seconds at p99 from Apache Flink to Vespa.“The time it takes for a single item to be updated is 4.64 seconds at the 99th percentile from Apache Flink to Vespa.”article, stated
- The team tested Vespa update and removal capacity up to 50k RPS per deployment.“handle up to 50k RPS for updates and removals per deployment – significantly reducing the time to index a single item”article, stated
Alternatives considered (roads not taken)
Keep Elasticsearch as the long-term search platform
Rejected because: Elasticsearch had become hard to scale, tune, and reindex as data and query complexity grew.
Adopt a solely vector or hybrid-search database
Rejected because: Vinted concluded that Vespa's breadth across vector, lexical, structured search, and ML inference better fit their scale and complexity.
Cut over without shadow traffic and relevance A/B iterations
Rejected because: The team first mirrored, amplified, and A/B-tested traffic until performance and relevance were acceptable.
Patterns
hybrid-search (retrieval)
Vinted chose Vespa partly because it could combine lexical search, vector search, and structured data queries in one request.
retrieval-ranking (retrieval)
The migration increased ranking depth and used Vespa ranking configurations to improve search relevance.
canary-rollout (deployment)
The migration used shadow traffic, amplified traffic, inactive-region testing, and A/B iterations before fully switching traffic.
eval-driven-development (evaluation)
Vinted used peak traffic simulation, stress tests, A/B relevance tests, and accuracy validation to tune the Vespa deployment.
observability-tracing (operations)
Prometheus metrics from Vespa were used to monitor latency, indexing throughput, and bottlenecks before user impact.
latency-optimization (performance)
The platform focused on lower query latency, lower indexing latency, and faster item visibility through Vespa's architecture and real-time indexing.
Tradeoffs
Consolidate item search into one Vespa deployment
Chose One Vespa deployment with content, config, and container nodes over Multiple Elasticsearch clusters with many data and client nodes.
Rationale: The consolidated Vespa topology reduced server count, improved consistency, removed hot-node issues, and simplified scaling.
Use Vespa's integrated search and ML platform
Chose Vespa as a unified lexical, vector, structured, and ML-inference search platform over A narrower vector-only or hybrid-search database.
Rationale: Vinted needed one platform that handled scale, query complexity, and real-time ML inference rather than a specialized retrieval store.
Preserve language analysis through upstream Lucene integration
Chose Contribute Lucene text analysis components to Vespa over Losing Elasticsearch language analyzers during migration.
Rationale: The team retained existing language-analysis capabilities while moving to Vespa's scalability and performance model.
Gotchas (what bit them)
Search-engine migration is also a client-interface migration unless clients are insulated.
Root cause: Product applications depended on search behavior while the backend engine changed from Elasticsearch to Vespa.
Resolution: A Golang gateway exposed a predefined search contract so clients did not need to track Vespa internals.
Fast query serving is not enough if indexing latency slows experimentation.
Root cause: Feature-development lead time depends on how quickly search-index changes become visible.
Resolution: Vinted fed Vespa from Apache Flink in real time and reduced visibility time from 300 seconds to about 5 seconds.
Elasticsearch shard and replica management became a source of operational toil.
Root cause: Reindexing and field changes required complex shard rebalancing, alias switches, and index recreation.
Resolution: Vespa's distributed architecture manages partitioning and replication across content nodes while continuing to serve queries.
Evaluation
Vinted validated Vespa through shadow traffic, amplified traffic, A/B relevance iterations, peak-load simulation, indexing stress tests, inactive-region testing, and Vespa Prometheus monitoring.
Metrics: 20,000 requests per second under 150 ms p99 · 10,300 RPS daily feeding rate · 4.64 seconds p99 item update latency · traffic amplification up to 3x · four A/B test iterations for main search relevance · query latency and indexing throughput
3 supporting quotes
Outcomes
- Vinted cut item-search servers roughly in half, down to 60 content nodes.
- Search latency improved by 2.5x and indexing latency improved by 3x.
- Search visibility dropped from a 300-second refresh interval to about 5 seconds.
- Ranking depth increased more than 3x to 200,000 candidate items.
- Load distribution became even across nodes, eliminating hot-node behavior.
- Vinted operated 21 unique Vespa deployments across item search, image retrieval, and search suggestions.
The article reports about 1 billion active searchable items, about 20,000 RPS under 150 ms at p99, 10,300 RPS real-time feeding, 4.64-second p99 item update latency, and 21 Vespa deployments.