bekko-static-embedding-v1: State-of-the-Art Retrieval for Multilingual Static Embeddings

Community Article
Published October 21, 2026

I've released bekko-static-embedding-v1, a multilingual static embedding model. It achieves state-of-the-art retrieval among static embeddings: about 11 points above the other multilingual static models on multilingual retrieval, and about 2 points above English-only static models on English retrieval.

Static embeddings skip the Transformer: each token maps to a fixed vector, and a sentence embedding is their average. They need no GPU and can run 100x to 400x faster on CPU than models like multilingual-e5-small.

bekko-static-embedding-v1 uses a custom 200k-token tokenizer and was trained contrastively on about 814 million text pairs covering 40 languages, with a batch size of 16,384.

It also performs close to Transformer models. On MMTEB's retrieval tasks, bekko-static-embedding-v1 comes within about 1 point of multilingual-e5-small, a 12-layer Transformer model.

Performance comparison

Against other static embedding models

bekko-static-embedding-v1 leads every public static model I compared, on both multilingual and English retrieval:

  • Multilingual retrieval. On MNanoBEIR (14 languages × 13 tasks, nDCG@10 × 100) it scores 43.76, about 11 points above static-similarity-mrl-multilingual-v1 (32.29) and potion-multilingual-128M (32.23).
  • English retrieval. On NanoBEIR-en (13 tasks) it scores 53.71, above the English-only stable-static-embedding-fast-retrieval-mrl-en-v2 (SST-v2 below, 51.57) and static-retrieval-mrl-en-v1 (50.35). Truncated to 512 dimensions (52.82), it still beats both.
  • MMTEB. Across 131 tasks the average is 50.18, about 3 points above both multilingual static models. In the Retrieval category the margins are 8.75 and 12.10 points.
  • Matryoshka dimensions. Truncating to 512 dimensions costs about 0.9 points of average retrieval score.
Static Embedding Language Dims NanoBEIR-en MNanoBEIR MMTEB Retrieval MMTEB Mean
bekko-static-embedding-v1 Multilingual 1024 53.71 43.76 49.96 50.18
static-similarity-mrl-multilingual-v1 Multilingual 1024 43.51 32.29 41.21 47.24
potion-multilingual-128M Multilingual 256 37.07 32.23 37.86 47.23
static-retrieval-mrl-en-v1 English 1024 50.35 – – –
SST-v2 English 512 51.57 – – –

Table 1: Public static embedding models compared. NanoBEIR-en averages 13 English retrieval tasks, MNanoBEIR 182 retrieval tasks in 14 languages, and MMTEB 131 tasks including classification and clustering. Retrieval columns are nDCG@10 × 100; MMTEB is each task's main score × 100.

Against contextual models

How close can a model with no Transformer layers get to a Transformer encoder? A natural reference is multilingual-e5-small, a 12-layer encoder with 21.6M active parameters that is a common pick for compact multilingual retrieval.

Model Transformer layers Active params NanoBEIR-en MNanoBEIR MMTEB Retrieval MMTEB Mean
bekko-static-embedding-v1 0 0 53.71 43.76 49.96 50.18
multilingual-e5-small 12 21.6M 58.37 51.17 50.9 56.4
bekko-embedding-v1-a8m 4 7.7M 60.34 52.65 56.2 56.7

Table 2: Comparison with contextual models. NanoBEIR-en and MNanoBEIR are HAKARI-Bench nDCG@10 × 100. MMTEB values for multilingual-e5-small and bekko-embedding-v1-a8m come from the bekko-embedding-v1-a8m model card, which uses the official MMTEB snapshot with the same 131 tasks and aggregation. Active parameters exclude the token embedding table.

On MMTEB Retrieval, bekko-static-embedding-v1 comes within about 1 point of multilingual-e5-small (49.96 vs 50.9) without running a single Transformer layer. multilingual-e5-small is still ahead on the Nano retrieval sets, and on the MMTEB mean, where most of its lead comes from BitextMining, Reranking and STS.

If you can afford a small Transformer, my bekko-embedding-v1-a8m scores above multilingual-e5-small in every column with only 7.7M active parameters, and it runs on CPU. BM25 also remains a strong retrieval baseline; I compare it in detail below.

I trained bekko-static-embedding-v1, and I also develop HAKARI-Bench, the retrieval benchmark used in this post.

How static embeddings work

