What's New in MDDB 2.17
MDDB 2.17 comes from two reports filed while running a real search site on it: a ports index of 105,000 documents with filters by system, repository, category and maintainer.
The full list is in the changelog. This article covers what changes for you.
Filters now see every match
If you filtered a full-text search, you may have been getting fewer results than exist.
/v1/fts asked the index for the best limit documents of the unfiltered
ranking, then applied filterMeta to those. A filter could only keep what
happened to rank in the global top limit. With 100 documents matching both
query and filter and limit: 50, the response held 7.
The index now returns every text match when a filter is set, the filter runs
over all of them, and the limit is applied last. The same request returns 50.
rangeMeta and boost had the same order and get the same fix, and so does
the text side of /v1/hybrid-search.
Nothing to change on your side, and no cost to speak of: the index was already scoring every match before truncating its sorted output. Only where the truncation happens moved.
A side effect worth knowing: a boost can now lift a document from below the
limit to the top, which is what boosting was for.
Facets over the whole result set
facetBy counts values over the documents a search returns, so the counts
depend on limit. A results page showing 50 ports could only say "among
these 50". A filter sidebar wants the number per category across everything
that matched.
That is now one parameter:
{
"collection": "ports",
"query": "library",
"limit": 50,
"filterMeta": {"system": ["freebsd"]},
"facetBy": ["category"],
"facetScope": "all"
}
{
"results": [ "…the 50 best…" ],
"total": 50,
"matched": 1525,
"facets": {"category": [{"value": "devel", "count": 412}]}
}
facetScope: "all" counts over every document that matched the query and its
filters, before pagination, and matched is the number for an "N found" line.
total keeps its meaning — the number of results returned — so existing
clients see no change.
The counts come from the metadata index rather than from loading each document. Over 20,000 documents with nine metadata fields, counting two facets across 19,823 matches takes 11 ms.
This is on the REST /v1/fts endpoint. Hybrid search has no all scope: its
vector half ranks every document, so "every match" would be the collection.
Bulk loads on spinning disks
On SSDs nobody noticed. On a ZFS mirror of 7,200 rpm disks, a bulk load ran
at 125 documents a second, mostly waiting in fsync.
add-batch itself was fine: two commits per request, whatever the batch
size. The commits came from the embedding worker, which after storing each
document's vectors opened two more write transactions to remove stale chunks
— almost always finding none, and paying an fsync for each empty commit
anyway. A 500-document batch with embeddings cost 1,500 background commits.
It now costs 500.
To see this without dtrace, there is a new Prometheus counter:
rate(mddb_db_write_transactions_total[1m])
Divide it by the documents you load to get commits per document.
DEPLOYMENT
has a new section on spinning disks: what each kind of write commits, and
when sync=disabled on the dataset is a reasonable trade — an index you can
rebuild from its sources — and when it is not.
Also in this release
2.16.1, released earlier the same day, moved the build to Go 1.27.3 for twelve standard-library vulnerabilities in the HTTP and TLS paths. 2.17.0 includes it.
Upgrading
Replace the binary or image and restart. There are no schema changes, no new configuration, and no change to existing request or response fields.