1use lance_core::utils::row_addr_remap::RowAddrRemap;
5use std::{
6 any::Any,
7 fmt::{Debug, Formatter},
8 sync::Arc,
9};
10
11use arrow_array::{Float32Array, RecordBatch, UInt32Array};
12use async_trait::async_trait;
13use datafusion::execution::SendableRecordBatchStream;
14use datafusion::physical_plan::stream::RecordBatchStreamAdapter;
15use lance_arrow::RecordBatchExt;
16use lance_core::ROW_ID;
17use lance_core::deepsize::DeepSizeOf;
18use lance_core::{Error, Result, datatypes::Schema};
19use lance_file::versions::v1::reader::FileReader as V1FileReader;
20use lance_io::traits::Reader;
21use lance_linalg::distance::DistanceType;
22use lance_table::format::SelfDescribingFileReader;
23use roaring::RoaringBitmap;
24use serde_json::json;
25use tracing::instrument;
26
27use crate::vector::ivf::storage::IvfModel;
28use crate::vector::quantizer::QuantizationType;
29use crate::vector::v3::subindex::{IvfSubIndex, SubIndexType};
30use crate::{
31 Index, IndexType,
32 vector::{
33 Query, VectorIndex,
34 graph::NEIGHBORS_FIELD,
35 hnsw::{HNSW, HnswMetadata, VECTOR_ID_FIELD},
36 ivf::storage::IVF_PARTITION_KEY,
37 quantizer::{IvfQuantizationStorage, Quantization, Quantizer},
38 storage::VectorStore,
39 },
40};
41use crate::{metrics::MetricsCollector, prefilter::PreFilter};
42
43#[derive(Clone, DeepSizeOf)]
44pub struct HNSWIndexOptions {
45 pub use_residual: bool,
46}
47
48#[derive(Clone, DeepSizeOf)]
49pub struct HNSWIndex<Q: Quantization> {
50 hnsw: Option<HNSW>,
52 storage: Option<Arc<Q::Storage>>,
53
54 partition_storage: IvfQuantizationStorage<Q>,
56 partition_metadata: Option<Vec<HnswMetadata>>,
57
58 options: HNSWIndexOptions,
59}
60
61impl<Q: Quantization> Debug for HNSWIndex<Q> {
62 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
63 self.hnsw.fmt(f)
64 }
65}
66
67impl<Q: Quantization> HNSWIndex<Q> {
68 pub async fn try_new(
69 reader: Arc<dyn Reader>,
70 aux_reader: Arc<dyn Reader>,
71 options: HNSWIndexOptions,
72 ) -> Result<Self> {
73 let reader = V1FileReader::try_new_self_described_from_reader(reader.clone(), None).await?;
74
75 let partition_metadata = match reader.schema().metadata.get(IVF_PARTITION_KEY) {
76 Some(json) => {
77 let metadata: Vec<HnswMetadata> = serde_json::from_str(json)?;
78 Some(metadata)
79 }
80 None => None,
81 };
82
83 let ivf_store = IvfQuantizationStorage::open(aux_reader).await?;
84 Ok(Self {
85 hnsw: None,
86 storage: None,
87 partition_storage: ivf_store,
88 partition_metadata,
89 options,
90 })
91 }
92
93 pub fn quantizer(&self) -> &Quantizer {
94 self.partition_storage.quantizer()
95 }
96
97 pub fn metadata(&self) -> HnswMetadata {
98 self.partition_metadata.as_ref().unwrap()[0].clone()
99 }
100
101 fn get_partition_metadata(&self, partition_id: usize) -> Result<HnswMetadata> {
102 match self.partition_metadata {
103 Some(ref metadata) => Ok(metadata[partition_id].clone()),
104 None => Err(Error::index("No partition metadata found".to_string())),
105 }
106 }
107}
108
109#[async_trait]
110impl<Q: Quantization + Send + Sync + 'static> Index for HNSWIndex<Q> {
111 fn as_any(&self) -> &dyn Any {
113 self
114 }
115
116 fn as_index(self: Arc<Self>) -> Arc<dyn Index> {
118 self
119 }
120
121 fn statistics(&self) -> Result<serde_json::Value> {
123 Ok(json!({
124 "index_type": "HNSW",
125 "distance_type": self.partition_storage.distance_type().to_string(),
126 }))
127 }
128
129 async fn prewarm(&self) -> Result<()> {
130 Ok(())
132 }
133
134 fn index_type(&self) -> IndexType {
136 IndexType::Vector
137 }
138
139 async fn calculate_included_frags(&self) -> Result<RoaringBitmap> {
144 unimplemented!()
145 }
146}
147
148#[async_trait]
149impl<Q: Quantization + Send + Sync + 'static> VectorIndex for HNSWIndex<Q> {
150 #[instrument(level = "debug", skip_all, name = "HNSWIndex::search")]
151 async fn search(
152 &self,
153 query: &Query,
154 pre_filter: Arc<dyn PreFilter>,
155 metrics: &dyn MetricsCollector,
156 ) -> Result<RecordBatch> {
157 let hnsw = self
158 .hnsw
159 .as_ref()
160 .ok_or(Error::index("HNSW index not loaded".to_string()))?;
161
162 let storage = self
163 .storage
164 .as_ref()
165 .ok_or(Error::index("vector storage not loaded".to_string()))?;
166
167 let refine_factor = query.refine_factor.unwrap_or(1) as usize;
168 let k = query.k * refine_factor;
169
170 hnsw.search(
171 query.key.clone(),
172 k,
173 query.into(),
174 storage.as_ref(),
175 pre_filter,
176 metrics,
177 )
178 }
179
180 fn find_partitions(&self, _: &Query) -> Result<(UInt32Array, Float32Array)> {
181 unimplemented!("only for IVF")
182 }
183
184 fn total_partitions(&self) -> usize {
185 1
186 }
187
188 async fn search_in_partition(
189 &self,
190 _: usize,
191 _: &Query,
192 _: Arc<dyn PreFilter>,
193 _: &dyn MetricsCollector,
194 ) -> Result<RecordBatch> {
195 unimplemented!("only for IVF")
196 }
197
198 fn is_loadable(&self) -> bool {
199 true
200 }
201
202 fn use_residual(&self) -> bool {
203 self.options.use_residual
204 }
205
206 async fn load(
207 &self,
208 reader: Arc<dyn Reader>,
209 _offset: usize,
210 _length: usize,
211 ) -> Result<Box<dyn VectorIndex>> {
212 let schema = Schema::try_from(&arrow_schema::Schema::new(vec![
213 NEIGHBORS_FIELD.clone(),
214 VECTOR_ID_FIELD.clone(),
215 ]))?;
216
217 let reader = V1FileReader::try_new_from_reader(
218 reader.path(),
219 reader.clone(),
220 None,
221 schema,
222 0,
223 0,
224 2,
225 None,
226 )
227 .await?;
228
229 let storage = Arc::new(self.partition_storage.load_partition(0).await?);
230 let batch = reader.read_range(0..reader.len(), reader.schema()).await?;
231 let hnsw = HNSW::load(batch)?;
232
233 Ok(Box::new(Self {
234 hnsw: Some(hnsw),
235 storage: Some(storage),
236 partition_storage: self.partition_storage.clone(),
237 partition_metadata: self.partition_metadata.clone(),
238 options: self.options.clone(),
239 }))
240 }
241
242 async fn load_partition(
243 &self,
244 reader: Arc<dyn Reader>,
245 offset: usize,
246 length: usize,
247 partition_id: usize,
248 ) -> Result<Box<dyn VectorIndex>> {
249 let reader = V1FileReader::try_new_self_described_from_reader(reader, None).await?;
250
251 let metadata = self.get_partition_metadata(partition_id)?;
252 let storage = Arc::new(self.partition_storage.load_partition(partition_id).await?);
253 let batch = reader
254 .read_range(offset..offset + length, reader.schema())
255 .await?;
256 let mut schema = batch.schema_ref().as_ref().clone();
257 schema.metadata.insert(
258 HNSW::metadata_key().to_owned(),
259 serde_json::to_string(&metadata)?,
260 );
261 let batch = batch.with_schema(schema.into())?;
262 let hnsw = HNSW::load(batch)?;
263
264 Ok(Box::new(Self {
265 hnsw: Some(hnsw),
266 storage: Some(storage),
267 partition_storage: self.partition_storage.clone(),
268 partition_metadata: self.partition_metadata.clone(),
269 options: self.options.clone(),
270 }))
271 }
272
273 async fn to_batch_stream(&self, with_vector: bool) -> Result<SendableRecordBatchStream> {
274 let store = self
275 .storage
276 .as_ref()
277 .ok_or(Error::index("vector storage not loaded".to_string()))?;
278
279 let schema = if with_vector {
280 store.schema().clone()
281 } else {
282 let schema = store.schema();
283 let row_id_idx = schema.index_of(ROW_ID)?;
284 Arc::new(schema.project(&[row_id_idx])?)
285 };
286
287 let batches = store
288 .to_batches()?
289 .map(|b| {
290 let batch = b.project_by_schema(&schema)?;
291 Ok(batch)
292 })
293 .collect::<Vec<_>>();
294 let stream = futures::stream::iter(batches);
295 let stream = RecordBatchStreamAdapter::new(schema, stream);
296 Ok(Box::pin(stream))
297 }
298
299 fn num_rows(&self) -> u64 {
300 self.hnsw
301 .as_ref()
302 .map_or(0, |hnsw| hnsw.num_nodes(0) as u64)
303 }
304
305 fn row_ids(&self) -> Box<dyn Iterator<Item = &'_ u64> + '_> {
306 Box::new(self.storage.as_ref().unwrap().row_ids())
307 }
308
309 async fn remap(&mut self, _mapping: &RowAddrRemap) -> Result<()> {
310 Err(Error::index(
311 "Remapping HNSW in this way not supported".to_string(),
312 ))
313 }
314
315 fn ivf_model(&self) -> &IvfModel {
316 unimplemented!("only for IVF")
317 }
318
319 fn quantizer(&self) -> Quantizer {
320 self.partition_storage.quantizer().clone()
321 }
322
323 fn partition_size(&self, _: usize) -> usize {
324 unimplemented!("only for IVF")
325 }
326
327 fn sub_index_type(&self) -> (SubIndexType, QuantizationType) {
328 (
329 SubIndexType::Hnsw,
330 self.partition_storage.quantizer().quantization_type(),
331 )
332 }
333
334 fn metric_type(&self) -> DistanceType {
335 self.partition_storage.distance_type()
336 }
337}