A static embedding model splits text into tokens with a tokenizer and gives each token a fixed vector. Encoding a sentence is just a table lookup for each token followed by a mean. With no Transformer layers to run, vectors come out fast.

Usage with Sentence Transformers

The model loads directly with Sentence Transformers. This example encodes "sushi is delicious" in English, French, Spanish and Chinese.

from sentence_transformers import SentenceTransformer

model = SentenceTransformer("hotchpotch/bekko-static-embedding-v1", device="cpu")
vectors = model.encode(
    [
        "Sushi is delicious.",
        "Les sushis sont délicieux.",
        "El sushi es delicioso.",
        "寿司很好吃。",
    ],
    normalize_embeddings=True,
)
print(vectors.shape)  # (4, 1024)
print(model.similarity(vectors, vectors))

Queries and documents are encoded the same way; no query: or passage: prefixes are needed. For shorter vectors, pass truncate_dim (32, 64, 128, 256, 512 or 1024):

compact = model.encode(["A short query"], truncate_dim=512, normalize_embeddings=True)

Results on MMTEB

MMTEB (Massive Multilingual Text Embedding Benchmark) covers retrieval, classification, clustering, semantic textual similarity (STS) and more. I evaluated the 131 tasks of MTEB(Multilingual, v2) at the full 1,024 dimensions.

The comparison models are static-similarity-mrl-multilingual-v1 from Sentence Transformers and potion-multilingual-128M from Model2Vec. For them I used published evaluation results and averaged over the same 131 tasks.

Category Tasks bekko-static-embedding-v1 static-similarity-mrl-multilingual-v1 potion-multilingual-128M Δ
All tasks 131 50.18 47.24 47.23 +2.93
Classification 43 52.40 48.60 52.36 +3.81
Clustering 16 40.03 30.67 37.63 +9.36
MultilabelClassification 5 14.99 14.74 15.95 +0.25
Retrieval 18 49.96 41.21 37.86 +8.75
Reranking 6 51.59 49.45 47.39 +2.14
STS 16 64.50 64.02 61.23 +0.47
BitextMining 13 43.68 50.62 40.72 -6.94
PairClassification 11 72.81 74.34 71.39 -1.53
InstructionReranking 3 -1.65 -1.24 -2.08 -0.41

Table 3: MMTEB main score × 100, averaged per category. Δ is bekko-static-embedding-v1 minus static-similarity-mrl-multilingual-v1.

The overall average is 50.18 for bekko-static-embedding-v1, about 3 points above static-similarity-mrl-multilingual-v1 (47.24) and potion-multilingual-128M (47.23).

Retrieval is where the gap is consistently large. bekko-static-embedding-v1 scores 49.96, 8.75 points above static-similarity-mrl-multilingual-v1 and 12.10 points above potion-multilingual-128M. Multilingual retrieval is this model's strength.

Against static-similarity-mrl-multilingual-v1 it wins 6 of 9 categories. The largest category gain is Clustering (+9.36), while STS is about even (+0.47).

static-similarity-mrl-multilingual-v1 is ahead on BitextMining, PairClassification and InstructionReranking. The BitextMining gap is the largest at 6.94 points (43.68 vs 50.62). If bitext mining or pair classification is your main use case, include static-similarity-mrl-multilingual-v1 in your evaluation.

English retrieval on HAKARI-Bench

I measured retrieval with the Nano datasets of HAKARI-Bench, which are smaller evaluation sets built from existing retrieval benchmarks. All HAKARI-Bench numbers below are nDCG@10 × 100 averaged with equal weight per task.

For English I used NanoBEIR-en: 13 tasks and 649 queries. The static comparison models are the English retrieval models static-retrieval-mrl-en-v1 and SST-v2. For reference I also include two contextual models, multilingual-e5-small and my own small bekko-embedding-v1-a8m, plus BM25, which ranks by word overlap and term frequency.

Model Type Dims NanoBEIR-en
bekko-static-embedding-v1 Static, multilingual 1024 53.71
bekko-static-embedding-v1 Static, multilingual 512 52.82
static-retrieval-mrl-en-v1 Static, English retrieval 1024 50.35
SST-v2 Static, English retrieval 512 51.57
potion-multilingual-128M Static, multilingual 256 37.07
multilingual-e5-small Contextual, multilingual 384 58.37
bekko-embedding-v1-a8m Contextual, multilingual 384 60.34
BM25 Lexical sparse 57.15

