diff --git a/python/python/tests/test_index.py b/python/python/tests/test_index.py index 0c71fc87b..18b845b2b 100644 --- a/python/python/tests/test_index.py +++ b/python/python/tests/test_index.py @@ -162,12 +162,13 @@ async def test_create_bitmap_index(some_table: AsyncTable): await some_table.create_index("data", config=Bitmap()) indices = await some_table.list_indices() assert len(indices) == 3 + # list_indices returns indices in alphabetical order by name assert indices[0].index_type == "Bitmap" - assert indices[0].columns == ["id"] + assert indices[0].columns == ["data"] assert indices[1].index_type == "Bitmap" - assert indices[1].columns == ["is_active"] + assert indices[1].columns == ["id"] assert indices[2].index_type == "Bitmap" - assert indices[2].columns == ["data"] + assert indices[2].columns == ["is_active"] index_name = indices[0].name stats = await some_table.index_stats(index_name) diff --git a/rust/lancedb/src/table.rs b/rust/lancedb/src/table.rs index 60debbd22..0866b3e55 100644 --- a/rust/lancedb/src/table.rs +++ b/rust/lancedb/src/table.rs @@ -89,7 +89,6 @@ use futures::future::join_all; pub use lance::dataset::refs::{TagContents, Tags as LanceTags}; pub use lance::dataset::scanner::DatasetRecordBatchStream; use lance::dataset::statistics::DatasetStatisticsExt; -use lance_index::frag_reuse::FRAG_REUSE_INDEX_NAME; pub use lance_index::optimize::OptimizeOptions; pub use optimize::{CompactionOptions, OptimizeAction, OptimizeStats}; pub use schema_evolution::{AddColumnsResult, AlterColumnsResult, DropColumnsResult}; @@ -2864,71 +2863,32 @@ impl BaseTable for NativeTable { async fn list_indices(&self) -> Result> { let dataset = self.dataset.get().await?; - let indices = dataset.load_indices().await?; - let results = futures::stream::iter(indices.as_slice()) - .then(|idx| async { - // skip Lance internal indexes - if idx.name == FRAG_REUSE_INDEX_NAME { - return None; - } - - let stats = match dataset.index_statistics(idx.name.as_str()).await { - Ok(stats) => stats, - Err(e) => { - log::warn!( - "Failed to get statistics for index {} ({}): {}", - idx.name, - idx.uuid, - e - ); - return None; - } - }; - - let stats: serde_json::Value = match serde_json::from_str(&stats) { - Ok(stats) => stats, - Err(e) => { - log::warn!( - "Failed to deserialize index statistics for index {} ({}): {}", - idx.name, - idx.uuid, - e - ); - return None; - } - }; - - let Some(index_type) = stats.get("index_type").and_then(|v| v.as_str()) else { - log::warn!( - "Index statistics was missing 'index_type' field for index {} ({})", - idx.name, - idx.uuid - ); - return None; - }; - - let index_type: crate::index::IndexType = match index_type.parse() { + let indices = dataset + .describe_indices(None) + .await? + .into_iter() + .filter_map(|idx_desc| { + let index_type: crate::index::IndexType = match idx_desc.index_type().parse() { Ok(index_type) => index_type, Err(e) => { log::warn!( - "Failed to parse index type for index {} ({}): {}", - idx.name, - idx.uuid, + "Failed to parse index type for index {}: {}", + idx_desc.name(), e ); return None; } }; - let mut columns = Vec::with_capacity(idx.fields.len()); - for field_id in &idx.fields { - let field_path = match dataset.schema().field_path(*field_id) { + let field_ids = idx_desc.field_ids(); + let mut columns = Vec::with_capacity(field_ids.len()); + for field_id in field_ids { + let field_path = match dataset.schema().field_path(*field_id as i32) { Ok(field_path) => field_path, Err(e) => { log::warn!( - "Failed to resolve field path for index {} ({}) field id {}: {}", - idx.name, - idx.uuid, + "Failed to resolve field path for index {} field id {}: {}", + idx_desc.name(), field_id, e ); @@ -2938,17 +2898,14 @@ impl BaseTable for NativeTable { columns.push(field_path); } - let name = idx.name.clone(); Some(IndexConfig { + name: idx_desc.name().to_string(), index_type, columns, - name, }) }) - .collect::>() - .await; - - Ok(results.into_iter().flatten().collect()) + .collect(); + Ok(indices) } async fn uri(&self) -> Result { @@ -4062,26 +4019,27 @@ mod tests { let index_configs = table.list_indices().await.unwrap(); assert_eq!(index_configs.len(), 5); + // list_indices returns indices in alphabetical order by name let mut configs_iter = index_configs.into_iter(); let index = configs_iter.next().unwrap(); assert_eq!(index.index_type, crate::index::IndexType::Bitmap); assert_eq!(index.columns, vec!["category".to_string()]); - let index = configs_iter.next().unwrap(); - assert_eq!(index.index_type, crate::index::IndexType::Bitmap); - assert_eq!(index.columns, vec!["is_active".to_string()]); - let index = configs_iter.next().unwrap(); assert_eq!(index.index_type, crate::index::IndexType::Bitmap); assert_eq!(index.columns, vec!["data".to_string()]); let index = configs_iter.next().unwrap(); assert_eq!(index.index_type, crate::index::IndexType::Bitmap); - assert_eq!(index.columns, vec!["large_data".to_string()]); + assert_eq!(index.columns, vec!["is_active".to_string()]); let index = configs_iter.next().unwrap(); assert_eq!(index.index_type, crate::index::IndexType::Bitmap); assert_eq!(index.columns, vec!["large_category".to_string()]); + + let index = configs_iter.next().unwrap(); + assert_eq!(index.index_type, crate::index::IndexType::Bitmap); + assert_eq!(index.columns, vec!["large_data".to_string()]); } #[tokio::test]