@@ -35,6 +35,7 @@ use lance_index::vector::quantizer::{QuantizationType, Quantizer};
35
35
use lance_index:: vector:: sq:: ScalarQuantizer ;
36
36
use lance_index:: vector:: storage:: VectorStore ;
37
37
use lance_index:: vector:: v3:: subindex:: SubIndexType ;
38
+ use lance_index:: vector:: VectorIndexCacheEntry ;
38
39
use lance_index:: {
39
40
pb,
40
41
vector:: {
@@ -49,7 +50,6 @@ use lance_io::{
49
50
object_store:: ObjectStore , scheduler:: ScanScheduler , traits:: Reader , ReadBatchParams ,
50
51
} ;
51
52
use lance_linalg:: { distance:: DistanceType , kernels:: normalize_arrow} ;
52
- use moka:: sync:: Cache ;
53
53
use object_store:: path:: Path ;
54
54
use prost:: Message ;
55
55
use roaring:: RoaringBitmap ;
@@ -68,12 +68,20 @@ use crate::{
68
68
69
69
use super :: { centroids_to_vectors, IvfIndexPartitionStatistics , IvfIndexStatistics } ;
70
70
71
- #[ derive( Debug ) ]
71
+ #[ derive( Debug , DeepSizeOf ) ]
72
72
pub struct PartitionEntry < S : IvfSubIndex , Q : Quantization > {
73
73
pub index : S ,
74
74
pub storage : Q :: Storage ,
75
75
}
76
76
77
+ impl < S : IvfSubIndex + ' static , Q : Quantization + ' static > VectorIndexCacheEntry
78
+ for PartitionEntry < S , Q >
79
+ {
80
+ fn as_any ( & self ) -> & dyn Any {
81
+ self
82
+ }
83
+ }
84
+
77
85
/// IVF Index.
78
86
#[ derive( Debug ) ]
79
87
pub struct IVFIndex < S : IvfSubIndex + ' static , Q : Quantization + ' static > {
@@ -86,9 +94,6 @@ pub struct IVFIndex<S: IvfSubIndex + 'static, Q: Quantization + 'static> {
86
94
sub_index_metadata : Vec < String > ,
87
95
storage : IvfQuantizationStorage ,
88
96
89
- /// Index in each partition.
90
- partition_cache : Cache < String , Arc < PartitionEntry < S , Q > > > ,
91
-
92
97
partition_locks : PartitionLoadLock ,
93
98
94
99
distance_type : DistanceType ,
@@ -98,7 +103,7 @@ pub struct IVFIndex<S: IvfSubIndex + 'static, Q: Quantization + 'static> {
98
103
/// The session cache, used when fetching pages
99
104
#[ allow( dead_code) ]
100
105
session : Weak < Session > ,
101
- _marker : PhantomData < Q > ,
106
+ _marker : PhantomData < ( S , Q ) > ,
102
107
}
103
108
104
109
impl < S : IvfSubIndex , Q : Quantization > DeepSizeOf for IVFIndex < S , Q > {
@@ -123,7 +128,6 @@ impl<S: IvfSubIndex + 'static, Q: Quantization> IVFIndex<S, Q> {
123
128
. upgrade ( )
124
129
. map ( |sess| sess. file_metadata_cache . clone ( ) )
125
130
. unwrap_or_else ( FileMetadataCache :: no_cache) ;
126
- let index_cache_capacity = session. upgrade ( ) . unwrap ( ) . index_cache . capacity ( ) ;
127
131
let index_reader = FileReader :: try_open (
128
132
scheduler
129
133
. open_file ( & index_dir. child ( uuid. as_str ( ) ) . child ( INDEX_FILE_NAME ) )
@@ -195,7 +199,6 @@ impl<S: IvfSubIndex + 'static, Q: Quantization> IVFIndex<S, Q> {
195
199
ivf,
196
200
reader : index_reader,
197
201
storage,
198
- partition_cache : Cache :: new ( index_cache_capacity) ,
199
202
partition_locks : PartitionLoadLock :: new ( num_partitions) ,
200
203
sub_index_metadata,
201
204
distance_type,
@@ -209,70 +212,76 @@ impl<S: IvfSubIndex + 'static, Q: Quantization> IVFIndex<S, Q> {
209
212
& self ,
210
213
partition_id : usize ,
211
214
write_cache : bool ,
212
- ) -> Result < Arc < PartitionEntry < S , Q > > > {
215
+ ) -> Result < Arc < dyn VectorIndexCacheEntry > > {
213
216
let cache_key = format ! ( "{}-ivf-{}" , self . uuid, partition_id) ;
214
- let part_entry = if let Some ( part_idx) = self . partition_cache . get ( & cache_key) {
215
- part_idx
216
- } else {
217
- if partition_id >= self . ivf . num_partitions ( ) {
218
- return Err ( Error :: Index {
219
- message : format ! (
220
- "partition id {} is out of range of {} partitions" ,
221
- partition_id,
222
- self . ivf. num_partitions( )
223
- ) ,
224
- location : location ! ( ) ,
225
- } ) ;
226
- }
227
-
228
- let mtx = self . partition_locks . get_partition_mutex ( partition_id) ;
229
- let _guard = mtx. lock ( ) . await ;
230
-
231
- // check the cache again, as the partition may have been loaded by another
232
- // thread that held the lock on loading the partition
233
- if let Some ( part_idx) = self . partition_cache . get ( & cache_key) {
217
+ let session = self . session . upgrade ( ) . ok_or ( Error :: Internal {
218
+ message : "attempt to use index after dataset was destroyed" . into ( ) ,
219
+ location : location ! ( ) ,
220
+ } ) ?;
221
+ let part_entry =
222
+ if let Some ( part_idx) = session. index_cache . get_vector_partition ( & cache_key) {
234
223
part_idx
235
224
} else {
236
- let schema = Arc :: new ( self . reader . schema ( ) . as_ref ( ) . into ( ) ) ;
237
- let batch = match self . reader . metadata ( ) . num_rows {
238
- 0 => RecordBatch :: new_empty ( schema) ,
239
- _ => {
240
- let row_range = self . ivf . row_range ( partition_id) ;
241
- if row_range. is_empty ( ) {
242
- RecordBatch :: new_empty ( schema)
243
- } else {
244
- let batches = self
245
- . reader
246
- . read_stream (
247
- ReadBatchParams :: Range ( row_range) ,
248
- u32:: MAX ,
249
- 1 ,
250
- FilterExpression :: no_filter ( ) ,
251
- ) ?
252
- . try_collect :: < Vec < _ > > ( )
253
- . await ?;
254
- concat_batches ( & schema, batches. iter ( ) ) ?
225
+ if partition_id >= self . ivf . num_partitions ( ) {
226
+ return Err ( Error :: Index {
227
+ message : format ! (
228
+ "partition id {} is out of range of {} partitions" ,
229
+ partition_id,
230
+ self . ivf. num_partitions( )
231
+ ) ,
232
+ location : location ! ( ) ,
233
+ } ) ;
234
+ }
235
+
236
+ let mtx = self . partition_locks . get_partition_mutex ( partition_id) ;
237
+ let _guard = mtx. lock ( ) . await ;
238
+
239
+ // check the cache again, as the partition may have been loaded by another
240
+ // thread that held the lock on loading the partition
241
+ if let Some ( part_idx) = session. index_cache . get_vector_partition ( & cache_key) {
242
+ part_idx
243
+ } else {
244
+ let schema = Arc :: new ( self . reader . schema ( ) . as_ref ( ) . into ( ) ) ;
245
+ let batch = match self . reader . metadata ( ) . num_rows {
246
+ 0 => RecordBatch :: new_empty ( schema) ,
247
+ _ => {
248
+ let row_range = self . ivf . row_range ( partition_id) ;
249
+ if row_range. is_empty ( ) {
250
+ RecordBatch :: new_empty ( schema)
251
+ } else {
252
+ let batches = self
253
+ . reader
254
+ . read_stream (
255
+ ReadBatchParams :: Range ( row_range) ,
256
+ u32:: MAX ,
257
+ 1 ,
258
+ FilterExpression :: no_filter ( ) ,
259
+ ) ?
260
+ . try_collect :: < Vec < _ > > ( )
261
+ . await ?;
262
+ concat_batches ( & schema, batches. iter ( ) ) ?
263
+ }
255
264
}
265
+ } ;
266
+ let batch = batch. add_metadata (
267
+ S :: metadata_key ( ) . to_owned ( ) ,
268
+ self . sub_index_metadata [ partition_id] . clone ( ) ,
269
+ ) ?;
270
+ let idx = S :: load ( batch) ?;
271
+ let storage = self . load_partition_storage ( partition_id) . await ?;
272
+ let partition_entry = Arc :: new ( PartitionEntry :: < S , Q > {
273
+ index : idx,
274
+ storage,
275
+ } ) ;
276
+ if write_cache {
277
+ session
278
+ . index_cache
279
+ . insert_vector_partition ( & cache_key, partition_entry. clone ( ) ) ;
256
280
}
257
- } ;
258
- let batch = batch. add_metadata (
259
- S :: metadata_key ( ) . to_owned ( ) ,
260
- self . sub_index_metadata [ partition_id] . clone ( ) ,
261
- ) ?;
262
- let idx = S :: load ( batch) ?;
263
- let storage = self . load_partition_storage ( partition_id) . await ?;
264
- let partition_entry = Arc :: new ( PartitionEntry {
265
- index : idx,
266
- storage,
267
- } ) ;
268
- if write_cache {
269
- self . partition_cache
270
- . insert ( cache_key. clone ( ) , partition_entry. clone ( ) ) ;
271
- }
272
281
273
- partition_entry
274
- }
275
- } ;
282
+ partition_entry
283
+ }
284
+ } ;
276
285
277
286
Ok ( part_entry)
278
287
}
@@ -428,9 +437,15 @@ impl<S: IvfSubIndex + 'static, Q: Quantization + 'static> VectorIndex for IVFInd
428
437
let param = ( & query) . into ( ) ;
429
438
let refine_factor = query. refine_factor . unwrap_or ( 1 ) as usize ;
430
439
let k = query. k * refine_factor;
431
- part_entry
432
- . index
433
- . search ( query. key , k, param, & part_entry. storage , pre_filter)
440
+ let part = part_entry
441
+ . as_any ( )
442
+ . downcast_ref :: < PartitionEntry < S , Q > > ( )
443
+ . ok_or ( Error :: Internal {
444
+ message : "failed to downcast partition entry" . to_string ( ) ,
445
+ location : location ! ( ) ,
446
+ } ) ?;
447
+ part. index
448
+ . search ( query. key , k, param, & part. storage , pre_filter)
434
449
} )
435
450
. await
436
451
}
@@ -465,6 +480,13 @@ impl<S: IvfSubIndex + 'static, Q: Quantization + 'static> VectorIndex for IVFInd
465
480
with_vector : bool ,
466
481
) -> Result < SendableRecordBatchStream > {
467
482
let partition = self . load_partition ( partition_id, false ) . await ?;
483
+ let partition = partition
484
+ . as_any ( )
485
+ . downcast_ref :: < PartitionEntry < S , Q > > ( )
486
+ . ok_or ( Error :: Internal {
487
+ message : "failed to downcast partition entry" . to_string ( ) ,
488
+ location : location ! ( ) ,
489
+ } ) ?;
468
490
let store = & partition. storage ;
469
491
let schema = if with_vector {
470
492
store. schema ( ) . clone ( )
0 commit comments