Table 4: NanoBEIR-en task average. bekko-static-embedding-v1 is shown at 1,024 and 512 dimensions; the other embedding models at their default dimensions.

At 1,024 dimensions bekko-static-embedding-v1 scores 53.71, above SST-v2 (51.57) and static-retrieval-mrl-en-v1 (50.35). At 512 dimensions it is still 1.25 points above SST-v2 at the same output width and wins 10 of 13 tasks.

The embedding tables differ in size, though: about 205M parameters for bekko-static-embedding-v1 against about 15.6M for SST-v2.

On English retrieval alone, bekko-embedding-v1-a8m (60.34), multilingual-e5-small (58.37) and BM25 (57.15) remain ahead of every static model.

Multilingual retrieval and BM25

For multilingual retrieval I compared static-similarity-mrl-multilingual-v1, potion-multilingual-128M, multilingual-e5-small, bekko-embedding-v1-a8m and BM25. MNanoBEIR has 14 languages × 13 tasks, 182 tasks in total. HAKARI-Bench covers 37 benchmarks and 550 tasks, including code, long-document and Japanese retrieval; the table shows 10 of them.

Benchmark Tasks bekko-static 1024d bekko-static 512d static-similarity potion mE5-small bekko a8m BM25
MNanoBEIR 182 43.76 42.89 32.29 32.23 51.17 52.65 46.46
NanoMMTEB-v2 18 43.30 42.87 36.08 35.22 44.55 50.25 45.50
NanoMIRACL 18 68.03 67.67 45.37 47.79 78.71 75.57 57.15
NanoRTEB 14 37.50 36.53 25.73 25.58 47.11 54.98 35.53
NanoCoIR 10 58.19 57.55 48.01 45.38 69.15 74.68 54.36
NanoBRIGHT 20 26.38 26.31 20.27 19.67 17.58 31.49 27.90
NanoMLDR 13 55.72 54.55 35.96 34.89 39.20 54.48 73.96
NanoLongEmbed 6 61.96 60.58 48.90 43.90 50.14 68.19 82.17
NanoJMTEB-v2 11 65.36 64.40 51.37 51.61 71.65 75.93 74.65
NanoIndicQA 11 35.35 35.23 34.91 53.69 70.09 65.12 56.53

Table 5: Task average within each benchmark, nDCG@10 × 100. Columns: bekko-static-embedding-v1 at 1,024d and 512d, static-similarity-mrl-multilingual-v1 (1,024d), potion-multilingual-128M (256d), multilingual-e5-small (384d), bekko-embedding-v1-a8m (384d) and BM25. NanoMMTEB-v2 is HAKARI-Bench's retrieval subset, separate from the full MMTEB above.

bekko-static-embedding-v1 at 1,024 dimensions beats static-similarity-mrl-multilingual-v1 on the average of all 37 benchmarks, and on 523 of 550 individual tasks.

Against potion-multilingual-128M it wins 36 of 37 benchmark averages and 520 of 550 tasks. The exception is NanoIndicQA, where potion-multilingual-128M scores 53.69 against 35.35.

The contextual models are still ahead. multilingual-e5-small beats bekko-static-embedding-v1 on 28 of 37 benchmark averages and bekko-embedding-v1-a8m on 36; on MNanoBEIR they score 51.17 and 52.65.

On the long-document benchmarks NanoMLDR and NanoLongEmbed, bekko-static-embedding-v1 beats multilingual-e5-small, partly because multilingual-e5-small reads at most 512 tokens. Against bekko-embedding-v1-a8m, which reads up to 8,192 tokens, NanoLongEmbed goes to bekko-embedding-v1-a8m (68.19), while bekko-static-embedding-v1 is slightly ahead on NanoMLDR (55.72 vs 54.48).

Should you use a static embedding for retrieval?

If retrieval is all you need, BM25 is often enough. In this evaluation BM25 beats bekko-static-embedding-v1 on 21 of 37 benchmark averages and on 342 of 550 tasks. It wins by a wide margin on the long-document NanoMLDR and NanoLongEmbed and on Japanese NanoJMTEB-v2.

On NanoMIRACL, where natural-language questions are matched to documents, the static model wins: 68.03 for bekko-static-embedding-v1 against 57.15 for BM25, a 10.88-point gap. For some retrieval tasks, a static embedding is the better choice.

