[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"readme:pg-jev":3},"\u003Cp align=\"center\">\n  \u003Cimg src=\"https:\u002F\u002Fraw.githubusercontent.com\u002FrealZachi\u002Fpg-jev\u002FHEAD\u002Fdocs\u002Fassets\u002Fheader.svg\" alt=\"pg-jev — ask your Postgres tables questions in plain language\" width=\"100%\" \u002F>\n\u003C\u002Fp>\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Ftrendshift.io\u002Frepositories\u002F244185?utm_source=trendshift-badge&amp;utm_medium=badge&amp;utm_campaign=badge-trendshift-244185\" rel=\"nofollow ugc noopener\">\u003Cimg src=\"https:\u002F\u002Ftrendshift.io\u002Fapi\u002Fbadge\u002Ftrendshift\u002Frepositories\u002F244185\u002Fdaily?language=Python\" alt=\"realZachi%2Fpg-jev | Trendshift\" width=\"250\" height=\"55\" \u002F>\u003C\u002Fa>\n\u003C\u002Fp>\u003Ch1>jev — ask your Postgres tables questions in plain language\u003C\u002Fh1>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FrealZachi\u002Fpg-jev\u002Factions\u002Fworkflows\u002Fci.yml\" rel=\"nofollow ugc noopener\">\u003Cimg src=\"https:\u002F\u002Fgithub.com\u002FrealZachi\u002Fpg-jev\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg\" alt=\"CI\" \u002F>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fpgxn.org\u002Fdist\u002Fjev\u002F\" rel=\"nofollow ugc noopener\">\u003Cimg src=\"https:\u002F\u002Fbadge.fury.io\u002Fpg\u002Fjev.svg\" alt=\"PGXN\" \u002F>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FrealZachi\u002Fpg-jev\u002Fblob\u002FHEAD\u002FLICENSE\" rel=\"nofollow ugc noopener\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-PostgreSQL-blue.svg\" alt=\"License\" \u002F>\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fpgjev.com\" rel=\"nofollow ugc noopener\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fwebsite-pgjev.com-0a56cf.svg\" alt=\"Website\" \u002F>\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>Write the condition the way you would say it. Postgres does the rest.\u003C\u002Fp>\n\u003Cp>\u003Ccode>jev\u003C\u002Fcode> lets you filter, rank and classify rows with plain-language conditions. Every row is judged by\n\u003Ca href=\"https:\u002F\u002Fdocs.typesafe.ai\" rel=\"nofollow ugc noopener\">TypeSafe's Jev\u003C\u002Fa>, a System One model that returns calibrated probabilities\ninstead of generated text. No index, no embeddings, no vector column.\u003C\u002Fp>\n\u003Cp>Website: \u003Ca href=\"https:\u002F\u002Fpgjev.com\" rel=\"nofollow ugc noopener\">pgjev.com\u003C\u002Fa>\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">CREATE EXTENSION jev CASCADE;\n\nSELECT * FROM people WHERE jev(people, 'the name is European');\n\nSELECT subject, jev_prob(tickets, 'the customer is angry') AS p\nFROM tickets ORDER BY p DESC LIMIT 20;\n\nSELECT jev_choice(tickets, 'which team should handle this?',\n                  ARRAY['billing', 'technical', 'security', 'sales']) AS team, count(*)\nFROM tickets GROUP BY 1;\n\nSELECT name, jev_score(products, 'how luxurious is this product?',\n                       ARRAY['budget', 'mid-range', 'premium', 'luxury']) AS luxury\nFROM products ORDER BY luxury DESC;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Ccode>jev()\u003C\u002Fcode> is an ordinary boolean function, so it composes with everything else in SQL: \u003Ccode>AND age &gt; 40\u003C\u002Fcode>,\njoins, \u003Ccode>GROUP BY\u003C\u002Fcode>, \u003Ccode>LIMIT\u003C\u002Fcode>, \u003Ccode>ORDER BY jev_prob(...)\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2>How it works\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Ccode>jev(table, 'condition')\u003C\u002Fcode> receives the row as a composite value. The first call for a table + condition starts a\nread-ahead that streams the table in physical order (TID range scans; \u003Ccode>OFFSET\u003C\u002Fcode> pages for views).\n\u003Ccode>jev.max_prefetch_rows\u003C\u002Fcode> limits how far it searches for a requested row and how many skipped rows it retains; it\ndoes not limit the answer cache or total session memory.\u003C\u002Fli>\n\u003Cli>Rows are packed \u003Ccode>jev.batch_size\u003C\u002Fcode> (20) per request into one shared \u003Cem>state\u003C\u002Fem>\n(\u003Ccode>{\"condition\": ..., \"rows\": [...]}\u003C\u002Fcode>) with one yes\u002Fno \u003Ca href=\"https:\u002F\u002Fdocs.typesafe.ai\u002Fprimitives\u002Fnoul\" rel=\"nofollow ugc noopener\">Noul\u003C\u002Fa>\nquestion per row. Jev evaluates all questions over one state in parallel, which amortises the ~270-token\nrequest overhead (about 435 tokens for one row alone vs 175 per row in batches of 20).\u003C\u002Fli>\n\u003Cli>Up to 2 × \u003Ccode>jev.concurrency\u003C\u002Fcode> requests are in flight over persistent HTTPS connections, and every row is answered\nas soon as its batch returns, so a \u003Ccode>LIMIT\u003C\u002Fcode> stops the read-ahead after the in-flight window, and rows that cheaper\npredicates filter out before \u003Ccode>jev()\u003C\u002Fcode> runs (\u003Ccode>WHERE age &gt; 60 AND jev(...)\u003C\u002Fcode>) are skipped rather than judged.\u003C\u002Fli>\n\u003Cli>Answers are cached per row content and question for the backend session, so re-running, changing the threshold or\nsorting by probability is free while those answers remain cached. The cache can grow with unique row\u002Fquestion\npairs until \u003Ccode>jev_cache_clear()\u003C\u002Fcode> clears it or the backend session ends. Rows from a subquery or CTE (anonymous\n\u003Ccode>record\u003C\u002Fcode> type) can't be read ahead and are judged one request at a time; put \u003Ccode>jev()\u003C\u002Fcode> on base tables or views when\nyou can.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Measured on a 2,000-row table from Europe (~190 ms to the API): first run ≈ 3.5 s in 100 requests, ≈ 296k input\ntokens, ≈ $0.012; second run ≈ 50 ms; \u003Ccode>LIMIT 3\u003C\u002Fcode> on a new condition ≈ 0.6 s. A new condition in a session that\nstill holds its pooled connections (idle for less than \u003Ccode>jev.keepalive\u003C\u002Fcode>) takes ≈ 2.3 s: the fir\u003C\u002Fp>\n",1793926097382]