Experiment with ES|QL lookup joins for event and stack queries - #2511
Draft
ejsmith wants to merge 9 commits into
Draft
Experiment with ES|QL lookup joins for event and stack queries#2511ejsmith wants to merge 9 commits into
ejsmith wants to merge 9 commits into
Conversation
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.
Summary
/eventscontractGET /events?mode=stackfor the organization stack list andGET /events/count?mode=stackfor its chart and totals; no/stack-rollupsresource is introducedLOOKUP JOINwhenever their filter contains stack-only criteria such asstatus,is_fixed,is_regressed, oris_hiddenWhy pursue this
The current implementation makes stack-aware event searches into a client-side join:
termsaggregation and discard buckets until the requested page is reached.That creates a hard 20,000-stack cardinality cliff, extra network/heap/cache work, progressively more expensive deep pages, and shard-candidate accuracy concerns when ranking aggregation buckets. The same limitation affects the ordinary events endpoint whenever it filters by stack status, so solving only the stack page would leave the core problem in place.
The lookup index lets Elasticsearch execute the relationship directly:
This gives both pages one source of truth for mixed event/stack filters, eliminates the intermediate id list and its cache/inversion machinery, enforces deleted-stack exclusion in the join itself, and keeps cursor work page-sized as navigation moves deeper. It is a structural simplification rather than just a faster version of the existing aggregation workaround.
How much better
These are isolated Elasticsearch 9.5 runs on the same development machine, with two warmups and seven measured iterations in alternating order. They are synthetic query comparisons, not production capacity claims, but the grouped lookup pipeline used here is the same one measured by the benchmark.
5,000 stacks / 15,000 events / page size 25
25,000 stacks / 25,000 events / page size 25
The most important result is the shape of the work: page 100 remains near page-1 latency, and queries continue past the old 20,000-stack ceiling.
API and behavior
GET /events?mode=stackreturns ranked stack summaries and acceptstotal,users,first_occurrence, orlast_occurrencesort in either direction./eventsrequests automatically use the join for stack-only filters and otherwise retain the normal Foundatio repository path.GET /events/count?mode=stacksupplies stack-page totals/chart data. Ordinary event counts with stack filters also join; the currently supported joined aggregation shapes are the event dashboard andterms:tags./stacksrepository/search-after path because they do not aggregate events and do not need a join.Intentional contract changes
stack_recent,stack_frequent,stack_new, andstack_usersmodes are replaced bymode=stackplus explicit sort/filter parameters.page; callers usebefore/afterwithlimit.first_occurrencefilter rather than hiddenstack_newbehavior.Tradeoffs and prerequisites
index.mode=lookupand exactly one primary shard; production adoption therefore needs write-throughput and shard-size monitoring.date/-datesorting, while stack mode supports the four grouped metrics above.terms:tags; unsupported free-form aggregation shapes return 400 rather than silently falling back.COUNT_DISTINCTremains approximate, and live cursors can observe inserts/updates between requests.Verification
npm run validate: formatting/lint passed; Svelte diagnostics 0 errors, 0 warnings/next/and/api/v2/aboutsmoke checks returned 2007a26941f: version, frontend, full API coverage, Docker, and full Aspire/Playwright E2E jobs passedOfficial references: LOOKUP JOIN, lookup prerequisites, QSTR, BUCKET, COUNT_DISTINCT, and terms aggregation ordering.