Commit 1acdf7b
committed
fix(pgvector): bound the get_recent scan when the filter is not pushdown-safe
PgVectorCollection.get_recent pushed the ORDER BY into SQL but passed
limit=None to _scroll whenever _requires_local_filter(where) was true, so
a filter like {"$or": [{"wing": "w1"}, {"wing": "w2"}]} dragged the whole
table across the wire to keep `limit` rows. Layer 1 never hits this (it
passes {"wing": ...} or None, both pushdown-safe), but get_recent is
public API and this is the shape a caller reaches for first.
The predicate still cannot ride along, but the ordering can, so instead
of one LIMIT-less scan the local-filter branch now walks the table
newest-first a SQL page at a time and stops at the first page that
completes the answer. On the common shape (a filter most rows match)
that is a single page. Details:
- Page stability. ORDER BY metadata->>field DESC NULLS LAST, id is a
total order because id is the primary key, so OFFSET paging is well
defined, matching the guarantee the existing ORDER BY id paging in
scroll_rows relies on. Rows are deduped by id so a concurrent insert
that shifts a row across a page boundary cannot return it twice. A
concurrent delete can still skip one row, which is inherent to OFFSET
paging and unchanged from the pre-existing paged get.
- Cap. The walk stops after 50,000 rows, so a filter matching almost
nothing in a huge table returns fewer than `limit` rows rather than
reading the table. Because the walk is newest-first, what it returns
is still the newest matching rows within the newest 50,000 records.
The pushdown branch keeps its unchanged SQL and stays exact.
- Projection. The post-filter reads only metadata, and this branch can
scan far more rows than it returns, so the document column is
projected out unless the caller asked for it.
Because the cap makes the non-pushdown path approximate where it used to
be exact, supports_recency_order is now spelled out rather than left to
read as a blanket promise: it covers the filters the backend can
evaluate in storage, which is every filter Layer 1 uses, and a backend
that bounds its non-pushdown walk must document the bound.
Also fixes two things the same diff introduced:
- BaseCollection.get_recent returned padding values for projections the
caller excluded, so include=["metadatas"] answered with a list of
empty strings for documents where pgvector answers with []. Worse,
include=["documents"] meant metadatas never came back, every sort key
collapsed to the same value and the sort silently did nothing.
metadatas are now always fetched because the sort reads order_field
out of them, and only returned when requested.
- The docstrings claimed the inexact branch re-sorted locally after
filtering, which it never did, and asserted filed_at is always UTC. It
is not: diary_ingest writes datetime.now(timezone.utc).isoformat() and
every other writer uses datetime.now().isoformat(), so on a host off
UTC the two sort against each other skewed by the local offset. That
predates this change (Layer 1 has compared filed_at as text since
#1630) and standardising the writers needs its own migration, so the
docs now name the limitation instead of denying it. The list of places
where the SQL order and recency_sort_key disagree also now includes
database collation, which the Python test double cannot emulate.
Tests: the reviewer's exact scenario (800 rows, an $or filter, limit=5)
asserting every scroll carries a SQL LIMIT and the rows requested stay
well under the table; a selective filter that has to page three times,
checking OFFSET advances and the order stays newest-first; the cap
stopping a filter that matches nothing; a row shifted across a page
boundary by a concurrent insert, which returns a duplicate without the
id dedupe; the document projection; and the base-class include
projection.1 parent fa60c79 commit 1acdf7b
5 files changed
Lines changed: 390 additions & 32 deletions
File tree
- mempalace/backends
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
362 | 362 | | |
363 | 363 | | |
364 | 364 | | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
365 | 375 | | |
366 | 376 | | |
367 | 377 | | |
| |||
540 | 550 | | |
541 | 551 | | |
542 | 552 | | |
543 | | - | |
544 | | - | |
| 553 | + | |
| 554 | + | |
545 | 555 | | |
546 | 556 | | |
547 | 557 | | |
548 | | - | |
549 | | - | |
550 | | - | |
551 | | - | |
552 | | - | |
553 | | - | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
554 | 577 | | |
555 | 578 | | |
556 | | - | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
557 | 586 | | |
558 | 587 | | |
559 | 588 | | |
560 | 589 | | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
561 | 595 | | |
562 | 596 | | |
563 | 597 | | |
| |||
566 | 600 | | |
567 | 601 | | |
568 | 602 | | |
569 | | - | |
| 603 | + | |
570 | 604 | | |
571 | 605 | | |
572 | 606 | | |
| |||
591 | 625 | | |
592 | 626 | | |
593 | 627 | | |
594 | | - | |
595 | | - | |
| 628 | + | |
| 629 | + | |
596 | 630 | | |
597 | 631 | | |
598 | 632 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
75 | 85 | | |
76 | 86 | | |
77 | 87 | | |
| |||
1211 | 1221 | | |
1212 | 1222 | | |
1213 | 1223 | | |
| 1224 | + | |
| 1225 | + | |
| 1226 | + | |
| 1227 | + | |
| 1228 | + | |
| 1229 | + | |
| 1230 | + | |
| 1231 | + | |
| 1232 | + | |
| 1233 | + | |
| 1234 | + | |
| 1235 | + | |
| 1236 | + | |
| 1237 | + | |
| 1238 | + | |
| 1239 | + | |
| 1240 | + | |
| 1241 | + | |
| 1242 | + | |
| 1243 | + | |
| 1244 | + | |
| 1245 | + | |
| 1246 | + | |
| 1247 | + | |
| 1248 | + | |
| 1249 | + | |
| 1250 | + | |
| 1251 | + | |
| 1252 | + | |
| 1253 | + | |
| 1254 | + | |
| 1255 | + | |
| 1256 | + | |
| 1257 | + | |
| 1258 | + | |
| 1259 | + | |
| 1260 | + | |
| 1261 | + | |
| 1262 | + | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
| 1266 | + | |
| 1267 | + | |
| 1268 | + | |
| 1269 | + | |
| 1270 | + | |
| 1271 | + | |
| 1272 | + | |
| 1273 | + | |
| 1274 | + | |
| 1275 | + | |
| 1276 | + | |
| 1277 | + | |
| 1278 | + | |
| 1279 | + | |
| 1280 | + | |
| 1281 | + | |
| 1282 | + | |
| 1283 | + | |
| 1284 | + | |
| 1285 | + | |
| 1286 | + | |
| 1287 | + | |
1214 | 1288 | | |
1215 | 1289 | | |
1216 | 1290 | | |
1217 | 1291 | | |
1218 | 1292 | | |
1219 | 1293 | | |
1220 | 1294 | | |
1221 | | - | |
1222 | | - | |
1223 | | - | |
1224 | | - | |
1225 | | - | |
1226 | | - | |
1227 | | - | |
1228 | | - | |
| 1295 | + | |
| 1296 | + | |
| 1297 | + | |
| 1298 | + | |
| 1299 | + | |
| 1300 | + | |
| 1301 | + | |
| 1302 | + | |
| 1303 | + | |
| 1304 | + | |
| 1305 | + | |
| 1306 | + | |
| 1307 | + | |
| 1308 | + | |
| 1309 | + | |
| 1310 | + | |
| 1311 | + | |
| 1312 | + | |
| 1313 | + | |
| 1314 | + | |
| 1315 | + | |
| 1316 | + | |
| 1317 | + | |
| 1318 | + | |
| 1319 | + | |
| 1320 | + | |
| 1321 | + | |
| 1322 | + | |
| 1323 | + | |
| 1324 | + | |
| 1325 | + | |
| 1326 | + | |
| 1327 | + | |
| 1328 | + | |
| 1329 | + | |
| 1330 | + | |
| 1331 | + | |
| 1332 | + | |
| 1333 | + | |
| 1334 | + | |
1229 | 1335 | | |
1230 | 1336 | | |
1231 | 1337 | | |
1232 | 1338 | | |
1233 | 1339 | | |
1234 | | - | |
1235 | | - | |
1236 | | - | |
1237 | | - | |
1238 | | - | |
1239 | | - | |
1240 | | - | |
1241 | | - | |
1242 | | - | |
| 1340 | + | |
| 1341 | + | |
| 1342 | + | |
| 1343 | + | |
| 1344 | + | |
| 1345 | + | |
| 1346 | + | |
| 1347 | + | |
| 1348 | + | |
| 1349 | + | |
| 1350 | + | |
| 1351 | + | |
| 1352 | + | |
| 1353 | + | |
| 1354 | + | |
| 1355 | + | |
| 1356 | + | |
| 1357 | + | |
| 1358 | + | |
| 1359 | + | |
| 1360 | + | |
| 1361 | + | |
| 1362 | + | |
1243 | 1363 | | |
1244 | 1364 | | |
1245 | 1365 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
556 | 556 | | |
557 | 557 | | |
558 | 558 | | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
559 | 611 | | |
560 | 612 | | |
561 | 613 | | |
| |||
0 commit comments