Match search operators against assetsSummary instead of per-asset metadata - #2882
Match search operators against assetsSummary instead of per-asset metadata#2882bendichter wants to merge 2 commits into
Conversation
The species, approach, and technique operators matched per-asset metadata in the asset_search materialized view using jsonb_path_exists with a jsonpath built at runtime. That predicate cannot use any of the view's GIN indexes, so every such query sequential-scanned one row per asset and evaluated a regex against each row's metadata blob. Measured against production, `species:mouse` took 13.4 seconds while the date operators, which filter the Dandiset table directly, took 0.26 seconds. These three fields are already rolled up per version in `assetsSummary`, which is where the previously removed `standard:` operator was eventually pointed for the same reason. Match all of them against the version metadata instead. The scan is now one row per dandiset version rather than one row per asset, which is three to four orders of magnitude fewer rows. This changes the cross-key semantics from per-asset AND to dandiset-level AND: `species:mouse approach:electrophysiological` now matches a dandiset whose summary lists both, even if no single asset has both. For a dandiset listing search that is the more useful reading, and the tests were updated to pin it. Re-add `standard:`, which was removed in 05fda3c pending a decision on the right metadata source, and drop `file_type:`, whose remaining value is covered by `standard:`. Removing it takes AssetSearch out of this code path entirely, so `apply_search_filters` no longer needs the requesting user: visibility was already enforced by the view's base queryset, and these filters only narrow it. The faceted-search `file_type` parameter on DandisetSearchQueryParameterSerializer is a separate feature and is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
demo on local seed data: Screen.Recording.2026-08-05.at.3.33.30.PM.mov |
`variableMeasured` records the neurodata types present in a dandiset's assets (ElectricalSeries, Units, LFP, ImagingPlane, and so on). Sampling the archive, it is populated on roughly 77% of dandisets with 22 distinct values, which makes it the most useful remaining field in assetsSummary. It also answers a different question than the operators we already have: approach and technique describe how an experiment was conducted, while this describes what data structures are actually in the files. Unlike the other summary arrays, `variableMeasured` holds bare strings rather than objects with a `name`, so its jsonpath selects the array elements themselves. That is the only structural difference, so the lookup table now holds full paths and `_jsonpath_name_match` is renamed to `_jsonpath_match` to reflect that it no longer always matches a name. Named `variable:` rather than `variable_measured:` to follow the existing convention, where `technique:` comes from `measurementTechnique` and `standard:` from `dataStandard`. Underscores are used only by the date operators, where the suffix distinguishes before from after. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Added a I surveyed the archive before picking this one. Of the fields left in The one structural difference is that On naming: I went with For the record, the fields I looked at and skipped: |
Problem
The advanced search operators released recently are slow. Timed against production:
species:mouse created_after:2026-01-01species:mousecreated_after:2026-01-01mouse(free text)All of the cost is in
species:,approach:, andtechnique:. Those matched per-asset metadata in theasset_searchmaterialized view withjsonb_path_existsand a jsonpath built at runtime. A runtime-built jsonpath regex cannot use any of the view's GIN indexes, so each query sequential-scanned one row per asset and evaluated a regex against every row's metadata blob. Thevisible_to()embargo check added a correlated subquery per row on top of that. A comment infilters.pyhad flagged this risk when the operators were written.Change
species,approach, andtechniquenow match the version-levelassetsSummaryaggregation, which already rolls up exactly these three fields. The scan moves from one row per asset to one row per dandiset version, three to four orders of magnitude fewer rows. This is the same source thestandard:operator was pointed at in a232b1f for a related reason.While in here:
standard:, which was removed in 05fda3c pending a decision on the right metadata source. That decision is now made, and it matchesassetsSummary.dataStandard.file_type:. Its remaining value is covered bystandard:, and dropping it takesAssetSearchout of this code path entirely. Note this is only the search operator; the faceted-searchfile_typequery parameter onDandisetSearchQueryParameterSerializeris a separate feature and is untouched.apply_search_filtersno longer takes the requesting user. Visibility is enforced by the view's base queryset (get_visible_dandisets), and these filters only ever narrow it, so the per-row embargo subquery was redundant. The embargo test is retained and still passes.One consequence to be aware of:
assetsSummaryis recomputed during metadata aggregation rather than on every asset write, so results can lag slightly for a dandiset whose assets changed very recently.I have not re-measured latency against production data, since that requires the change to be deployed. The structural argument is the row-count reduction described above.
🤖 Generated with Claude Code