BM25 relies on matching words, so embedding search can help when queries and documents phrase the same thing differently. The reliable way to choose is to try both on your own corpus.

Matryoshka dimensions and INT8 weights

I trained 1,024, 512, 256, 128, 64 and 32 dimensions together with Matryoshka Representation Learning (MRL), which teaches the model to keep useful information in the leading dimensions. You can pick a vector length per use case and cut storage and search cost.

Besides FP16, I also provide INT8 weights. Here INT8 means the model weights are stored as 8-bit integers; the output vectors are not quantized.

Dims NanoBEIR-en FP16 NanoBEIR-en INT8 MNanoBEIR FP16 MNanoBEIR INT8 Overall FP16 Overall INT8
1024 53.71 53.70 43.76 43.77 45.88 45.89
512 52.82 52.79 42.89 42.88 45.03 45.02
256 50.83 50.82 41.04 41.03 43.29 43.28
128 47.83 47.97 38.03 38.04 40.12 40.12
64 43.96 44.04 32.87 32.87 34.82 34.81
32 35.74 35.72 24.97 24.96 26.46 26.44

Table 6: Retrieval scores by Matryoshka dimension and weight precision, nDCG@10 × 100. Overall is the 550-task average. INT8 results use ONNX.

Going from 1,024 to 512 dimensions halves the vector length and lowers the score by about 0.9 points on both NanoBEIR-en and MNanoBEIR. At 256 dimensions the drop widens to 2.88 and 2.72 points. Even so, at 128 dimensions the MNanoBEIR score of 38.03 is still above static-similarity-mrl-multilingual-v1 at 1,024 dimensions (32.29). INT8 and FP16 differ by less than 0.15 points at every dimension.

I would start with 512 dimensions, and pick INT8 at 512 or 256 dimensions when memory is tight.

Loading only the weights you need

Sentence Transformers' truncate_dim truncates the output vectors, but it still loads the full 1,024-dimensional table. If you only ever use 512 or 256 dimensions, that memory is wasted.

So the repository also ships ONNX and OpenVINO files that contain only the weights for one dimension. The model card provides a small get_model() helper to pick the backend, dimension and precision:

from transformers.dynamic_module_utils import get_class_from_dynamic_module


def get_model(backend="onnx", dim=512, precision="int8", revision="main"):
    repo = "hotchpotch/bekko-static-embedding-v1"
    ext = {"onnx": "onnx", "openvino": "xml"}[backend]
    return get_class_from_dynamic_module(
        "bekko_static_backend.BekkoStaticBackend", repo, revision=revision,
    ).load_sentence_transformer(
        repo, revision=revision, backend=backend,
        file_name=f"{backend}/model_{precision}_dim{dim}.{ext}",
    )


model = get_model(backend="onnx", dim=512, precision="int8")
Dims FP16 weights INT8 weights
1024 409.6 MB 205.6 MB
512 204.8 MB 103.2 MB
256 102.4 MB 52.0 MB
128 51.2 MB 26.4 MB
64 25.6 MB 13.6 MB
32 12.8 MB 7.2 MB

Table 7: Model file size per dimension (decimal MB). ONNX and OpenVINO files are the same size; the tokenizer (about 5.1 MB) is not included.

INT8 at 512 dimensions is 103.2 MB, about a quarter of the 409.6 MB FP16 model at 1,024 dimensions. At 256 dimensions it shrinks to 52.0 MB.

Which model should you pick?

Based on these results, this is how I would choose:

  • For cheap multilingual embeddings, start with bekko-static-embedding-v1 at 512 dimensions.
  • If retrieval is the only goal, compare it against BM25 with a tokenizer suited to your language.
  • For bitext mining or pair classification, also evaluate static-similarity-mrl-multilingual-v1.
  • If retrieval quality matters most and you can afford Transformer inference, consider multilingual-e5-small or bekko-embedding.

bekko-embedding is a contextual embedding family that uses Transformer attention, unlike bekko-static-embedding-v1. Its Transformer part is kept small: bekko-embedding-v1-a8m has about 7.7M active parameters and runs on CPU. In this comparison it scores 60.34 on NanoBEIR-en and 52.65 on MNanoBEIR, both above multilingual-e5-small. If you want a balance of retrieval quality and inference speed, bekko-embedding is worth a look.

How I trained it

