Repository navigation
Conversation
The evaluator now works on a record in whichever form it arrives in, a Gramps object or its raw data, and reads related records in the same form through a RecordReader: - ObjectReader (default) reads through db's object getters, so Gramps proxies and CacheProxyDb behave as before. - RawDataReader (opt-in) reads through get_raw_<table>_data and the table cursor, never building an object per record. Much faster on a database that cleans raw data directly, such as gramps-web-api's RestrictedDb. Both only use db's public methods, so a proxy's __getattr__ never forwards a read to the unfiltered database. Related records are cached per query in a bounded LRU cache. run_query no longer goes through GenericFilter, and turns only the final page into objects when no select is given. run_query_with_total returns the rows and the number of matches (ignoring after and limit, like compile_count_query) from one pass, so a paged caller no longer needs a second, unlimited run_query to count. Behavior change, matching the SQL path: a related record that doesn't read back (hidden or missing) is never counted in len(...) or any(...). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
CC: @DavidMStraub |
Contributor
|
Nice! |
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.
The evaluator path (
run_query,evaluate_where) can now read records as raw data instead of building a Gramps object for each one, andrun_query_with_totalreturns the number of matches from the same pass. For a guest in gramps-web-api with RestrictedDb (gramps-project/gramps-web-api#1107), this makes/query1.3–13× faster on a 100k-person tree. The default behavior, and so the Gramps addons, is unchanged in speed.Changes
Records in either form.
evaluate_whereandresolve_column_refwork on a Gramps object or its raw data, and never convert wholesale. Related records are read in the same form through aRecordReader:ObjectReader(the default) reads throughdb's object getters, as before, so Gramps proxies andCacheProxyDbbehave the same.RawDataReader(opt-in) reads throughget_raw_<table>_dataand the table cursor, and never builds an object per record.Both use only
db's public methods, so a proxy's__getattr__never forwards a read to the unfiltered database. Related records are cached per query in an LRU cache of 10,000 entries.run_queryno longer goes throughGenericFilter. It takes areader=argument, and turns only the final page into objects when noselectis given.run_query_with_totalreturns(rows, total). The total ignoresafterandlimit, likecompile_count_query.run_querykeeps its return type.Behavior change, matching the SQL path: a related record that doesn't read back (hidden or missing) is never counted in
len(...)orany(...). Before,any(...)andlen(...)without a condition still counted a related record the database hides (its getter returns None).What gramps-web-api can change
Once this is released and #1107 is merged,
_post_proxiedinresources/object_query.pycan use both:X-Total-Countthen comes fromtotal, and the second, unlimitedrun_querygoes away. Today that second call reads and cleans every record again whenever the matches span more than one page.RawDataReadersuitsRestrictedDb, which cleans raw data directly. On a Gramps proxy it would be slower, because the proxy builds the object anyway.gramps-object-query-languagebound needs to move to the release that has this.Performance
Guests on a 100k-person tree (shared PostgreSQL; about 91,000 of its people are visible to a guest). Before is GOQL 0.5.6's
run_querythroughRestrictedDb, which is what gramps-web-api does with #1107. After is this branch withRawDataReader. Median of 3 runs, before and after alternating,gc.collect()before each. Every run checked that both return the same records.gender == Person.FEMALEprimary_name.first_name == 'Mary'birth.date.sortval >= Date('Jan 1, 1950')like(birth.place.title, '%Texas%')any(children, given_name == 'Steve')like(place.title, '%Texas%')These times are for one full pass. Today a counted request spanning more than one page pays for a second full pass; with
run_query_with_totalit pays for one.childrengains the least. My guess, not profiled:RestrictedDbre-reads each parent family when it cleans a person fetched by handle (noted on #1107).Gramps' example tree, default reader, median ms of 7 runs. The
RawDataReadercolumn is new and has no "before". This run overlapped the 100k run; old and new alternated, so both sides saw the same load.PrivateProxyDbold → newCacheProxyDb(PrivateProxyDb)old → newRestrictedDbold → newRestrictedDb+RawDataReaderThe addons' path is a Gramps filter rule calling
evaluate_whereper record, as GOQLFilter'swhereexprrule.pydoes. It's within about 2% on every query, under bothPrivateProxyDbandCacheProxyDb(PrivateProxyDb), with the same matches.The largest slowdown is
childrenon a plain database, 61 → 67 ms. Holding the cached related records makes Python's garbage collection a little more expensive on queries where those records rarely repeat.About the cache:
like(place.title, …)took 13.6 s with 1,000 entries against 4.0 s with 10,000.events4.2 → 4.1 s,hop212.1 → 10.4 s,children19.8 → 16.9 s).Tests
limitandafterevaluate_wheregiving the same answer on raw data as on objectsREADME-query-language.mdanddocs/where_expr.md(82 queries), sorted and unsorted, on a plain database,PrivateProxyDbandRestrictedDb, with about 10% of records and their parts made private. Both readers were checked. 492 comparisons, 0 differences.The benchmark and parity scripts aren't in this PR, because they depend on local trees and paths. I can add cleaned-up versions if they're wanted.
🤖 Generated with Claude Code