Skip to content

perf(vector/index): stop persisting the HNSW graph as redundant manual u64s; pack as CSR + variable-byte deltas #627

Description

@mosuka

Round-3 perf push sub-issue (tracked under umbrella #535).

[M] Stop persisting the HNSW graph as redundant manual u64s; pack as CSR + variable-byte deltas

  • Where: laurus/src/vector/index/hnsw/writer.rs:1259-1297
    (write path) and :417-485 (read path).

  • Current behaviour: graph dump is node_count u64 followed by
    per-node [doc_id u64, layer_count u32, per layer [neighbour_count u32, neighbours u64*]]. Every edge takes 8 bytes even though
    neighbour IDs are local to the segment and almost always <2^32. No
    compression at all.

  • Why it might be a bottleneck: I/O size is doubled vs Lucene's
    packed graph; cold-start mmap loads more pages than necessary. For a
    10 M-node segment with avg ~24 neighbours per node, the graph dump is
    ~2 GB at u64.

  • Reference precedent: Lucene99HnswVectorsFormat writes layer-0 as
    [delta(n) varint]* per node, sorted neighbours, plus a sparse upper
    layer dump. Qdrant uses bincode with u32 IDs over a length-prefixed
    layout.

  • Proposed layout (LVS2 graph section):

    per layer:
      offsets : Vec<u64> length n+1     // mmap-friendly random access
      edges   : Vec<u32>                // (sorted within node, delta-varint
                                        //  optional later)
    
  • Suggested direction: convert IDs to u32 (already proposed for
    CSR); store sorted-within-node neighbours so a future v3 can introduce
    delta-varint codes without breaking compatibility; align offsets
    array to 8 B for direct mmap. Combine with Add parallel search #1 and Add parallel index #2.

  • Risk / scope: format break; needs LVS2 magic; pairs naturally
    with the in-memory CSR change.



ID: VI-09 — see ~/.claude/tasks/laurus/20260523_perf_round3_audit/task_list.md for the full Round-3 issue list.

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