hermes_core/segment/
vector_data.rs1use std::mem::size_of;
4
5use serde::{Deserialize, Serialize};
6
7const FLAT_BINARY_MAGIC: u32 = 0x46564432;
9
10const FLAT_BINARY_HEADER_SIZE: usize = 3 * size_of::<u32>();
12const FLOAT_SIZE: usize = size_of::<f32>();
14const DOC_ID_ENTRY_SIZE: usize = size_of::<u32>() + size_of::<u16>();
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct FlatVectorData {
20 pub dim: usize,
21 pub vectors: Vec<Vec<f32>>,
22 pub doc_ids: Vec<(u32, u16)>,
25}
26
27impl FlatVectorData {
28 pub fn estimated_memory_bytes(&self) -> usize {
30 let vec_overhead = size_of::<Vec<f32>>();
31 let vectors_bytes: usize = self
32 .vectors
33 .iter()
34 .map(|v| v.capacity() * FLOAT_SIZE + vec_overhead)
35 .sum();
36 let doc_ids_bytes = self.doc_ids.capacity() * size_of::<(u32, u16)>();
37 vectors_bytes + doc_ids_bytes + vec_overhead * 2
38 }
39
40 pub fn to_binary_bytes(&self) -> Vec<u8> {
45 let num_vectors = self.doc_ids.len();
46 let total = Self::serialized_binary_size(self.dim, num_vectors);
47 let mut buf = Vec::with_capacity(total);
48
49 buf.extend_from_slice(&FLAT_BINARY_MAGIC.to_le_bytes());
50 buf.extend_from_slice(&(self.dim as u32).to_le_bytes());
51 buf.extend_from_slice(&(num_vectors as u32).to_le_bytes());
52
53 for vec in &self.vectors {
54 for &val in vec {
55 buf.extend_from_slice(&val.to_le_bytes());
56 }
57 }
58
59 for &(doc_id, ordinal) in &self.doc_ids {
60 buf.extend_from_slice(&doc_id.to_le_bytes());
61 buf.extend_from_slice(&ordinal.to_le_bytes());
62 }
63
64 buf
65 }
66
67 pub fn serialized_binary_size(index_dim: usize, num_vectors: usize) -> usize {
69 FLAT_BINARY_HEADER_SIZE
70 + num_vectors * index_dim * FLOAT_SIZE
71 + num_vectors * DOC_ID_ENTRY_SIZE
72 }
73
74 pub fn serialize_binary_from_flat_streaming(
79 index_dim: usize,
80 flat_vectors: &[f32],
81 original_dim: usize,
82 doc_ids: &[(u32, u16)],
83 writer: &mut dyn std::io::Write,
84 ) -> std::io::Result<()> {
85 let num_vectors = doc_ids.len();
86
87 writer.write_all(&FLAT_BINARY_MAGIC.to_le_bytes())?;
88 writer.write_all(&(index_dim as u32).to_le_bytes())?;
89 writer.write_all(&(num_vectors as u32).to_le_bytes())?;
90
91 if index_dim == original_dim {
92 let bytes: &[u8] = unsafe {
95 std::slice::from_raw_parts(
96 flat_vectors.as_ptr() as *const u8,
97 flat_vectors.len() * FLOAT_SIZE,
98 )
99 };
100 writer.write_all(bytes)?;
101 } else {
102 for i in 0..num_vectors {
104 let start = i * original_dim;
105 let slice = &flat_vectors[start..start + index_dim];
106 let bytes: &[u8] = unsafe {
107 std::slice::from_raw_parts(slice.as_ptr() as *const u8, index_dim * FLOAT_SIZE)
108 };
109 writer.write_all(bytes)?;
110 }
111 }
112
113 for &(doc_id, ordinal) in doc_ids {
114 writer.write_all(&doc_id.to_le_bytes())?;
115 writer.write_all(&ordinal.to_le_bytes())?;
116 }
117
118 Ok(())
119 }
120
121 pub fn from_binary_bytes(data: &[u8]) -> std::io::Result<Self> {
123 if data.len() < FLAT_BINARY_HEADER_SIZE {
124 return Err(std::io::Error::new(
125 std::io::ErrorKind::InvalidData,
126 "FlatVectorData binary too short",
127 ));
128 }
129
130 let magic = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
131 if magic != FLAT_BINARY_MAGIC {
132 return Err(std::io::Error::new(
133 std::io::ErrorKind::InvalidData,
134 "Invalid FlatVectorData binary magic",
135 ));
136 }
137
138 let dim = u32::from_le_bytes([data[4], data[5], data[6], data[7]]) as usize;
139 let num_vectors = u32::from_le_bytes([data[8], data[9], data[10], data[11]]) as usize;
140
141 let vectors_start = FLAT_BINARY_HEADER_SIZE;
142 let vectors_byte_len = num_vectors * dim * FLOAT_SIZE;
143 let doc_ids_start = vectors_start + vectors_byte_len;
144 let doc_ids_byte_len = num_vectors * DOC_ID_ENTRY_SIZE;
145
146 if data.len() < doc_ids_start + doc_ids_byte_len {
147 return Err(std::io::Error::new(
148 std::io::ErrorKind::InvalidData,
149 "FlatVectorData binary truncated",
150 ));
151 }
152
153 let mut vectors = Vec::with_capacity(num_vectors);
154 for i in 0..num_vectors {
155 let mut vec = Vec::with_capacity(dim);
156 let base = vectors_start + i * dim * FLOAT_SIZE;
157 for j in 0..dim {
158 let off = base + j * FLOAT_SIZE;
159 vec.push(f32::from_le_bytes([
160 data[off],
161 data[off + 1],
162 data[off + 2],
163 data[off + 3],
164 ]));
165 }
166 vectors.push(vec);
167 }
168
169 let mut doc_ids = Vec::with_capacity(num_vectors);
170 for i in 0..num_vectors {
171 let off = doc_ids_start + i * DOC_ID_ENTRY_SIZE;
172 let doc_id =
173 u32::from_le_bytes([data[off], data[off + 1], data[off + 2], data[off + 3]]);
174 let ordinal = u16::from_le_bytes([data[off + 4], data[off + 5]]);
175 doc_ids.push((doc_id, ordinal));
176 }
177
178 Ok(FlatVectorData {
179 dim,
180 vectors,
181 doc_ids,
182 })
183 }
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct IVFRaBitQIndexData {
189 pub index: crate::structures::IVFRaBitQIndex,
190 pub centroids: crate::structures::CoarseCentroids,
191 pub codebook: crate::structures::RaBitQCodebook,
192}
193
194impl IVFRaBitQIndexData {
195 pub fn to_bytes(&self) -> std::io::Result<Vec<u8>> {
196 serde_json::to_vec(self)
197 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
198 }
199
200 pub fn from_bytes(data: &[u8]) -> std::io::Result<Self> {
201 serde_json::from_slice(data)
202 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
203 }
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct ScaNNIndexData {
209 pub index: crate::structures::IVFPQIndex,
210 pub centroids: crate::structures::CoarseCentroids,
211 pub codebook: crate::structures::PQCodebook,
212}
213
214impl ScaNNIndexData {
215 pub fn to_bytes(&self) -> std::io::Result<Vec<u8>> {
216 serde_json::to_vec(self)
217 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
218 }
219
220 pub fn from_bytes(data: &[u8]) -> std::io::Result<Self> {
221 serde_json::from_slice(data)
222 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
223 }
224}