Rebuild missing SOLR content everywhere it is read, not just in term_info - #110
Merged
Conversation
Three things, all downstream of the same cause: records that reach the PDB
after the bulk indexer last completed have nothing in vfb_json, and the
`precompute live query results` job has not completed since 22 June.
## The query indexes went missing as silently as term_info did
Both hydration paths skipped an id whose document lacked the field, so the
rows AND the count came back short with nothing to say so. For the
connectivity queries that is not "fewer rows" -- it is a confident empty
answer. Measured before and after on the live backend:
FBbt_00110929 alpha/beta core Kenyon cell 0 rows -> 236
FBbt_00048273 wing bristle mechanosensory 0 rows -> 604
152 of 4,000 sampled connectivity classes are in that state. A user asking
what is downstream of a Kenyon cell was being told, with a straight face,
nothing.
Both call sites now collect what SOLR returned, work out which requested
ids have no usable entry, and rebuild those in one batched call through
the indexer's own query -- the same borrowed-not-copied approach as
term_info. Measured on the live PDB a rebuild costs one round trip rather
than per-id work: 1 id 0.37s, 50 ids 0.91s, 200 ids 0.80s, 500 ids 1.49s
(3 ms/id). So the whole missing set goes at once, capped at the indexer's
own REQUEST_BATCH_SIZE of 500 purely to stop a pathological expansion
stalling. The rebuilt payloads are returned in memory and used by the
current request, because the indexer writes with commitWithin 60s and
re-reading SOLR here would still miss.
Global coverage measured against each indexer's own parameter query:
anat_image_query 0.5% missing, up/downstream connectivity ~2.1%,
cluster_expression 0%, anat_query has 279 MORE documents than the
population (stale entries a fallback cannot fix -- only the bulk job
clearing them can).
## The term_info fallback never actually indexed anything
solr_client builds its update URL from SOLRserver/SOLRcollection, and a
VFBquery deployment sets neither, so get_solr_update_url() returned None
and send_solr_payload returned False without making a request. Confirmed
against live 1.22.49: get_term_info("VFB_00107fob") served a complete
document while id:VFB_00107fob stayed numFound 0 past the 60s
commitWithin. Both are now seeded from VFBquery's own pysolr client
alongside the PDB variables.
The tests missed it because the one write test set VFBQUERY_CACHE_ENABLED
false to prove the guard, and that guard short-circuits before the URL is
needed -- the path that would have caught it was the path the test
disabled.
## Two tests that asserted content, not contract
term_info_serialization_dataset asserted exactly 4 types; DataSets gained
stage labels and Ito2013 now has 5 (Adult). It asserts the types it is
about instead.
test_default_excludes_are_a_strict_subset_of_everything demanded a strict
decrease from excluding hemibrain and FAFB, which additionally requires
those datasets to hold rows for that particular term pair -- content, not
contract. Now asserts subset, which is what excluding a dataset actually
guarantees.
Note on scope: the anat_query / anat_image_query rebuilds are wired but
latent. The expansions those queries produce did not contain unindexed ids
in any case I could construct -- get_instances and get_images_neurons are
unchanged before and after. The demonstrated win is the connectivity path.
_bulk_fetch_per_instance_connectivity skipped instances with no cached result and warned that connected_n / pairwise_connections / total_weight would be "a slight underestimate". That is a wrong number presented as a real one. This miss is a different animal to the others here: it is not a gap in the bulk index but VFBquery's own @with_solr_cache never having been asked for that instance. So the fix is simply to ask -- get_neuron_neuron_connectivity is wrapped in the cache decorator, so computing a missing instance also fills the cache and the next caller pays nothing. Deliberately unbounded. An individual call should fix itself even if that call is slow, rather than return a quietly incomplete count; misses are rare enough for that to be safe (0 of 4,000 connectivity individuals sampled had no cached result, and the case that surfaced this was 1 of 794 instances under FBbt_00048273). Same principle applied to the query-index rebuild: BACKFILL_BATCH_SIZE replaces MAX_BACKFILL_IDS, and a missing set larger than one batch is now looped rather than truncated. Batching is what makes it cheap -- 500 ids in 1.49s against 0.37s for one -- so there is no reason to drop the tail. Verified live: FBbt_00048273 logs "Computing per-instance connectivity for 1 uncached instance(s)" and still returns its 604 rows.
…anch Fourth hydration path with the same silent skip. get_hierarchy batch-reads term_info from SOLR to work out each term's parents and did `continue` on a document that was not there. That did not just lose the term's own node: it lost everything beneath it, because nothing was ever appended to its parent's child list, so an unindexed term took its whole branch out of the tree with no error and no warning. Collect the documents first, rebuild any that are missing through the term_info fallback, then build the tree from the merged set.
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.
Rebuild missing SOLR content everywhere it is read, not just in term_info
#108 fixed
term_info. It turns out four hydration paths had the same silent skip, and one of them was worse than "incomplete".The connectivity queries were returning nothing
Not fewer rows — a confident empty answer. Before and after, live:
152 of 4,000 sampled connectivity classes are in that state. Someone asking what is downstream of a Kenyon cell was being told, with a straight face, nothing.
Four paths, one cause
Records that reach the PDB after the bulk indexer last completed have nothing in
vfb_json, andprecompute live query resultshas not completed since 22 June._owlery_query_to_resultsanat_query,anat_image_query_fetch_connectivity_entriesup/downstream_connectivity_query_bulk_fetch_per_instance_connectivity@with_solr_cacheentriesget_hierarchyterm_infoAll four now collect what SOLR returned, work out what is missing, rebuild it, and carry on.
How the rebuilds work
The first two borrow the indexer's own query, same as #108 — nothing re-implements the schema. Measured on the live PDB a rebuild costs one round trip rather than per-id work (1 id 0.37s, 50 ids 0.91s, 200 ids 0.80s, 500 ids 1.49s, 3 ms/id), so ids go in batches of the indexer's own
REQUEST_BATCH_SIZE. A set larger than one batch is looped, not truncated — dropping the tail would be the same quietly-short answer this PR exists to stop. Rebuilt payloads are returned in memory and used by the current request, because the write usescommitWithin60s.The per-instance connectivity miss is a different animal: not a gap in the bulk index but VFBquery's own result cache never having been asked for that instance. So the fix is to ask —
get_neuron_neuron_connectivityis cache-wrapped, so computing one also fills the cache. Deliberately unbounded: an individual call should fix itself even if that call is slow. Misses are rare enough for that to be safe — 0 of 4,000 connectivity individuals sampled had none, and the case that surfaced it was 1 of 794.#108 was serving but never indexing
solr_clientbuilds its update URL fromSOLRserver/SOLRcollectionand a VFBquery deployment sets neither, soget_solr_update_url()returnedNoneandsend_solr_payloadreturnedFalsewithout making a request. Confirmed against live 1.22.49:get_term_info("VFB_00107fob")served a complete document whileid:VFB_00107fobstayednumFound 0past the 60scommitWithin. Both are now seeded from VFBquery's own pysolr client.The tests missed it because the one write test set
VFBQUERY_CACHE_ENABLED=falseto prove the guard, and that guard short-circuits before the URL is needed — the path that would have caught it was the path the test disabled.Two tests that asserted content, not contract
term_info_serialization_datasetasserted exactly 4 types; DataSets gained stage labels andIto2013now has 5.test_default_excludes_are_a_strict_subset_of_everythingdemanded a strict decrease from excluding hemibrain and FAFB, which additionally requires those datasets to hold rows for that term pair — content, not contract. Both were failing onmain.Measured coverage
Population from each indexer's own
get_parameters_query, coverage from SOLR:anat_queryhaving 279 more documents than its population is stale entries for deprecated or removed classes. A fallback cannot fix that; only the bulk job clearing them can.How to test
pytest src/test/test_term_info_fallback.py src/test/test_hierarchy.py— 54 pass, and the fallback tests need no backend. The example suite is unchanged at 15/15.Scope note
The
anat_query/anat_image_queryrebuilds are wired but latent: the expansions those queries produce did not contain unindexed ids in any case I could construct, andget_instances/get_images_neuronsreturn identically before and after. The demonstrated wins are the connectivity and hierarchy paths.