Why it mattersA developer can now write a semantic filter in SQL alongside numeric predicates and joins, which puts natural-language matching inside a Postgres query plan and reports the tokens and dollars each run costs.
Zach Rait released pg-jev on 17 September, a PostgreSQL extension that adds a jev() function to a WHERE clause and answers it with TypeSafe's Jev model. The repository has reached 220 stars in three days and ships on PGXN. There is no index to build, no embedding, and no vector column: every candidate row is passed to Jev in batches of 20, one yes-or-no question per row, and the answer comes back as a calibrated probability.
What the SQL looks like
The extension exposes jev(row, condition) as an ordinary boolean function, plus jev_prob for the probability, jev_choice for the most likely of a set of options, and jev_score for a probability-weighted position on an ordered set of labels. The rait/pg-jev README gives four examples: SELECT * FROM people WHERE jev(people, 'the name is European'), ranking tickets by jev_prob(tickets, 'the customer is angry'), routing tickets to a team with jev_choice, and scoring products against ARRAY['budget', 'mid-range', 'premium', 'luxury'] with jev_score. Because jev() is a plain SQL function, it composes with AND age > 40, joins, GROUP BY, LIMIT and ORDER BY jev_prob(...).
Cost and speed, from the project's own numbers
Rait publishes measured figures on a 2,000-row table with a 190 ms round trip to the TypeSafe API. A first run over the whole table takes 3.5 seconds across 100 requests, uses 296,000 input tokens, and costs 1.2 cents. A second run of the same query takes 50 milliseconds because per-row judgments are cached for the session. Adding LIMIT 3 on a new condition takes 0.6 seconds, because the read-ahead stops after the in-flight window and rows that other predicates already filtered out are never judged. Version 0.1.0 needed 8.5 seconds and 338,000 tokens for the same full query, so the batched-state approach in the current release cuts tokens by 12% and time by 59%.
Why 20 rows per request
Jev has to find rows[i] by position in an array, and Rait reports that accuracy holds up to a batch of 20 rows. Against ground truth from structured columns (job title, EU membership, a phrase in a free-text field, 400 rows each), batches of one to 20 rows were 100% correct, batches of 40 fell to 92 to 98%, and batches of 80 fell to 77 to 94%. Batches of 20 cost 4% more tokens than batches of 40 and take the same wall-clock time, because request latency depends barely on payload size. That is how the extension picks its default.
Where it will not run
pg-jev needs PostgreSQL 14 to 17 with the plpython3u extension, a superuser to install it, and a TypeSafe API key. Rait names three managed hosts that block one of those requirements: Supabase, Neon, RDS. The extension fits a self-hosted Postgres, a Docker Postgres in tests, a preview database, or a laptop. jev_stats() returns the tokens, estimated cost, cache hits and pooled connections for the current session, so the bill can be watched in the same psql window.
No index means every judged row costs an API call. The README puts the request overhead at 270 tokens before any row content is added, so a query over one row uses 435 tokens against 175 tokens per row in a batch of 20. A team that wants a persistent semantic filter across a large table is better served by embeddings and pgvector. pg-jev is the answer when the condition changes per query, the row count is small enough for a full scan, and the probability calibration matters.
Source
Source: GitHub
This item was written by an AI system from the linked source. Reveneau is responsible for what it publishes.
Get AI News in your inbox
New developer tools, model and agent releases, and how teams are actually using them to release software. Short, and only when there is something worth reading.
