1use std::sync::Arc;
5
6use super::index::FlatMetadata;
7use crate::frag_reuse::FragReuseIndex;
8use crate::vector::quantizer::QuantizerStorage;
9use crate::vector::storage::{DistCalculator, VectorStore};
10use crate::vector::utils::do_prefetch;
11use arrow::array::AsArray;
12use arrow::compute::concat_batches;
13use arrow::datatypes::UInt8Type;
14use arrow_array::ArrowPrimitiveType;
15use arrow_array::{
16 Array, ArrayRef, FixedSizeListArray, RecordBatch, UInt64Array,
17 types::{Float32Type, UInt64Type},
18};
19use arrow_schema::SchemaRef;
20use deepsize::DeepSizeOf;
21use lance_core::{Error, ROW_ID, Result};
22use lance_file::previous::reader::FileReader as PreviousFileReader;
23use lance_linalg::distance::DistanceType;
24use lance_linalg::distance::hamming::hamming;
25
26pub const FLAT_COLUMN: &str = "flat";
27
28#[derive(Debug, Clone)]
30pub struct FlatFloatStorage {
31 metadata: FlatMetadata,
32 batch: RecordBatch,
33 distance_type: DistanceType,
34
35 pub(super) row_ids: Arc<UInt64Array>,
37 vectors: Arc<FixedSizeListArray>,
38}
39
40impl DeepSizeOf for FlatFloatStorage {
41 fn deep_size_of_children(&self, _: &mut deepsize::Context) -> usize {
42 self.batch.get_array_memory_size()
43 }
44}
45
46#[async_trait::async_trait]
47impl QuantizerStorage for FlatFloatStorage {
48 type Metadata = FlatMetadata;
49
50 fn try_from_batch(
51 batch: RecordBatch,
52 metadata: &Self::Metadata,
53 distance_type: DistanceType,
54 frag_reuse_index: Option<Arc<FragReuseIndex>>,
55 ) -> Result<Self> {
56 let batch = if let Some(frag_reuse_index_ref) = frag_reuse_index.as_ref() {
57 frag_reuse_index_ref.remap_row_ids_record_batch(batch, 0)?
58 } else {
59 batch
60 };
61
62 let row_ids = Arc::new(
63 batch
64 .column_by_name(ROW_ID)
65 .ok_or(Error::schema(format!("column {} not found", ROW_ID)))?
66 .as_primitive::<UInt64Type>()
67 .clone(),
68 );
69 let vectors = Arc::new(
70 batch
71 .column_by_name(FLAT_COLUMN)
72 .ok_or(Error::schema("column flat not found".to_string()))?
73 .as_fixed_size_list()
74 .clone(),
75 );
76 Ok(Self {
77 metadata: metadata.clone(),
78 batch,
79 distance_type,
80 row_ids,
81 vectors,
82 })
83 }
84
85 fn metadata(&self) -> &Self::Metadata {
86 &self.metadata
87 }
88
89 async fn load_partition(
90 _: &PreviousFileReader,
91 _: std::ops::Range<usize>,
92 _: DistanceType,
93 _: &Self::Metadata,
94 _: Option<Arc<FragReuseIndex>>,
95 ) -> Result<Self> {
96 unimplemented!("Flat will be used in new index builder which doesn't require this")
97 }
98}
99
100impl FlatFloatStorage {
101 pub fn new(vectors: FixedSizeListArray, distance_type: DistanceType) -> Self {
103 let row_ids = Arc::new(UInt64Array::from_iter_values(0..vectors.len() as u64));
104 let vectors = Arc::new(vectors);
105
106 let batch = RecordBatch::try_from_iter_with_nullable(vec![
107 (ROW_ID, row_ids.clone() as ArrayRef, true),
108 (FLAT_COLUMN, vectors.clone() as ArrayRef, true),
109 ])
110 .unwrap();
111
112 Self {
113 metadata: FlatMetadata {
114 dim: vectors.value_length() as usize,
115 },
116 batch,
117 distance_type,
118 row_ids,
119 vectors,
120 }
121 }
122
123 pub fn vector(&self, id: u32) -> ArrayRef {
124 self.vectors.value(id as usize)
125 }
126}
127
128impl VectorStore for FlatFloatStorage {
129 type DistanceCalculator<'a> = FlatDistanceCal<'a, Float32Type>;
130
131 fn to_batches(&self) -> Result<impl Iterator<Item = RecordBatch>> {
132 Ok([self.batch.clone()].into_iter())
133 }
134
135 fn append_batch(&self, batch: RecordBatch, _vector_column: &str) -> Result<Self> {
136 let new_batch = concat_batches(&batch.schema(), vec![&self.batch, &batch].into_iter())?;
138 let mut storage = self.clone();
139 storage.batch = new_batch;
140 Ok(storage)
141 }
142
143 fn schema(&self) -> &SchemaRef {
144 self.batch.schema_ref()
145 }
146
147 fn as_any(&self) -> &dyn std::any::Any {
148 self
149 }
150
151 fn len(&self) -> usize {
152 self.vectors.len()
153 }
154
155 fn distance_type(&self) -> DistanceType {
156 self.distance_type
157 }
158
159 fn row_id(&self, id: u32) -> u64 {
160 self.row_ids.values()[id as usize]
161 }
162
163 fn row_ids(&self) -> impl Iterator<Item = &u64> {
164 self.row_ids.values().iter()
165 }
166
167 fn dist_calculator(&self, query: ArrayRef, _dist_q_c: f32) -> Self::DistanceCalculator<'_> {
168 Self::DistanceCalculator::new(self.vectors.as_ref(), query, self.distance_type)
169 }
170
171 fn dist_calculator_from_id(&self, id: u32) -> Self::DistanceCalculator<'_> {
172 Self::DistanceCalculator::new(
173 self.vectors.as_ref(),
174 self.vectors.value(id as usize),
175 self.distance_type,
176 )
177 }
178}
179
180#[derive(Debug, Clone)]
182pub struct FlatBinStorage {
183 metadata: FlatMetadata,
184 batch: RecordBatch,
185 distance_type: DistanceType,
186
187 pub(super) row_ids: Arc<UInt64Array>,
189 vectors: Arc<FixedSizeListArray>,
190}
191
192impl DeepSizeOf for FlatBinStorage {
193 fn deep_size_of_children(&self, _: &mut deepsize::Context) -> usize {
194 self.batch.get_array_memory_size()
195 }
196}
197
198#[async_trait::async_trait]
199impl QuantizerStorage for FlatBinStorage {
200 type Metadata = FlatMetadata;
201
202 fn try_from_batch(
203 batch: RecordBatch,
204 metadata: &Self::Metadata,
205 distance_type: DistanceType,
206 frag_reuse_index: Option<Arc<FragReuseIndex>>,
207 ) -> Result<Self> {
208 let batch = if let Some(frag_reuse_index_ref) = frag_reuse_index.as_ref() {
209 frag_reuse_index_ref.remap_row_ids_record_batch(batch, 0)?
210 } else {
211 batch
212 };
213
214 let row_ids = Arc::new(
215 batch
216 .column_by_name(ROW_ID)
217 .ok_or(Error::schema(format!("column {} not found", ROW_ID)))?
218 .as_primitive::<UInt64Type>()
219 .clone(),
220 );
221 let vectors = Arc::new(
222 batch
223 .column_by_name(FLAT_COLUMN)
224 .ok_or(Error::schema("column flat not found".to_string()))?
225 .as_fixed_size_list()
226 .clone(),
227 );
228 Ok(Self {
229 metadata: metadata.clone(),
230 batch,
231 distance_type,
232 row_ids,
233 vectors,
234 })
235 }
236
237 fn metadata(&self) -> &Self::Metadata {
238 &self.metadata
239 }
240
241 async fn load_partition(
242 _: &PreviousFileReader,
243 _: std::ops::Range<usize>,
244 _: DistanceType,
245 _: &Self::Metadata,
246 _: Option<Arc<FragReuseIndex>>,
247 ) -> Result<Self> {
248 unimplemented!("Flat will be used in new index builder which doesn't require this")
249 }
250}
251
252impl FlatBinStorage {
253 pub fn new(vectors: FixedSizeListArray, distance_type: DistanceType) -> Self {
255 let row_ids = Arc::new(UInt64Array::from_iter_values(0..vectors.len() as u64));
256 let vectors = Arc::new(vectors);
257
258 let batch = RecordBatch::try_from_iter_with_nullable(vec![
259 (ROW_ID, row_ids.clone() as ArrayRef, true),
260 (FLAT_COLUMN, vectors.clone() as ArrayRef, true),
261 ])
262 .unwrap();
263
264 Self {
265 metadata: FlatMetadata {
266 dim: vectors.value_length() as usize,
267 },
268 batch,
269 distance_type,
270 row_ids,
271 vectors,
272 }
273 }
274
275 pub fn vector(&self, id: u32) -> ArrayRef {
276 self.vectors.value(id as usize)
277 }
278}
279
280impl VectorStore for FlatBinStorage {
281 type DistanceCalculator<'a> = FlatDistanceCal<'a, UInt8Type>;
282
283 fn to_batches(&self) -> Result<impl Iterator<Item = RecordBatch>> {
284 Ok([self.batch.clone()].into_iter())
285 }
286
287 fn append_batch(&self, batch: RecordBatch, _vector_column: &str) -> Result<Self> {
288 let new_batch = concat_batches(&batch.schema(), vec![&self.batch, &batch].into_iter())?;
290 let mut storage = self.clone();
291 storage.batch = new_batch;
292 Ok(storage)
293 }
294
295 fn schema(&self) -> &SchemaRef {
296 self.batch.schema_ref()
297 }
298
299 fn as_any(&self) -> &dyn std::any::Any {
300 self
301 }
302
303 fn len(&self) -> usize {
304 self.vectors.len()
305 }
306
307 fn distance_type(&self) -> DistanceType {
308 self.distance_type
309 }
310
311 fn row_id(&self, id: u32) -> u64 {
312 self.row_ids.values()[id as usize]
313 }
314
315 fn row_ids(&self) -> impl Iterator<Item = &u64> {
316 self.row_ids.values().iter()
317 }
318
319 fn dist_calculator(&self, query: ArrayRef, _dist_q_c: f32) -> Self::DistanceCalculator<'_> {
320 Self::DistanceCalculator::new(self.vectors.as_ref(), query, self.distance_type)
321 }
322
323 fn dist_calculator_from_id(&self, id: u32) -> Self::DistanceCalculator<'_> {
324 Self::DistanceCalculator::new(
325 self.vectors.as_ref(),
326 self.vectors.value(id as usize),
327 self.distance_type,
328 )
329 }
330}
331
332pub struct FlatDistanceCal<'a, T: ArrowPrimitiveType> {
333 vectors: &'a [T::Native],
334 query: Vec<T::Native>,
335 dimension: usize,
336 #[allow(clippy::type_complexity)]
337 distance_fn: fn(&[T::Native], &[T::Native]) -> f32,
338}
339
340impl<'a> FlatDistanceCal<'a, Float32Type> {
341 fn new(vectors: &'a FixedSizeListArray, query: ArrayRef, distance_type: DistanceType) -> Self {
342 let flat_array = vectors.values().as_primitive::<Float32Type>();
345 let dimension = vectors.value_length() as usize;
346 Self {
347 vectors: flat_array.values(),
348 query: query.as_primitive::<Float32Type>().values().to_vec(),
349 dimension,
350 distance_fn: distance_type.func(),
351 }
352 }
353}
354
355impl<'a> FlatDistanceCal<'a, UInt8Type> {
356 fn new(vectors: &'a FixedSizeListArray, query: ArrayRef, _distance_type: DistanceType) -> Self {
357 let flat_array = vectors.values().as_primitive::<UInt8Type>();
360 let dimension = vectors.value_length() as usize;
361 Self {
362 vectors: flat_array.values(),
363 query: query.as_primitive::<UInt8Type>().values().to_vec(),
364 dimension,
365 distance_fn: hamming,
366 }
367 }
368}
369
370impl<T: ArrowPrimitiveType> FlatDistanceCal<'_, T> {
371 #[inline]
372 fn get_vector(&self, id: u32) -> &[T::Native] {
373 &self.vectors[self.dimension * id as usize..self.dimension * (id + 1) as usize]
374 }
375}
376
377impl<T: ArrowPrimitiveType> DistCalculator for FlatDistanceCal<'_, T> {
378 #[inline]
379 fn distance(&self, id: u32) -> f32 {
380 let vector = self.get_vector(id);
381 (self.distance_fn)(&self.query, vector)
382 }
383
384 fn distance_all(&self, _k_hint: usize) -> Vec<f32> {
385 let query = &self.query;
386 self.vectors
387 .chunks_exact(self.dimension)
388 .map(|vector| (self.distance_fn)(query, vector))
389 .collect()
390 }
391
392 #[inline]
393 fn prefetch(&self, id: u32) {
394 let vector = self.get_vector(id);
395 do_prefetch(vector.as_ptr_range())
396 }
397}