Token API: server-side kNN /similarity endpoint + concurrency guard (don't starve live users)#1648
Open
JasonWildMe wants to merge 1 commit into
Open
Token API: server-side kNN /similarity endpoint + concurrency guard (don't starve live users)#1648JasonWildMe wants to merge 1 commit into
JasonWildMe wants to merge 1 commit into
Conversation
…st-scoped PITs Addresses the critical scaling bottleneck from live API feedback (downloading every 2152-float vector to find matches) AND the operator requirement that high-volume agents must not interfere with interactive Wildbook use. POST /api/v3/similarity (token, read-only): server-side k-NN re-identification — given an annotation the caller can see, return the most similar annotations with scores, WITHOUT shipping any vectors. Surfaces Wildbook's existing OpenSearch kNN. - Filtered ANN: ACL + same viewpoint + method/version + optional taxonomy/locationId scope + self/encounter exclusion all go INSIDE the native knn.filter (an outer bool.filter would post-filter ANN results). For non-admin, also an outer ACL wrap (defense in depth). Filtered nested kNN verified empirically on the deployed cluster. - Never returns vectors (_source excludes embeddings + defensive remove()). - No-oracle visibility gate on the query annotation (not-visible == not-found == 404). - Deterministic single-embedding resolution; viewpoint required (400 if null); k 1-100. - Re-ID metric wildbook_token_reid_queries_total, distinct from pipeline ID gauges. Concurrency guard (TokenApiConcurrency): per-instance semaphores bound how many token requests run at once so volume is unlimited but live users aren't starved. Wired into ALL token endpoints: SIMILARITY pool (default 2) for the heavy kNN; GENERAL pool (default 8) for search + media/resolve. AutoCloseable permit (no leak/over-release); best-effort metrics; instant 429 + Retry-After; inflight + rejected Prometheus gauges. Sizes via OpenSearch.properties (restart to resize). Request-scoped PITs (OpenSearch.queryPitPrivate): the similarity endpoint never touches the shared static PIT_CACHE, so a token call can't delete/race a PIT an interactive UI search is using. (Migrating existing token search/media-resolve to private PITs is the recommended fast-follow.) Specs Codex design-reviewed before implementation; code Codex-reviewed. Tests (46 across the touched suites): TokenApiConcurrencyTest (3); SimilarityApiTest (9: auth/ validation, embeddings-stripped, ambiguous-embedding 400, filtered-ANN shape + self-exclusion, no-oracle 404, 429 guard); MediaResolveApi + SearchApi GENERAL-guard 429 tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f8db3e3 to
d93749c
Compare
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 headline of the API-feedback series (MMF/Sharkbook): a server-side k-NN re-ID endpoint that kills the critical scaling bottleneck (no more downloading every 2,152-float vector — a 200-record page took ~176s), plus a concurrency guard so a high-volume agent can do unlimited work without crowding out interactive Wildbook users.
POST /api/v3/similarity(token, read-only)Given an annotation the caller can see, returns the most visually similar annotations with scores and no vectors — surfacing Wildbook's existing OpenSearch kNN.
viewpoint+method/methodVersion+ optionaltaxonomy/locationIdscope + self/encounter exclusion all go inside the nativeknn.filter(an outerbool.filterwould post-filter ANN results → recall loss/leak). Non-admins additionally get an outer ACL wrap (defense in depth). Filtered nested kNN was verified empirically on the live cluster (knn.filter honors nested and parent fields)._sourceexcludesembeddings+ defensiveremove()).viewpointrequired;k1–100.wildbook_token_reid_queries_total— this is user-run identification compute on our servers, kept distinct from the pipelinewildbook_identification_tasks*gauges.Concurrency guard (
TokenApiConcurrency) — "unlimited volume, no interference"Per-instance semaphores cap how many token requests run at once (not total volume); excess gets
429+Retry-After. Wired into all token endpoints: a tight SIMILARITY pool (default 2) for the heavy kNN, a GENERAL pool (default 8) for search +media/resolve. Only token requests are throttled — interactive session/UI traffic is never. AutoCloseable permits (no leak/over-release, released on every path incl. exceptions), best-effortinflight/rejectedPrometheus gauges. Sizes viaOpenSearch.properties(restart to resize).Request-scoped PITs (
OpenSearch.queryPitPrivate)The similarity endpoint uses a private point-in-time and never touches the shared static
PIT_CACHE, so a token call can't delete or race a PIT a live UI search is using.Process / tests
Both specs Codex design-reviewed before coding; code Codex-reviewed (3 rounds, converged). 46 tests across the touched suites:
TokenApiConcurrencyTest(3),SimilarityApiTest(9: auth/validation, embeddings-stripped, ambiguous-embedding 400, filtered-ANN shape + self-exclusion, no-oracle 404, 429), plus GENERAL-guard 429 tests onMediaResolveApi/SearchApi.Merge notes / fast-follows
SearchApi.javaandMediaResolveApi.java(guard wiring) andOpenSearch.java; expect small, easily-resolved conflicts with media/resolve: explicit per-ID status (identified/unidentified/no_image/unavailable/error) #1646/Token search: safe terms aggregations (+ explicit 400 for unsupported aggs) #1647 — resolve in favor of keeping both changes.search/media/resolvepaths toqueryPitPrivatetoo — today they delete sharedPIT_CACHEentries and can disrupt live UI searches even at low concurrency. This PR fixes that for the new endpoint and bounds concurrency everywhere; the PIT migration for the older paths is the remaining piece.🤖 Generated with Claude Code