Changing Default Search Algorithm
Choosing between BM25, QPS, and PT15 for your search needs.
ZBSearch defaults to BM25. You can swap it for QPS (Quantum Proximity Scoring) or PT15 (Positional Token 15) with a plugin:
import { create } from 'zbsearch'
import { pluginQPS } from '@zbsearch/plugin-qps'
import { pluginPT15 } from '@zbsearch/plugin-pt15'
const db = create({
schema: {
title: 'string',
description: 'string',
rating: 'number',
},
plugins: [
pluginQPS() // or pluginPT15()
],
})Comparison
| BM25 | QPS | PT15 | |
|---|---|---|---|
| Focus | Term frequency + document length | Token proximity | Token position |
| Best for | General-purpose search | Queries where nearby terms matter | Titles, structured text, prefixes |
| Trade-off | Ignores proximity | More ranking overhead | Fixed 15 position buckets |
BM25 is the industry-standard default - solid for most workloads.
QPS scores documents by how close matching tokens are, which helps with short, focused queries and browser/edge environments.
PT15, inspired by Thomas Wilkerling's work on Flexsearch, stores tokens in 15 positional buckets and prefers matches that appear earlier in a document. It is typically the fastest of the three at search time.
Benchmarks
Same 1,512-document dataset, ZBSearch 4.0.0 (npm run benchmark:algorithms). Higher ops/s is better.
| Benchmark | BM25 | QPS | PT15 |
|---|---|---|---|
| Insert multiple | 29 | 17 | 15 |
| Plain search | 78,046 | 51,316 | 80,490 |
| Search with filters | 28,698 | 33,571 | 42,148 |
| Long text + complex filters | 15,617 | 15,957 | 21,037 |
| Single-term prefix | 2,725 | 4,043 | 8,259 |
BM25 indexes fastest (~1.7–1.9× QPS/PT15). PT15 wins every search case here (about 3× BM25 on prefixes). QPS trades some throughput for proximity-aware ranking.
How to choose
- Stick with BM25 unless you have a reason to change.
- Try QPS when proximity (e.g.
"machine learning"vs"learning machine") matters for relevance. - Try PT15 when you want position-aware ranking and maximum search throughput.
Test each algorithm on your own dataset and queries before committing.