Skip to content

Eliminate Implicit Per-Search Schema Fetches by Caching searchable_fields #5

@cferrys

Description

@cferrys

Summary

lib/Search.js currently performs an extra GET /collections/:name request during search() whenever the caller provides q but omits query_by, so the client can infer searchable_fields before issuing the actual search. In a high-performance search client, this hidden round trip turns one logical search into two network calls, increases tail latency, and adds avoidable load to the cluster.

Context

The hot path is in lib/Search.js inside _searchCollection(), where this.collections.get(collectionName) is called to populate queryParams.query_by if the caller did not pass it explicitly. That behavior is convenient, but it is expensive in the exact path that should be cheapest: user-facing query execution.

This is especially relevant now because the recent changes expand search-facing workflows and documentation, including SAM search/status usage in lib/SAM.js and README.md. As adoption grows, the current fallback will amplify p95/p99 latency and double request volume for callers who rely on the client’s inferred defaults.

For a RocksDB-backed search system, the client should avoid adding synchronous control-plane lookups to the query path unless absolutely necessary. Metadata lookup belongs in a cacheable preparation step, not on every request.

Proposed Implementation

  1. Add a collection schema cache keyed by collection name, storing at least searchable_fields and a timestamp/version.
  2. Resolve query_by from that cache in Search._searchCollection() instead of calling collections.get() on every search.
  3. Populate or refresh the cache on collection-oriented operations in lib/Collections.js such as get(), create(), and update(), and invalidate on delete().
  4. Add a configurable cache strategy:
    • default in-memory caching with TTL
    • optional disable_schema_cache for strict callers
    • optional strict_query_by mode that throws when query_by is missing and cache is cold
  5. Add tests covering:
    • repeated searches without query_by only trigger one schema fetch
    • cache invalidation after schema updates
    • graceful behavior on cold cache and metadata fetch failure

Impact

Addressing this removes an avoidable network hop from a core read path, which should reduce median and tail search latency, cut control-plane traffic, and make throughput scale more cleanly under load. It also makes client behavior more predictable: a search request should not silently depend on a second synchronous API call unless the caller explicitly asked for that tradeoff.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions