|
| 1 | +// SPDX-License-Identifier: Apache-2.0 |
| 2 | +// SPDX-FileCopyrightText: Copyright The Lance Authors |
| 3 | + |
| 4 | +use std::sync::Arc; |
| 5 | + |
| 6 | +use lance_index::metrics::NoOpMetricsCollector; |
| 7 | +use lance_index::scalar::lance_format::LanceIndexStore; |
| 8 | +use lance_index::scalar::zonemap::ZoneMapIndex; |
| 9 | +use lance_table::format::IndexMetadata; |
| 10 | +use roaring::RoaringBitmap; |
| 11 | +use uuid::Uuid; |
| 12 | + |
| 13 | +use crate::{Dataset, Error, Result, dataset::index::LanceIndexStoreExt}; |
| 14 | + |
| 15 | +/// Merge one caller-defined group of source ZoneMap segments into a single segment. |
| 16 | +pub(in crate::index) async fn merge_segments( |
| 17 | + dataset: &Dataset, |
| 18 | + segments: Vec<IndexMetadata>, |
| 19 | +) -> Result<IndexMetadata> { |
| 20 | + if segments.is_empty() { |
| 21 | + return Err(Error::index("No segment metadata was provided".to_string())); |
| 22 | + } |
| 23 | + |
| 24 | + let field_id = *segments[0].fields.first().ok_or_else(|| { |
| 25 | + Error::invalid_input(format!( |
| 26 | + "CreateIndex: segment {} is missing field ids", |
| 27 | + segments[0].uuid |
| 28 | + )) |
| 29 | + })?; |
| 30 | + let field_path = dataset.schema().field_path(field_id)?; |
| 31 | + |
| 32 | + let mut scalar_indices = Vec::with_capacity(segments.len()); |
| 33 | + let mut fragment_bitmap = RoaringBitmap::new(); |
| 34 | + let dataset_fragments = dataset.fragment_bitmap.as_ref(); |
| 35 | + for segment in &segments { |
| 36 | + let effective = segment |
| 37 | + .effective_fragment_bitmap(dataset_fragments) |
| 38 | + .ok_or_else(|| { |
| 39 | + Error::invalid_input(format!( |
| 40 | + "CreateIndex: segment {} is missing fragment coverage", |
| 41 | + segment.uuid |
| 42 | + )) |
| 43 | + })?; |
| 44 | + fragment_bitmap |= effective; |
| 45 | + let scalar_index = |
| 46 | + super::open_scalar_index(dataset, &field_path, segment, &NoOpMetricsCollector).await?; |
| 47 | + scalar_indices.push((segment.uuid, scalar_index)); |
| 48 | + } |
| 49 | + |
| 50 | + let mut source_indices = Vec::with_capacity(scalar_indices.len()); |
| 51 | + for (segment_uuid, scalar_index) in &scalar_indices { |
| 52 | + let zonemap_index = scalar_index |
| 53 | + .as_any() |
| 54 | + .downcast_ref::<ZoneMapIndex>() |
| 55 | + .ok_or_else(|| { |
| 56 | + Error::index(format!( |
| 57 | + "merge_existing_index_segments: expected zonemap segment {}, got {:?}", |
| 58 | + segment_uuid, |
| 59 | + scalar_index.index_type() |
| 60 | + )) |
| 61 | + })?; |
| 62 | + source_indices.push(zonemap_index); |
| 63 | + } |
| 64 | + |
| 65 | + let new_uuid = Uuid::new_v4(); |
| 66 | + let new_store = LanceIndexStore::from_dataset_for_new(dataset, &new_uuid)?; |
| 67 | + let created_index = lance_index::scalar::zonemap::merge_zonemap_indices( |
| 68 | + &source_indices, |
| 69 | + &new_store, |
| 70 | + &fragment_bitmap, |
| 71 | + ) |
| 72 | + .await?; |
| 73 | + |
| 74 | + Ok(IndexMetadata { |
| 75 | + uuid: new_uuid, |
| 76 | + fields: vec![field_id], |
| 77 | + dataset_version: dataset.manifest.version, |
| 78 | + fragment_bitmap: Some(fragment_bitmap), |
| 79 | + index_details: Some(Arc::new(created_index.index_details)), |
| 80 | + index_version: created_index.index_version as i32, |
| 81 | + created_at: Some(chrono::Utc::now()), |
| 82 | + base_id: None, |
| 83 | + files: Some(created_index.files), |
| 84 | + ..segments[0].clone() |
| 85 | + }) |
| 86 | +} |
0 commit comments