MCPcopy Create free account
hub / github.com/apache/datafusion / analyze

Function analyze

datafusion/physical-expr/src/analysis.rs:164–231  ·  view source on GitHub ↗

Attempts to refine column boundaries and compute a selectivity value. The function accepts boundaries of the input columns in the `context` parameter. It then tries to tighten these boundaries based on the provided `expr`. The resulting selectivity value is calculated by comparing the initial and final boundaries. The computation assumes that the data within the column is uniformly distributed an

(
    expr: &Arc<dyn PhysicalExpr>,
    context: AnalysisContext,
    schema: &Schema,
)

Source from the content-addressed store, hash-verified

162///
163/// * `AnalysisContext` constructed by pruned boundaries and a selectivity value.
164pub fn analyze(
165 expr: &Arc<dyn PhysicalExpr>,
166 context: AnalysisContext,
167 schema: &Schema,
168) -> Result<AnalysisContext> {
169 let initial_boundaries = &context.boundaries;
170
171 if initial_boundaries
172 .iter()
173 .all(|bound| bound.interval.is_none())
174 {
175 assert_or_internal_err!(
176 !initial_boundaries
177 .iter()
178 .any(|bound| bound.distinct_count != Precision::Exact(0)),
179 "ExprBoundaries has a non-zero distinct count although it represents an empty table"
180 );
181 assert_or_internal_err!(
182 context.selectivity.unwrap_or(0.0) == 0.0,
183 "AnalysisContext has a non-zero selectivity although it represents an empty table"
184 );
185 Ok(context)
186 } else if initial_boundaries
187 .iter()
188 .any(|bound| bound.interval.is_none())
189 {
190 internal_err!(
191 "AnalysisContext is an inconsistent state. Some columns represent empty table while others don't"
192 )
193 } else {
194 let mut target_boundaries = context.boundaries;
195 let mut graph = ExprIntervalGraph::try_new(Arc::clone(expr), schema)?;
196 let columns = collect_columns(expr)
197 .into_iter()
198 .map(|c| Arc::new(c) as _)
199 .collect::<Vec<_>>();
200
201 let mut target_indices_and_boundaries = vec![];
202 let target_expr_and_indices = graph.gather_node_indices(columns.as_slice());
203
204 for (expr, index) in &target_expr_and_indices {
205 if let Some(column) = expr.downcast_ref::<Column>()
206 && let Some(bound) =
207 target_boundaries.iter().find(|b| b.column == *column)
208 {
209 // Now, it's safe to unwrap
210 target_indices_and_boundaries
211 .push((*index, bound.interval.as_ref().unwrap().clone()));
212 }
213 }
214
215 match graph.update_ranges(&mut target_indices_and_boundaries, Interval::TRUE)? {
216 PropagationResult::Success => {
217 shrink_boundaries(&graph, target_boundaries, &target_expr_and_indices)
218 }
219 PropagationResult::Infeasible => {
220 // If the propagation result is infeasible, set intervals to None
221 target_boundaries

Calls 15

collect_columnsFunction · 0.85
newFunction · 0.85
shrink_boundariesFunction · 0.85
allMethod · 0.80
is_noneMethod · 0.80
gather_node_indicesMethod · 0.80
update_rangesMethod · 0.80
with_selectivityMethod · 0.80
iterMethod · 0.45
anyMethod · 0.45
mapMethod · 0.45
into_iterMethod · 0.45

Tested by 4

test_analyzeFunction · 0.68

Used in the wild real call sites across dependent graphs

searching dependent graphs…