Skip to content

Wave 4 / Search: index size (~455% of source) and query latency exceed #174 targets #358

Description

@dean0x

Summary

The search index misses two of the four #174 performance targets on a real repo:

#174 target Target Observed (this repo, 666 files / ~20 MB source) Status
Index size < 30% of source 91 MB total ≈ 455% of source ❌ ~15× over
Query latency < 50 ms 42–63 ms (temporal 53 ms, jaccard coupling 63 ms) ⚠️ marginal/over on a small repo
Index build (10k files) < 30s 666 files in 1.6s ⇒ ~24s/10k extrapolated ✅ (extrapolated)
Incremental update < 500ms not separately measured here

Index size is the headline: the on-disk index is ~4.5× the size of the source it indexes, against a target of under one-third. This reproduces on a pristine index, so it is inherent to the format, not accumulated cruft.

Severity

🟠 Performance / scalability. At ~4.5× source the index does not scale to large repos within the stated budget, and the oversized postings file directly inflates query latency (it must be mmap'd/scanned). Query latency is already at/over the 50 ms target on a small 666-file repo, so larger repos will exceed it.

Evidence

Per-file breakdown of the index for this repo (~/Library/Caches/skim/search/<hash>/, or a fresh SKIM_CACHE_DIR):

74M  index.skpost        <- lexical bigram postings (dominant)
11M  index.skfiles
3.7M ast_index.skcache
2.0M ast_index.skpost
182K ast_index.skidx
155K index.skidx
48K  temporal.db
---- ----
91M  total   (source tree, tracked, excl. .git/target = ~20 MB)

skim search --stats reports total n-grams : 9577index.skpost is ~74 MB / 9577 ≈ 7.7 KB per n-gram posting list.

Query latency (internal duration_ms from --json, 666-file index):

  • temporal → 53 ms
  • CompositeWeights6 → 42 ms
  • jaccard coupling → 63 ms
export SKIM_CACHE_DIR=/tmp/skim-repro
./target/release/skim search "lock" --limit 1 >/dev/null
du -sh "$SKIM_CACHE_DIR"/search/*/ ; ls -lah "$SKIM_CACHE_DIR"/search/*/
./target/release/skim search "temporal" --limit 20 --json | grep duration_ms

Root cause

Shared with #355 (lexical relevance): the lexical index is a byte-bigram index. There are ~65k possible bigrams and common code bigrams (re, in, er, …) occur in nearly every file at many positions, so their posting lists are enormous. Storing per-occurrence position data for these high-frequency bigrams is what bloats index.skpost to 74 MB. The same coarseness that makes bigrams non-selective for ranking makes their posting lists huge.

→ Whatever n-gram-width / tokenization change is chosen for the relevance issue (#355) will change this size profile substantially, so the two should be designed together. But there are also size wins available independent of relevance (see below).

Design directions for a fix (needs design + measurement)

  • Address jointly with the lexical-relevance fix. Trigrams/token-aware grams have far fewer, far shorter high-frequency posting lists.
  • Compress postings: delta + varint (or PForDelta/Roaring) encoding of doc-id and position lists; this is standard for inverted indexes and typically yields multiple-× reductions.
  • Reconsider storing per-occurrence positions for high-frequency grams (or cap/skip positions above a frequency threshold) — positions are the bulk of the bytes.
  • Prune the lowest-IDF grams entirely (they carry no ranking signal but dominate size).
  • Re-measure all four North Star: 3-Layer Code Search System (skim search) #174 targets after the relevance redesign; treat the targets as acceptance gates.

Acceptance criteria

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsearchCode search featurewave-4Wave 4: Compound queries

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions