Code search is hard

What makes code search hard

  • Code isn’t natural language: stop words, stemming, and token boundaries for things like a.toString() or sourceCode.toString() break standard FTS defaults.
  • Supporting substring queries (e.g., “ring” inside “toString”) causes index bloat and performance issues; trigrams reduce guesswork but inflate index sizes and can yield false positives.
  • There’s tension between index size, update cost, false positives, and the need for contextual results.

Indexes, trigrams, and databases

  • Trigram-based indexing (e.g., Postgres pg_trgm) can severely bloat indexes on frequently updated data.
  • Some advocate Postgres FTS (with custom analyzers, tsvector “plain”, RUM, summarization/“compass” tables, sharding) as sufficient and simpler to operate than separate search clusters.
  • Others argue dedicated engines (Lucene/Tantivy, Elasticsearch, Vespa, ParadeDB-on-Postgres) provide richer analyzers, typo tolerance, and better scaling, at higher operational cost.
  • Indexing time vs ingest speed is a recurring trade-off; “when to index” is as important as “what to index.”

Brute-force and “do the dumb thing first”

  • Several commenters note how far brute-force (ripgrep-like) search goes, especially when you only need the first N matches or work on modest corpora.
  • Strategy suggested: start with brute-force; add indexing only when real workloads show it’s needed.

Search engines and tools compared

  • Zoekt, Livegrep, Hound, OpenGrok, Debian DCS, Vespa, and elastic-based setups are all discussed.
  • Zoekt is praised for per-repo indexing and scalability; Livegrep for clean design but criticized for monolithic indexes and scaling issues.
  • Hound’s unbounded responses can be slow/DoS-like. OpenGrok is considered powerful but dated in UI.
  • Sourcegraph (built atop Zoekt, SCIP/LSIF) is seen as closest to Google-level experience among public tools.

Semantic search, ASTs, and build integration

  • Many stress that “good” code search often means semantic navigation, not just text search.
  • Tree-sitter, Kythe, SCIP/LSIF, stack-graphs, ast-grep are mentioned as ways to get ASTs and cross-reference graphs.
  • Integration with a unified build system/monorepo (Google-style) gives precise symbol resolution, version context, and macro-aware navigation that open-source stacks rarely match.

LLMs and embeddings

  • Some propose vector embeddings for code; others report poor results because user queries rarely resemble target code semantically, and related code sections can be semantically dissimilar.
  • Embedding-based indexes are also seen as expensive to build at scale.

UX, scope, and developer workflow

  • Several emphasize defining query types, user intent, and expected results before choosing technology.
  • GitHub’s search is seen by some as powerful (especially with regex and path/lang filters), by others as clumsy or enshittified (login requirement, removed features).
  • Basic skills ladder suggested: Ctrl+F → ripgrep/grep → editor integration → eventually indexed search.

Val Town–specific ideas

  • Suggestions include: index parsed vals (AST tokens, names, comments), or export all public vals to a Git repo and rely on GitHub search or local ripgrep.
  • The author of Zoekt recommends starting Val Town with brute-force search plus incremental trigram indexing over older snippets.