1use std::collections::HashSet;
7use std::collections::hash_map::DefaultHasher;
8use std::hash::{Hash, Hasher};
9
10use arrow_array::cast::AsArray;
11use arrow_array::{
12 Array, BinaryArray, LargeBinaryArray, LargeListArray, LargeStringArray, ListArray, RecordBatch,
13 StringArray, StructArray,
14};
15use arrow_schema::DataType;
16use deepsize::DeepSizeOf;
17use lance_core::Result;
18use lance_index::scalar::bloomfilter::sbbf::{Sbbf, SbbfBuilder};
19use lance_table::format::pb;
20
21pub const BLOOM_FILTER_DEFAULT_NUMBER_OF_ITEMS: u64 = 8192;
23pub const BLOOM_FILTER_DEFAULT_PROBABILITY: f64 = 0.00057;
24
25#[derive(Debug, Clone, PartialEq, Eq, Hash)]
27pub enum KeyValue {
28 String(String),
29 Int64(i64),
30 UInt64(u64),
31 Binary(Vec<u8>),
32 List(Vec<Self>),
33 Struct(Vec<Self>),
34 Composite(Vec<Self>),
35}
36
37impl KeyValue {
38 pub fn to_bytes(&self) -> Vec<u8> {
39 match self {
40 Self::String(s) => s.as_bytes().to_vec(),
41 Self::Int64(i) => i.to_le_bytes().to_vec(),
42 Self::UInt64(u) => u.to_le_bytes().to_vec(),
43 Self::Binary(b) => b.clone(),
44 Self::List(values) | Self::Struct(values) | Self::Composite(values) => {
45 let mut result = Vec::new();
46 for value in values {
47 result.extend_from_slice(&value.to_bytes());
48 result.push(0);
49 }
50 result
51 }
52 }
53 }
54
55 pub fn hash_value(&self) -> u64 {
56 let mut hasher = DefaultHasher::new();
57 self.to_bytes().hash(&mut hasher);
58 hasher.finish()
59 }
60}
61
62#[derive(Debug, Clone)]
64pub struct KeyExistenceFilterBuilder {
65 sbbf: Sbbf,
66 field_ids: Vec<i32>,
67 item_count: usize,
68}
69
70impl KeyExistenceFilterBuilder {
71 pub fn new(field_ids: Vec<i32>) -> Self {
72 let sbbf = SbbfBuilder::new()
73 .expected_items(BLOOM_FILTER_DEFAULT_NUMBER_OF_ITEMS)
74 .false_positive_probability(BLOOM_FILTER_DEFAULT_PROBABILITY)
75 .build()
76 .expect("Failed to build SBBF");
77 Self {
78 sbbf,
79 field_ids,
80 item_count: 0,
81 }
82 }
83
84 pub fn insert(&mut self, key: KeyValue) -> Result<()> {
85 self.sbbf.insert(&key.to_bytes()[..]);
86 self.item_count += 1;
87 Ok(())
88 }
89
90 pub fn contains(&self, key: &KeyValue) -> bool {
91 self.sbbf.check(&key.to_bytes()[..])
92 }
93
94 pub fn might_intersect(&self, other: &Self) -> Result<bool> {
95 self.sbbf
96 .might_intersect(&other.sbbf)
97 .map_err(|e| lance_core::Error::invalid_input(e.to_string()))
98 }
99
100 pub fn field_ids(&self) -> &[i32] {
101 &self.field_ids
102 }
103
104 pub fn estimated_size_bytes(&self) -> usize {
105 self.sbbf.size_bytes()
106 }
107
108 pub fn len(&self) -> usize {
109 self.item_count
110 }
111
112 pub fn is_empty(&self) -> bool {
113 self.item_count == 0
114 }
115
116 pub fn build(&self) -> KeyExistenceFilter {
117 KeyExistenceFilter {
118 field_ids: self.field_ids.clone(),
119 filter: FilterType::Bloom {
120 bitmap: self.sbbf.to_bytes(),
121 num_bits: (self.sbbf.size_bytes() as u32) * 8,
122 number_of_items: BLOOM_FILTER_DEFAULT_NUMBER_OF_ITEMS,
123 probability: BLOOM_FILTER_DEFAULT_PROBABILITY,
124 },
125 }
126 }
127}
128
129impl From<&KeyExistenceFilterBuilder> for pb::transaction::KeyExistenceFilter {
130 fn from(builder: &KeyExistenceFilterBuilder) -> Self {
131 Self {
132 field_ids: builder.field_ids.clone(),
133 data: Some(pb::transaction::key_existence_filter::Data::Bloom(
134 pb::transaction::BloomFilter {
135 bitmap: builder.sbbf.to_bytes(),
136 num_bits: (builder.sbbf.size_bytes() as u32) * 8,
137 number_of_items: BLOOM_FILTER_DEFAULT_NUMBER_OF_ITEMS,
138 probability: BLOOM_FILTER_DEFAULT_PROBABILITY,
139 },
140 )),
141 }
142 }
143}
144
145#[derive(Debug, Clone, DeepSizeOf, PartialEq)]
147pub enum FilterType {
148 ExactSet(HashSet<u64>),
149 Bloom {
150 bitmap: Vec<u8>,
151 num_bits: u32,
152 number_of_items: u64,
153 probability: f64,
154 },
155}
156
157#[derive(Debug, Clone, DeepSizeOf, PartialEq)]
160pub struct KeyExistenceFilter {
161 pub field_ids: Vec<i32>,
162 pub filter: FilterType,
163}
164
165impl KeyExistenceFilter {
166 pub fn from_bloom_filter(bloom: &KeyExistenceFilterBuilder) -> Self {
167 bloom.build()
168 }
169
170 pub fn intersects(&self, other: &Self) -> Result<(bool, bool)> {
173 match (&self.filter, &other.filter) {
174 (FilterType::ExactSet(a), FilterType::ExactSet(b)) => {
175 Ok((a.iter().any(|h| b.contains(h)), false))
176 }
177 (FilterType::ExactSet(_), FilterType::Bloom { .. })
178 | (FilterType::Bloom { .. }, FilterType::ExactSet(_)) => {
179 Ok((true, true))
181 }
182 (
183 FilterType::Bloom {
184 bitmap: a_bits,
185 number_of_items: a_num_items,
186 probability: a_prob,
187 ..
188 },
189 FilterType::Bloom {
190 bitmap: b_bits,
191 number_of_items: b_num_items,
192 probability: b_prob,
193 ..
194 },
195 ) => {
196 if a_num_items != b_num_items || (a_prob - b_prob).abs() > f64::EPSILON {
197 return Err(lance_core::Error::invalid_input(format!(
198 "Bloom filter config mismatch: ({}, {}) vs ({}, {})",
199 a_num_items, a_prob, b_num_items, b_prob
200 )));
201 }
202 let has = Sbbf::bytes_might_intersect(a_bits, b_bits)
203 .map_err(|e| lance_core::Error::invalid_input(e.to_string()))?;
204 Ok((has, has))
205 }
206 }
207 }
208}
209
210impl From<&KeyExistenceFilter> for pb::transaction::KeyExistenceFilter {
211 fn from(filter: &KeyExistenceFilter) -> Self {
212 match &filter.filter {
213 FilterType::ExactSet(hashes) => Self {
214 field_ids: filter.field_ids.clone(),
215 data: Some(pb::transaction::key_existence_filter::Data::Exact(
216 pb::transaction::ExactKeySetFilter {
217 key_hashes: hashes.iter().copied().collect(),
218 },
219 )),
220 },
221 FilterType::Bloom {
222 bitmap,
223 num_bits,
224 number_of_items,
225 probability,
226 } => Self {
227 field_ids: filter.field_ids.clone(),
228 data: Some(pb::transaction::key_existence_filter::Data::Bloom(
229 pb::transaction::BloomFilter {
230 bitmap: bitmap.clone(),
231 num_bits: *num_bits,
232 number_of_items: *number_of_items,
233 probability: *probability,
234 },
235 )),
236 },
237 }
238 }
239}
240
241impl TryFrom<&pb::transaction::KeyExistenceFilter> for KeyExistenceFilter {
242 type Error = lance_core::Error;
243
244 fn try_from(message: &pb::transaction::KeyExistenceFilter) -> Result<Self> {
245 let filter = match message.data.as_ref() {
246 Some(pb::transaction::key_existence_filter::Data::Exact(exact)) => {
247 FilterType::ExactSet(exact.key_hashes.iter().copied().collect())
248 }
249 Some(pb::transaction::key_existence_filter::Data::Bloom(b)) => {
250 let number_of_items = if b.number_of_items == 0 {
252 BLOOM_FILTER_DEFAULT_NUMBER_OF_ITEMS
253 } else {
254 b.number_of_items
255 };
256 let probability = if b.probability == 0.0 {
257 BLOOM_FILTER_DEFAULT_PROBABILITY
258 } else {
259 b.probability
260 };
261 FilterType::Bloom {
262 bitmap: b.bitmap.clone(),
263 num_bits: b.num_bits,
264 number_of_items,
265 probability,
266 }
267 }
268 None => FilterType::ExactSet(HashSet::new()),
269 };
270 Ok(Self {
271 field_ids: message.field_ids.clone(),
272 filter,
273 })
274 }
275}
276
277pub fn extract_key_value_from_batch(
279 batch: &RecordBatch,
280 row_idx: usize,
281 on_columns: &[String],
282) -> Option<KeyValue> {
283 let mut parts: Vec<KeyValue> = Vec::with_capacity(on_columns.len());
284
285 for col_name in on_columns {
286 let (col_idx, _) = batch.schema().column_with_name(col_name)?;
287 let column = batch.column(col_idx);
288
289 if column.is_null(row_idx) {
290 return None;
291 }
292
293 let key_part = extract_key_value(column, row_idx)?;
294 parts.push(key_part);
295 }
296
297 if parts.is_empty() {
298 None
299 } else if parts.len() == 1 {
300 Some(parts.into_iter().next().unwrap())
301 } else {
302 Some(KeyValue::Composite(parts))
303 }
304}
305
306fn extract_key_value(array: &dyn Array, row_idx: usize) -> Option<KeyValue> {
307 let v = match array.data_type() {
308 DataType::Utf8 => {
309 let arr = array.as_any().downcast_ref::<StringArray>()?;
310 KeyValue::String(arr.value(row_idx).to_string())
311 }
312 DataType::LargeUtf8 => {
313 let arr = array.as_any().downcast_ref::<LargeStringArray>()?;
314 KeyValue::String(arr.value(row_idx).to_string())
315 }
316 DataType::UInt64 => {
317 let arr = array.as_primitive::<arrow_array::types::UInt64Type>();
318 KeyValue::UInt64(arr.value(row_idx))
319 }
320 DataType::Int64 => {
321 let arr = array.as_primitive::<arrow_array::types::Int64Type>();
322 KeyValue::Int64(arr.value(row_idx))
323 }
324 DataType::UInt32 => {
325 let arr = array.as_primitive::<arrow_array::types::UInt32Type>();
326 KeyValue::UInt64(arr.value(row_idx) as u64)
327 }
328 DataType::Int32 => {
329 let arr = array.as_primitive::<arrow_array::types::Int32Type>();
330 KeyValue::Int64(arr.value(row_idx) as i64)
331 }
332 DataType::Binary => {
333 let arr = array.as_any().downcast_ref::<BinaryArray>()?;
334 KeyValue::Binary(arr.value(row_idx).to_vec())
335 }
336 DataType::LargeBinary => {
337 let arr = array.as_any().downcast_ref::<LargeBinaryArray>()?;
338 KeyValue::Binary(arr.value(row_idx).to_vec())
339 }
340 DataType::List(_) => {
341 let list_array = array.as_any().downcast_ref::<ListArray>().unwrap();
342 let values = list_array.value(row_idx);
343
344 let mut elements = Vec::with_capacity(values.len());
345 for i in 0..values.len() {
346 if values.is_null(i) {
347 return None;
348 }
349 let element = extract_key_value(&values, i)?;
350 elements.push(element);
351 }
352 KeyValue::List(elements)
353 }
354 DataType::LargeList(_) => {
355 let list_array = array.as_any().downcast_ref::<LargeListArray>().unwrap();
356 let values = list_array.value(row_idx);
357
358 let mut elements = Vec::with_capacity(values.len());
359 for i in 0..values.len() {
360 if values.is_null(i) {
361 return None;
362 }
363 let element = extract_key_value(&values, i)?;
364 elements.push(element);
365 }
366 KeyValue::List(elements)
367 }
368 DataType::Struct(_) => {
369 let struct_array = array.as_any().downcast_ref::<StructArray>()?;
370 let mut elements = Vec::with_capacity(struct_array.num_columns());
371 for i in 0..struct_array.num_columns() {
372 let child = struct_array.column(i);
373 if child.is_null(row_idx) {
374 return None;
375 }
376 let field_value = extract_key_value(child.as_ref(), row_idx)?;
377 elements.push(field_value);
378 }
379 KeyValue::Struct(elements)
380 }
381 _ => return None,
382 };
383 Some(v)
384}
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389 use std::sync::Arc;
390
391 use arrow_array::builder::{Int32Builder, ListBuilder, StringBuilder};
392 use arrow_array::{Int32Array, RecordBatch, StringArray, StructArray};
393 use arrow_schema::{Field, Schema};
394
395 #[test]
396 fn test_extract_key_value_from_batch_list_int() {
397 let values_builder = Int32Builder::new();
398 let mut list_builder = ListBuilder::new(values_builder);
399
400 list_builder.append_value([Some(1), Some(2)]);
401 list_builder.append_value([Some(3), Some(4), Some(5)]);
402
403 let list_array = list_builder.finish();
404
405 let schema = Arc::new(Schema::new(vec![Field::new(
406 "id",
407 list_array.data_type().clone(),
408 false,
409 )]));
410
411 let batch = RecordBatch::try_new(schema, vec![Arc::new(list_array)])
412 .expect("batch should be valid");
413
414 let key0 = extract_key_value_from_batch(&batch, 0, &[String::from("id")])
415 .expect("first row should produce a key");
416 let key1 = extract_key_value_from_batch(&batch, 1, &[String::from("id")])
417 .expect("second row should produce a key");
418
419 match &key0 {
420 KeyValue::List(values) => {
421 assert_eq!(values.len(), 2);
422 assert_eq!(values[0], KeyValue::Int64(1));
423 assert_eq!(values[1], KeyValue::Int64(2));
424 }
425 other => panic!("expected list key, got {:?}", other),
426 }
427
428 match &key1 {
429 KeyValue::List(values) => {
430 assert_eq!(values.len(), 3);
431 assert_eq!(values[0], KeyValue::Int64(3));
432 assert_eq!(values[1], KeyValue::Int64(4));
433 assert_eq!(values[2], KeyValue::Int64(5));
434 }
435 other => panic!("expected list key, got {:?}", other),
436 }
437
438 assert_ne!(
439 key0.hash_value(),
440 key1.hash_value(),
441 "different list values should hash differently",
442 );
443 }
444
445 #[test]
446 fn test_extract_key_value_from_batch_empty_list() {
447 let values_builder = Int32Builder::new();
448 let mut list_builder = ListBuilder::new(values_builder);
449
450 list_builder.append_value(std::iter::empty::<Option<i32>>());
451
452 let list_array = list_builder.finish();
453
454 let schema = Arc::new(Schema::new(vec![Field::new(
455 "id",
456 list_array.data_type().clone(),
457 false,
458 )]));
459
460 let batch = RecordBatch::try_new(schema, vec![Arc::new(list_array)])
461 .expect("batch should be valid");
462
463 let key = extract_key_value_from_batch(&batch, 0, &[String::from("id")])
464 .expect("empty list should still produce a key");
465
466 match key {
467 KeyValue::List(values) => {
468 assert!(values.is_empty(), "expected empty list");
469 }
470 other => panic!("expected list key, got {:?}", other),
471 }
472 }
473
474 #[test]
475 fn test_extract_key_value_from_batch_list_utf8() {
476 let values_builder = StringBuilder::new();
477 let mut list_builder = ListBuilder::new(values_builder);
478
479 list_builder.append_value([Some("a"), Some("bc")]);
480 list_builder.append_value([Some("de")]);
481
482 let list_array = list_builder.finish();
483
484 let schema = Arc::new(Schema::new(vec![Field::new(
485 "id",
486 list_array.data_type().clone(),
487 false,
488 )]));
489
490 let batch = RecordBatch::try_new(schema, vec![Arc::new(list_array)])
491 .expect("batch should be valid");
492
493 let key0 = extract_key_value_from_batch(&batch, 0, &[String::from("id")])
494 .expect("first row should produce a key");
495 let key1 = extract_key_value_from_batch(&batch, 1, &[String::from("id")])
496 .expect("second row should produce a key");
497
498 match &key0 {
499 KeyValue::List(values) => {
500 assert_eq!(values.len(), 2);
501 assert_eq!(values[0], KeyValue::String("a".to_string()));
502 assert_eq!(values[1], KeyValue::String("bc".to_string()));
503 }
504 other => panic!("expected list key, got {:?}", other),
505 }
506
507 match &key1 {
508 KeyValue::List(values) => {
509 assert_eq!(values.len(), 1);
510 assert_eq!(values[0], KeyValue::String("de".to_string()));
511 }
512 other => panic!("expected list key, got {:?}", other),
513 }
514
515 assert_ne!(
516 key0.hash_value(),
517 key1.hash_value(),
518 "different list values should hash differently",
519 );
520 }
521
522 #[test]
523 fn test_extract_key_value_from_batch_list_with_null_child() {
524 let values_builder = Int32Builder::new();
525 let mut list_builder = ListBuilder::new(values_builder);
526
527 list_builder.append_value([Some(1), Some(2)]);
528 list_builder.append_value([Some(3), None]);
529
530 let list_array = list_builder.finish();
531
532 let schema = Arc::new(Schema::new(vec![Field::new(
533 "id",
534 list_array.data_type().clone(),
535 false,
536 )]));
537
538 let batch = RecordBatch::try_new(schema, vec![Arc::new(list_array)])
539 .expect("batch should be valid");
540
541 let key0 = extract_key_value_from_batch(&batch, 0, &[String::from("id")])
542 .expect("first row should produce a key");
543 let key1 = extract_key_value_from_batch(&batch, 1, &[String::from("id")]);
544
545 match &key0 {
546 KeyValue::List(values) => {
547 assert_eq!(values.len(), 2);
548 assert_eq!(values[0], KeyValue::Int64(1));
549 assert_eq!(values[1], KeyValue::Int64(2));
550 }
551 other => panic!("expected list key, got {:?}", other),
552 }
553
554 assert!(
555 key1.is_none(),
556 "list row with a null child should not produce a key",
557 );
558 }
559
560 #[test]
561 fn test_extract_key_value_from_batch_struct_int() {
562 let a_values = Int32Array::from(vec![1, 3]);
563 let b_values = Int32Array::from(vec![2, 4]);
564
565 let struct_array = StructArray::from(vec![
566 (
567 Arc::new(Field::new("a", arrow_schema::DataType::Int32, false)),
568 Arc::new(a_values) as Arc<dyn arrow_array::Array>,
569 ),
570 (
571 Arc::new(Field::new("b", arrow_schema::DataType::Int32, false)),
572 Arc::new(b_values) as Arc<dyn arrow_array::Array>,
573 ),
574 ]);
575
576 let schema = Arc::new(Schema::new(vec![Field::new(
577 "id",
578 struct_array.data_type().clone(),
579 false,
580 )]));
581
582 let batch = RecordBatch::try_new(schema, vec![Arc::new(struct_array)])
583 .expect("batch should be valid");
584
585 let key0 = extract_key_value_from_batch(&batch, 0, &[String::from("id")])
586 .expect("first row should produce a key");
587 let key1 = extract_key_value_from_batch(&batch, 1, &[String::from("id")])
588 .expect("second row should produce a key");
589
590 match &key0 {
591 KeyValue::Struct(values) => {
592 assert_eq!(values.len(), 2);
593 assert_eq!(values[0], KeyValue::Int64(1));
594 assert_eq!(values[1], KeyValue::Int64(2));
595 }
596 other => panic!("expected struct key, got {:?}", other),
597 }
598
599 match &key1 {
600 KeyValue::Struct(values) => {
601 assert_eq!(values.len(), 2);
602 assert_eq!(values[0], KeyValue::Int64(3));
603 assert_eq!(values[1], KeyValue::Int64(4));
604 }
605 other => panic!("expected struct key, got {:?}", other),
606 }
607
608 assert_ne!(
609 key0.hash_value(),
610 key1.hash_value(),
611 "different struct values should hash differently",
612 );
613 }
614
615 #[test]
616 fn test_extract_key_value_from_batch_struct_utf8() {
617 let first_names = StringArray::from(vec!["alice", "bob"]);
618 let last_names = StringArray::from(vec!["smith", "jones"]);
619
620 let struct_array = StructArray::from(vec![
621 (
622 Arc::new(Field::new("first", arrow_schema::DataType::Utf8, false)),
623 Arc::new(first_names) as Arc<dyn arrow_array::Array>,
624 ),
625 (
626 Arc::new(Field::new("last", arrow_schema::DataType::Utf8, false)),
627 Arc::new(last_names) as Arc<dyn arrow_array::Array>,
628 ),
629 ]);
630
631 let schema = Arc::new(Schema::new(vec![Field::new(
632 "id",
633 struct_array.data_type().clone(),
634 false,
635 )]));
636
637 let batch = RecordBatch::try_new(schema, vec![Arc::new(struct_array)])
638 .expect("batch should be valid");
639
640 let key0 = extract_key_value_from_batch(&batch, 0, &[String::from("id")])
641 .expect("first row should produce a key");
642 let key1 = extract_key_value_from_batch(&batch, 1, &[String::from("id")])
643 .expect("second row should produce a key");
644
645 match &key0 {
646 KeyValue::Struct(values) => {
647 assert_eq!(values.len(), 2);
648 assert_eq!(values[0], KeyValue::String("alice".to_string()));
649 assert_eq!(values[1], KeyValue::String("smith".to_string()));
650 }
651 other => panic!("expected struct key, got {:?}", other),
652 }
653
654 match &key1 {
655 KeyValue::Struct(values) => {
656 assert_eq!(values.len(), 2);
657 assert_eq!(values[0], KeyValue::String("bob".to_string()));
658 assert_eq!(values[1], KeyValue::String("jones".to_string()));
659 }
660 other => panic!("expected struct key, got {:?}", other),
661 }
662
663 assert_ne!(
664 key0.hash_value(),
665 key1.hash_value(),
666 "different struct values should hash differently",
667 );
668 }
669
670 #[test]
671 fn test_extract_key_value_from_batch_struct_with_null_child() {
672 let a_values = Int32Array::from(vec![Some(1), None]);
673 let b_values = Int32Array::from(vec![Some(2), Some(3)]);
674
675 let struct_array = StructArray::from(vec![
676 (
677 Arc::new(Field::new("a", arrow_schema::DataType::Int32, true)),
678 Arc::new(a_values) as Arc<dyn arrow_array::Array>,
679 ),
680 (
681 Arc::new(Field::new("b", arrow_schema::DataType::Int32, true)),
682 Arc::new(b_values) as Arc<dyn arrow_array::Array>,
683 ),
684 ]);
685
686 let schema = Arc::new(Schema::new(vec![Field::new(
687 "id",
688 struct_array.data_type().clone(),
689 false,
690 )]));
691
692 let batch = RecordBatch::try_new(schema, vec![Arc::new(struct_array)])
693 .expect("batch should be valid");
694
695 let key0 = extract_key_value_from_batch(&batch, 0, &[String::from("id")])
696 .expect("first row should produce a key");
697 let key1 = extract_key_value_from_batch(&batch, 1, &[String::from("id")]);
698
699 match &key0 {
700 KeyValue::Struct(values) => {
701 assert_eq!(values.len(), 2);
702 assert_eq!(values[0], KeyValue::Int64(1));
703 assert_eq!(values[1], KeyValue::Int64(2));
704 }
705 other => panic!("expected struct key, got {:?}", other),
706 }
707
708 assert!(
709 key1.is_none(),
710 "struct row with a null child should not produce a key",
711 );
712 }
713}