A custom tokenizer

In a static model, the tokenizer's units are exactly the units whose vectors get averaged. So besides the existing vocabularies of multilingual BERT and Gemma 2, I tried vocabularies fitted to the training data. bert-base-multilingual-uncased, used by static-similarity-mrl-multilingual-v1, is among the baselines.

The custom vocabularies use WordPiece. I first trained a 30k English vocabulary on equal numbers of Wikipedia and FineWeb documents. I then added vocabulary for 39 more languages while keeping the English token IDs, for 200k tokens in total.

To choose, I trained 8 models, one per tokenizer, on 10% of the training data. I evaluated them on 200 retrieval tasks: MNanoBEIR (14 languages × 13 tasks) and NanoMIRACL (18 languages), nDCG@10 × 100 averaged with equal weight.

"uncased" ignores letter case and "cased" keeps it. "script-balanced" is a candidate that rebalances vocabulary across writing systems. "200k, 30k English" means 200k tokens in total with a 30k English core reserved first.

Tokenizer 1024d 512d
Multilingual BERT uncased 37.87 37.17
Multilingual BERT cased 38.51 38.01
Gemma 2 38.73 38.08
Custom 100k, 24k English, uncased 40.19 39.29
Custom 100k, 30k English, uncased 39.86 39.21
Custom 200k, 30k English, cased 41.60 40.69
Custom 200k, 30k English, script-balanced 41.20 40.40
Custom 200k, 30k English, uncased (selected) 41.89 41.18

Table 8: Retrieval score per tokenizer, nDCG@10 × 100. All 8 models share the same data and training settings. This 10% experiment used a different contrastive loss from the final model, so its scores are not directly comparable with the final model's.

The best was the 200k uncased vocabulary with a 30k English core. Its 41.89 at 1,024 dimensions beats multilingual BERT uncased (37.87) and Gemma 2 (38.73), so the final model uses the same tokenizer.

Training data and hyperparameters

Training uses the bekko-embedding unsupervised dataset, the multilingual corpus described in the Bekko Embedding paper.

From its roughly 1.15 billion rows, I selected 265 data configurations targeting 40 languages, about 814 million text pairs in total.

The 40 target languages are English, Arabic, Bulgarian, Bengali, Catalan, Czech, Danish, German, Greek, Spanish, Estonian, Persian, Finnish, French, Hebrew, Hindi, Croatian, Hungarian, Indonesian, Italian, Japanese, Korean, Dutch, Norwegian, Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Serbian, Swedish, Swahili, Telugu, Thai, Turkish, Ukrainian, Vietnamese, Yoruba, Chinese.

The pairs include titles and bodies, questions and answers, generated search queries and translation pairs. For translation data I kept NLLB English HQ and dropped the other bitext sources. The selection also includes data derived from the MIRACL train split and from NLI.

The embedding table starts from random initialization and learns to pull matching pairs together. The loss is Multiple Negatives Ranking Loss (MNRL), which contrasts each pair against the other candidates in the batch, applied at the full 1,024 dimensions and at every Matryoshka dimension. There is no distillation from a teacher model.

Setting Value
Model Randomly initialized static embedding table with mean pooling
Vocabulary, embedding dim 200,000, 1,024
Embedding table parameters 204,800,000
Data 265 configurations, 40 target languages, about 814M rows
Loss MNRL, temperature 0.03 (scale = 1 / 0.03)
MRL dimensions 32, 64, 128, 256, 512, 1,024
MRL weights 0.025, 0.05, 0.1, 0.15, 0.3, 1.0 (same order)
Epochs, steps 1, 49,727
Global batch size 16,384
Learning rate 0.25
Schedule 10% warmup, cosine decay
Optimizer AdamW, weight decay 0, β₂ = 0.999, ε = 1e−8
Precision BF16 mixed precision, FP32 master weights
Max input length in training 512 tokens
Seed 42
Sampling Proportional to configuration size, with in-batch duplicate suppression

Table 9: Training settings of the released model.

Reproduction scripts

The model repository includes scripts for tokenizer training, model training and FP16 export. They come with the training and data-selection configs, so you can follow the whole path from data selection to the FP16 release.

References

Explore the results

All HAKARI-Bench results are on the leaderboard. The link filters to multilingual-e5-small, bekko-embedding-v1-a8m and every model with static in its name.

Community

Sign up or log in to comment