Independent demo based on public GitHub data. PRA is not affiliated with or endorsed by Typesense, Inc.
typesense/typesense · v31 branch · 2026-09-01 to
2026-10-01, UTC
Most of the month’s work corrects searches that returned the wrong
result set. A search across several collections dropped documents it had
already counted. Natural language search ran the user’s sentence instead
of the query built from it, so a question answered by filters returned
nothing. Phrase and infix searches ignored a filter_by that
matched no documents. Two changes are measured: a selective filter from
31 ms to 1 ms, and an embedding call from a 471 ms median to 179 ms.
A search across several collections ranked results through a key that
combined the collection id and the document id by hashing them. The hash
collides on small values, so two documents in neighbouring collections
were read as one and one was discarded. The found count
stayed complete, no cutoff flag was set, and the client saw a total that
did not match the pages. The key now carries both ids and is used for
pinned hits too, so a pinned document no longer suppresses an unrelated
one.
Sources: #3035 · review, section 1.
When a filter_by matched no documents or timed out,
phrase and infix search fell back to their unfiltered matches. The path
is reachable when a pinned or hidden hit, facets or grouping stop the
search from returning early, so a request could answer with the
documents the filter excluded. Both paths now keep such a filter and
admit nothing.
Sources: direct commit d4dbdae, regression tests in #3051 · review, section 5.
A model turns a sentence into search parameters, but retrieval ran on the sentence itself: it was passed in a hidden parameter that outranked the generated query. A wildcard query with a filter, the usual shape of a question answered by filters, returned no hits (#2910). The generated query now drives retrieval and the sentence is kept for highlighting.
Sources: #3047 · review, section 2.
filter_by=A && B cost whatever its wider side
cost: both were computed in full and then intersected. A conjunction
cannot return more documents than its narrower side, so when the other
is at least 32 times wider the narrow side is computed alone and the
wide side is only asked about the ids it produced.
On the project’s benchmark corpus the author measured the conjunction
at 31 ms before and 1 ms after, a mixed filter at 8 ms and 2 ms, with
single-leaf controls unchanged. The measurements are the author’s, on
one machine. The plan needs a wide side not yet computed when the
conjunction starts, so numeric filters in the default configuration,
geo, id and filters over a referenced collection are
unchanged.
Sources: #3049 · review, section 4.
An alias points at a collection, and a join can be declared through it. Swapping an alias to an incompatible collection returned an error and looked rolled back, yet after a restart the alias pointed at the rejected target, which broke join queries. The queue that replays writes after a restart applied the alias change before the collections referring to it, so there was nothing to validate against. Such changes are now ordered behind the collections that depend on them.
Sources: #3055 · review, section 7.
A collection can declare a field whose embeddings come from a remote model. On startup the server pinged that endpoint and treated a failure as fatal, so a restart while it was unreachable removed the field from the schema (#2988). When the dimensions are already stored the ping adds nothing and is now skipped, and endpoint problems surface on requests to the model. The same pull request rejects a query embedding whose size does not match the field: a 400 instead of mismatched vectors in the index.
Sources: #3058 · review, sections 8 and 9.
Calls to remote models and other external endpoints opened a new connection every time, repeating DNS resolution and the TLS handshake. Non-streaming calls now lease connections from a pool with shared DNS and TLS session caches, while streaming and server-sent-event calls keep their own short-lived handles. The author measured an embedding call at a 471 ms median before and 179 ms after, with new TCP connections dropping from five to zero, and natural language search at 944 ms against 778 ms. The streaming case still opens its connections, and its slowest run got slower.
Sources: #3057 · review, section 12.
Async references and aliases. Alias ordering is fixed, the work on reference registrations is not: restoring missing registrations and removing one together with its field (#3082, 7 commits), and skipping collections that failed to load instead of creating ghost documents (#3066, 8 commits). While they are unmerged, a schema change that touches a reference can leave a stale registration behind.
Durability of bulk import. The month fixed what a
search returns, not what a write stores: the branch where a
seq_id becomes searchable before the document is durable
(#3050, 7
commits) was open at the end of September.
Natural language search. Retrieval uses the generated query and the prompt is configurable. The branch with the most September commits, 14, is the typed judgment provider with reranking (#3072), and it is unmerged, so the shape of that generation may still change.
Filter cost and memory. The conjunction plan was measured by its author on two filter shapes. Work on the memory used by nested numeric range filters, in the same iterator code (#3063, 5 commits), is open, and a memory figure would set the boundary of the result.
Facet identifiers. The pinned-hit case is fixed. The collision between a sentinel and a real facet id (#3075) has been open since 24 September and was still open at the end of the month.
Outside the month’s themes. Also open at the cutoff: tokenizers for EmbeddingGemma and Qwen3 (#3038, #3039) and moving the bundled OpenSSL to 3.5.8 (#3064). None of them had merged by the end of September.
The rest of the month’s integrated work. The schema prompt became
configurable through five parameters with its previous defaults, and
nl_query and nl_model_id started working
inside a stored preset (#3046, section
3). Reference facets stopped losing the name of their collection
under pinned hits, which could hang a search (#3084, section
6). Long synonyms sharing a prefix stopped matching the wrong term
(#3054,
section
10), and a geopolygon query takes the polygons whose cells it shares
rather than all of them (#3061, section
11).
Typesense is a trademark of Typesense, Inc.