lance_index/vector/
storage.rs1use crate::vector::quantizer::QuantizerStorage;
7use arrow::compute::concat_batches;
8use arrow_array::{ArrayRef, RecordBatch};
9use arrow_schema::SchemaRef;
10use deepsize::DeepSizeOf;
11use futures::prelude::stream::TryStreamExt;
12use lance_arrow::RecordBatchExt;
13use lance_core::{Error, ROW_ID, Result};
14use lance_encoding::decoder::FilterExpression;
15use lance_file::reader::FileReader;
16use lance_io::ReadBatchParams;
17use lance_linalg::distance::DistanceType;
18use prost::Message;
19use std::{any::Any, sync::Arc};
20
21use crate::frag_reuse::FragReuseIndex;
22use crate::{
23 pb,
24 vector::{
25 ivf::storage::{IVF_METADATA_KEY, IvfModel},
26 quantizer::Quantization,
27 },
28};
29
30use super::DISTANCE_TYPE_KEY;
31use super::quantizer::{Quantizer, QuantizerMetadata};
32
33pub trait DistCalculator {
39 fn distance(&self, id: u32) -> f32;
40
41 fn distance_all(&self, k_hint: usize) -> Vec<f32>;
44
45 fn prefetch(&self, _id: u32) {}
46}
47
48pub const STORAGE_METADATA_KEY: &str = "storage_metadata";
49
50pub trait VectorStore: Send + Sync + Sized + Clone {
64 type DistanceCalculator<'a>: DistCalculator
65 where
66 Self: 'a;
67
68 fn as_any(&self) -> &dyn Any;
69
70 fn schema(&self) -> &SchemaRef;
71
72 fn to_batches(&self) -> Result<impl Iterator<Item = RecordBatch> + Send>;
73
74 fn len(&self) -> usize;
75
76 fn is_empty(&self) -> bool {
78 self.len() == 0
79 }
80
81 fn distance_type(&self) -> DistanceType;
83
84 fn row_id(&self, id: u32) -> u64;
86
87 fn row_ids(&self) -> impl Iterator<Item = &u64>;
88
89 fn append_batch(&self, batch: RecordBatch, vector_column: &str) -> Result<Self>;
92
93 fn dist_calculator(&self, query: ArrayRef, dist_q_c: f32) -> Self::DistanceCalculator<'_>;
98
99 fn dist_calculator_from_id(&self, id: u32) -> Self::DistanceCalculator<'_>;
100
101 fn dist_between(&self, u: u32, v: u32) -> f32 {
102 let dist_cal_u = self.dist_calculator_from_id(u);
103 dist_cal_u.distance(v)
104 }
105}
106
107pub struct StorageBuilder<Q: Quantization> {
108 vector_column: String,
109 distance_type: DistanceType,
110 quantizer: Q,
111
112 frag_reuse_index: Option<Arc<FragReuseIndex>>,
113}
114
115impl<Q: Quantization> StorageBuilder<Q> {
116 pub fn new(
117 vector_column: String,
118 distance_type: DistanceType,
119 quantizer: Q,
120 frag_reuse_index: Option<Arc<FragReuseIndex>>,
121 ) -> Result<Self> {
122 Ok(Self {
123 vector_column,
124 distance_type,
125 quantizer,
126 frag_reuse_index,
127 })
128 }
129
130 pub fn build(&self, batches: Vec<RecordBatch>) -> Result<Q::Storage> {
131 let mut batch = concat_batches(batches[0].schema_ref(), batches.iter())?;
132
133 if batch.column_by_name(self.quantizer.column()).is_none() {
134 let vectors = batch
135 .column_by_name(&self.vector_column)
136 .ok_or(Error::index(format!(
137 "Vector column {} not found in batch",
138 self.vector_column
139 )))?;
140 let codes = self.quantizer.quantize(vectors)?;
141 batch = batch.drop_column(&self.vector_column)?.try_with_column(
142 arrow_schema::Field::new(self.quantizer.column(), codes.data_type().clone(), true),
143 codes,
144 )?;
145 }
146
147 debug_assert!(batch.column_by_name(ROW_ID).is_some());
148 debug_assert!(batch.column_by_name(self.quantizer.column()).is_some());
149
150 Q::Storage::try_from_batch(
151 batch,
152 &self.quantizer.metadata(None),
153 self.distance_type,
154 self.frag_reuse_index.clone(),
155 )
156 }
157}
158
159#[derive(Debug)]
161pub struct IvfQuantizationStorage<Q: Quantization> {
162 reader: FileReader,
163
164 distance_type: DistanceType,
165 metadata: Q::Metadata,
166
167 ivf: IvfModel,
168 frag_reuse_index: Option<Arc<FragReuseIndex>>,
169}
170
171impl<Q: Quantization> DeepSizeOf for IvfQuantizationStorage<Q> {
172 fn deep_size_of_children(&self, context: &mut deepsize::Context) -> usize {
173 self.metadata.deep_size_of_children(context) + self.ivf.deep_size_of_children(context)
174 }
175}
176
177impl<Q: Quantization> IvfQuantizationStorage<Q> {
178 pub async fn try_new(
182 reader: FileReader,
183 frag_reuse_index: Option<Arc<FragReuseIndex>>,
184 ) -> Result<Self> {
185 let schema = reader.schema();
186
187 let distance_type = DistanceType::try_from(
188 schema
189 .metadata
190 .get(DISTANCE_TYPE_KEY)
191 .ok_or(Error::index(format!("{} not found", DISTANCE_TYPE_KEY)))?
192 .as_str(),
193 )?;
194
195 let ivf_pos = schema
196 .metadata
197 .get(IVF_METADATA_KEY)
198 .ok_or(Error::index(format!("{} not found", IVF_METADATA_KEY)))?
199 .parse()
200 .map_err(|e| Error::index(format!("Failed to decode IVF metadata: {}", e)))?;
201 let ivf_bytes = reader.read_global_buffer(ivf_pos).await?;
202 let ivf = IvfModel::try_from(pb::Ivf::decode(ivf_bytes)?)?;
203
204 let mut metadata: Vec<String> = serde_json::from_str(
205 schema
206 .metadata
207 .get(STORAGE_METADATA_KEY)
208 .ok_or(Error::index(format!("{} not found", STORAGE_METADATA_KEY)))?
209 .as_str(),
210 )?;
211 debug_assert_eq!(metadata.len(), 1);
212 let metadata = metadata
214 .pop()
215 .ok_or(Error::index("metadata is empty".to_string()))?;
216 let mut metadata: Q::Metadata = serde_json::from_str(&metadata)?;
217 if let Some(pos) = metadata.buffer_index() {
220 let bytes = reader.read_global_buffer(pos).await?;
221 metadata.parse_buffer(bytes)?;
222 }
223
224 Ok(Self {
225 reader,
226 distance_type,
227 metadata,
228 ivf,
229 frag_reuse_index,
230 })
231 }
232
233 pub fn num_rows(&self) -> u64 {
234 self.reader.num_rows()
235 }
236
237 pub fn partition_size(&self, part_id: usize) -> usize {
238 self.ivf.partition_size(part_id)
239 }
240
241 pub fn quantizer(&self) -> Result<Quantizer> {
242 let metadata = self.metadata();
243 Q::from_metadata(metadata, self.distance_type)
244 }
245
246 pub fn metadata(&self) -> &Q::Metadata {
247 &self.metadata
248 }
249
250 pub fn distance_type(&self) -> DistanceType {
251 self.distance_type
252 }
253
254 pub fn schema(&self) -> SchemaRef {
255 Arc::new(self.reader.schema().as_ref().into())
256 }
257
258 pub fn num_partitions(&self) -> usize {
260 self.ivf.num_partitions()
261 }
262
263 pub async fn load_partition(&self, part_id: usize) -> Result<Q::Storage> {
264 let range = self.ivf.row_range(part_id);
265 let batch = if range.is_empty() {
266 let schema = self.reader.schema();
267 let arrow_schema = arrow_schema::Schema::from(schema.as_ref());
268 RecordBatch::new_empty(Arc::new(arrow_schema))
269 } else {
270 let batches = self
271 .reader
272 .read_stream(
273 ReadBatchParams::Range(range),
274 u32::MAX,
275 1,
276 FilterExpression::no_filter(),
277 )?
278 .try_collect::<Vec<_>>()
279 .await?;
280 let schema = Arc::new(self.reader.schema().as_ref().into());
281 concat_batches(&schema, batches.iter())?
282 };
283 Q::Storage::try_from_batch(
284 batch,
285 self.metadata(),
286 self.distance_type,
287 self.frag_reuse_index.clone(),
288 )
289 }
290}