struct FieldId(u16); // 65K fields per index
struct FieldRegistry {
id_by_name: ahash::AHashMap<String, FieldId>,
names: Vec<String>,
}
// Storage pools key by FieldId:
pub field_index: SmallVec<[Arc<DocIdMap>; 4]>, // indexed by FieldId.0
pub vector_ids: Vec<(u64, FieldId)>, // (u64, u16) = 16 bytes (12 packed)
Round-3 perf push sub-issue (tracked under umbrella #536).
[M] Per-field
Stringkeys everywhere — wasted hashing & alloc when field count is tinyWhere:
QuantizedVectorPool.field_index: HashMap<String, ...>(
quantized_storage.rs:45);HnswIndexReader.prefetch_index: HashMap<String, ...>(
hnsw/reader.rs:64);vector_ids: Vec<(u64, String)>everywhere;FieldSearchInput.field: String.Current behavior: Every per-field lookup hashes a
String(or clones from&strvia
to_string()). In practice indexes have 1-10 vector fields per collection.Why it might be a bottleneck / risk: Memory waste from dual storage (each
(u64, String)tuple holds a copy of the field name). Hashing a 20-char field name is~50 cycles per call.
Reference precedent: Lucene interns field names to integer ords at segment open;
Tantivy uses
FieldId(u32); Qdrant uses payload schema IDs.Data structure (proposed):
Suggested direction: Introduce per-index
FieldRegistry. Storage pools indexed byFieldId.Stringonly at public API boundary.Risk / scope: Medium-Large diff; mechanical. Doubles per-field hot-loop speed, cuts
memory ~30 %.
ID:
VS-31— see~/.claude/tasks/laurus/20260523_perf_round3_audit/task_list.mdfor the full Round-3 issue list.