Repository navigation
sqlitedb: make id, isa and regexp searches fast (port of DID-matlab#229) - #98
Merged
Merged
Conversation
NDI's most common searches -- base.id or isa daqsystem, ANDed with base.session_id, sometimes with a regexp -- searched every term over the whole branch and intersected the results, so the session term returned every document of the session and the regexp tested every document. Ported from DID-matlab#229 (dae960b..83a2bda): - _search_doc_ids searches the terms of an AND in rank order: base.id lookups, other terms, base.session_id, then terms that test every value (regexp, contains_string, hasmember, and the brute-force operations). It stops at the first term that matches nothing, and once the result is down to 1000 documents checks later terms against those only (docs.doc_id IN (...), CROSS JOIN order, INDEXED BY doc_data_doc_idx). A brute-force term given candidates loads only those documents. - ORed base.id lookups, nested to any depth, are one query per 1000 ids (_search_base_ids, _base_id_lookup_values). - Unrestricted 'isa' runs its regexp on the distinct superclass lists only, read from doc_data_field_value, instead of on every document. - _ensure_indexes now records whether the doc_data indexes exist (_search_indexes_ready) and leaves a database it cannot write to without them, where it used to fail to open; searches there run as before. DID-matlab now creates the same indexes under the same names. Synthetic database, 100,000 documents / 3M doc_data rows, main -> this: base.id AND session 0.177 s -> 0.0001 s OR of 9 ids AND session 0.181 s -> 0.0006 s isa daqsystem AND session 0.299 s -> 0.027 s isa AND session AND regexp 0.603 s -> 0.027 s Tests: tests/test_search_indexes.py (mirrors DID-matlab's TestSearchIndexes). Bridge: sqlitedb and database entries -> 83a2bda. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv7SxVR8MCu3MKpUvwwUia
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Port of VH-Lab/DID-matlab#229 (
dae960b..83a2bda).What was slow
NDI's most common searches combine
base.idorisa daqsystemwithbase.session_id, and sometimes aregexp._search_doc_idssearched every ANDed term over the whole branch, then intersected the results. So:isaran the Pythonregexp()on every document's superclass list;regexpterm tested every document.MATLAB measured 5.5 s for
isa daqsystemAND session on ~100,000 documents.What changed (
src/did/implementations/sqlitedb.py)_search_rank):base.idlookups;isa);base.session_id;regexp,contains_string,hasmember, and the operations Python brute-forces).docs.doc_id IN (...)and aCROSS JOINorder, withINDEXED BY doc_data_doc_idx(_search_query_head). A brute-force term given candidates loads only those documents.base.idlookups, nested to any depth, run as one query per 1000 ids (_search_base_ids,_base_id_lookup_values).isa(unrestricted) runs its regexp only on the distinct superclass lists, read fromdoc_data_field_value.LIMIT -1stops SQLite from pushing the regexp back onto every row._ensure_indexes_search_indexes_ready).doc_data_value,doc_data_field_value,doc_data_doc_idx), so a database touched by both carries one copy of each.Three deviations from MATLAB, none of which changes a result. All are recorded in the sqlitedb bridge
decision_log:Timings
Same synthetic database as the MATLAB PR: 100,000 docs, 3M
doc_datarows. Best of 3,mainvs this branch:base.idAND sessionisa daqsystemAND session (3 docs)isaAND session ANDbase.name regexp (.*)On first open, adding the indexes to an older database took 2.4–2.9 s.
maincreates them too.Tests
tests/test_search_indexes.pymirrors DID-matlab'sTestSearchIndexes. Its test database has 1,500 + 100 documents. It records the rows each search query returns. It covers:isaAND session, in either order: no query returns more rows thanisamatched;isa/~isagive the same results with and without the indexes;Locally, all pass:
black --checkandruff check;pytest: 817 passed, run withDID_BRIDGE_CHECK_STRICT=1;bin/check_bridge_coverage.py, all six checks, run against a full DID-matlab checkout of the PR branch.Bridge
sqlitedbanddatabaseentries →83a2bda.Ordering with the MATLAB PR:
claude/did-base-id-indexbranch. CI'sfetch-depth: 0checkout fetches all branches, so it resolves now. Merge DID-matlab#229 first.matlab_last_sync_hashis a commit in PORTING_INSTRUCTIONS.md).One existing limit, not changed here:
Query.to_search_structurerecurses once per OR level. So an OR of ~1,000 ids built left-to-right in a loop raisesRecursionErrorbefore the search runs.Generated by Claude Code