Skip to content

perf: FieldId(u16) registry across crates (drop HashMap<String, _> from hot paths) #685

Description

@mosuka

Cross-cutting data-structure rewrite tracked under #537.

Current state

Field names are kept as String everywhere on the hot path:

  • laurus/src/lexical/index/inverted/writer.rs:59: fields: HashMap<String, FieldOption>.
  • laurus/src/lexical/index/inverted/writer.rs:621: format!("{field}:{term}") per token.
  • laurus/src/vector/index/quantized_storage.rs:45: field_index: HashMap<String, Arc<HashMap<u64, u32>>>.
  • laurus/src/vector/index/hnsw/reader.rs:64,560: prefetch_index: HashMap<String, _>, vector_ids: Vec<(u64, String)>.
  • Per-vector field_name UTF-8 inline in segment records (quantized_io.rs:14-23).

Typical schemas have 1-10 fields per index; the String cost on every probe is pure waste.

Proposed direction

  • Introduce FieldId(u16) and FieldRegistry { id_by_name: AHashMap<String, FieldId>, names: Vec<String> } at segment/index open.
  • Lexical writer: Vec<(SmolStr, FieldOption)> indexed by FieldId.
  • Vector storage pools: SmallVec<[Arc<DocIdMap>; 4]> indexed by FieldId.0 as usize.
  • Per-segment field dictionary on disk (one string per id, varint-coded) so per-record payload references field by id only.
  • String field names retained only at the public API boundary.

Acceptance

  • Lexical writer hot path no longer calls format!.
  • Vector storage records drop the inline field_name UTF-8 (replaced by field_id: u16).
  • Per-query hashing on field name eliminated in HNSW/Flat/IVF search paths.

References

  • Lucene FieldInfos (interns to int fieldNumber).
  • Tantivy FieldId(u32).
  • Qdrant payload schema ids.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions