Skip to content

Commit a84579d

Browse files
Optimize generic InList static filtering
1 parent afc196b commit a84579d

1 file changed

Lines changed: 14 additions & 23 deletions

File tree

datafusion/physical-expr/src/expressions/in_list/array_static_filter.rs

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ use arrow::buffer::{BooleanBuffer, NullBuffer};
2323
use arrow::compute::{SortOptions, take};
2424
use arrow::datatypes::DataType;
2525
use arrow::util::bit_iterator::BitIndexIterator;
26-
use datafusion_common::HashMap;
2726
use datafusion_common::Result;
2827
use datafusion_common::hash_utils::{RandomState, with_hashes};
29-
use hashbrown::hash_map::RawEntryMut;
28+
use hashbrown::HashTable;
3029

3130
use super::result::build_in_list_result;
3231
use super::static_filter::StaticFilter;
@@ -36,11 +35,8 @@ use super::static_filter::StaticFilter;
3635
pub(super) struct ArrayStaticFilter {
3736
in_array: ArrayRef,
3837
state: RandomState,
39-
/// Used to provide a lookup from value to in list index
40-
///
41-
/// Note: usize::hash is not used, instead the raw entry
42-
/// API is used to store entries w.r.t their value
43-
map: HashMap<usize, (), ()>,
38+
/// Stores indices into `in_array` for O(1) lookups.
39+
table: HashTable<usize>,
4440
}
4541

4642
impl ArrayStaticFilter {
@@ -56,36 +52,34 @@ impl ArrayStaticFilter {
5652
return Ok(ArrayStaticFilter {
5753
in_array,
5854
state: RandomState::default(),
59-
map: HashMap::with_hasher(()),
55+
table: HashTable::new(),
6056
});
6157
}
6258

6359
let state = RandomState::default();
64-
let map = Self::build_haystack_map(&in_array, &state)?;
60+
let table = Self::build_haystack_table(&in_array, &state)?;
6561

6662
Ok(Self {
6763
in_array,
6864
state,
69-
map,
65+
table,
7066
})
7167
}
7268

73-
fn build_haystack_map(
69+
fn build_haystack_table(
7470
haystack: &ArrayRef,
7571
state: &RandomState,
76-
) -> Result<HashMap<usize, (), ()>> {
77-
let mut map: HashMap<usize, (), ()> = HashMap::with_hasher(());
72+
) -> Result<HashTable<usize>> {
73+
let mut table = HashTable::new();
7874

7975
with_hashes([haystack.as_ref()], state, |hashes| -> Result<()> {
8076
let cmp = make_comparator(haystack, haystack, SortOptions::default())?;
8177

8278
let insert_value = |idx| {
8379
let hash = hashes[idx];
84-
if let RawEntryMut::Vacant(v) = map
85-
.raw_entry_mut()
86-
.from_hash(hash, |x| cmp(*x, idx).is_eq())
87-
{
88-
v.insert_with_hasher(hash, idx, (), |x| hashes[*x]);
80+
// Only insert if not already present (deduplication)
81+
if table.find(hash, |&x| cmp(x, idx).is_eq()).is_none() {
82+
table.insert_unique(hash, idx, |&x| hashes[x]);
8983
}
9084
};
9185

@@ -100,7 +94,7 @@ impl ArrayStaticFilter {
10094
Ok(())
10195
})?;
10296

103-
Ok(map)
97+
Ok(table)
10498
}
10599

106100
fn find_needles_in_haystack(
@@ -122,10 +116,7 @@ impl ArrayStaticFilter {
122116
#[inline(always)]
123117
|i| {
124118
let hash = needle_hashes[i];
125-
self.map
126-
.raw_entry()
127-
.from_hash(hash, |idx| cmp(i, *idx).is_eq())
128-
.is_some()
119+
self.table.find(hash, |&idx| cmp(i, idx).is_eq()).is_some()
129120
},
130121
))
131122
})

0 commit comments

Comments
 (0)