@@ -34,8 +34,65 @@ use datafusion_expr::ColumnarValue;
34
34
35
35
use itertools:: izip;
36
36
37
- /// Expression that can be evaluated against a RecordBatch
37
+ /// `PhysicalExpr` evaluate DataFusion expressions such as `A + 1`, or `CAST(c1
38
+ /// AS int)`.
39
+ ///
40
+ /// `PhysicalExpr` are the physical counterpart to [`Expr`] used in logical
41
+ /// planning, and can be evaluated directly on a [`RecordBatch`]. They are
42
+ /// normally created from `Expr` by a [`PhysicalPlanner`] and can be created
43
+ /// directly using [`create_physical_expr`].
44
+ ///
38
45
/// A Physical expression knows its type, nullability and how to evaluate itself.
46
+ ///
47
+ /// [`PhysicalPlanner`]: https://docs.rs/datafusion/latest/datafusion/physical_planner/trait.PhysicalPlanner.html
48
+ /// [`create_physical_expr`]: crate::create_physical_expr
49
+ /// [`Expr`]: datafusion_expr::Expr
50
+ ///
51
+ /// # Example: Create `PhysicalExpr` from `Expr`
52
+ /// ```
53
+ /// # use arrow_schema::{DataType, Field, Schema};
54
+ /// # use datafusion_common::DFSchema;
55
+ /// # use datafusion_expr::{Expr, col, lit};
56
+ /// # use datafusion_physical_expr::create_physical_expr;
57
+ /// # use datafusion_physical_expr::execution_props::ExecutionProps;
58
+ /// // For a logical expression `a = 1`, we can create a physical expression
59
+ /// let expr = col("a").eq(lit(1));
60
+ /// // To create a PhysicalExpr we need 1. a schema
61
+ /// let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
62
+ /// let df_schema = DFSchema::try_from(schema).unwrap();
63
+ /// // 2. ExecutionProps
64
+ /// let props = ExecutionProps::new();
65
+ /// // We can now create a PhysicalExpr:
66
+ /// let physical_expr = create_physical_expr(&expr, &df_schema, &props).unwrap();
67
+ /// ```
68
+ ///
69
+ /// # Example: Executing a PhysicalExpr to obtain [`ColumnarValue`]
70
+ /// ```
71
+ /// # use std::sync::Arc;
72
+ /// # use arrow_array::{cast::AsArray, BooleanArray, Int32Array, RecordBatch};
73
+ /// # use arrow_schema::{DataType, Field, Schema};
74
+ /// # use datafusion_common::{assert_batches_eq, DFSchema};
75
+ /// # use datafusion_expr::{Expr, col, lit, ColumnarValue};
76
+ /// # use datafusion_physical_expr::create_physical_expr;
77
+ /// # use datafusion_physical_expr::execution_props::ExecutionProps;
78
+ /// # let expr = col("a").eq(lit(1));
79
+ /// # let schema = Schema::new(vec![Field::new("a", DataType::Int32, true)]);
80
+ /// # let df_schema = DFSchema::try_from(schema.clone()).unwrap();
81
+ /// # let props = ExecutionProps::new();
82
+ /// // Given a PhysicalExpr, for `a = 1` we can evaluate it against a RecordBatch like this:
83
+ /// let physical_expr = create_physical_expr(&expr, &df_schema, &props).unwrap();
84
+ /// // Input of [1,2,3]
85
+ /// let input_batch = RecordBatch::try_from_iter(vec![
86
+ /// ("a", Arc::new(Int32Array::from(vec![1, 2, 3])) as _)
87
+ /// ]).unwrap();
88
+ /// // The result is a ColumnarValue (either an Array or a Scalar)
89
+ /// let result = physical_expr.evaluate(&input_batch).unwrap();
90
+ /// // In this case, a BooleanArray with the result of the comparison
91
+ /// let ColumnarValue::Array(arr) = result else {
92
+ /// panic!("Expected an array")
93
+ /// };
94
+ /// assert_eq!(arr.as_boolean(), &BooleanArray::from(vec![true, false, false]));
95
+ /// ```
39
96
pub trait PhysicalExpr : Send + Sync + Display + Debug + PartialEq < dyn Any > {
40
97
/// Returns the physical expression as [`Any`] so that it can be
41
98
/// downcast to a specific implementation.
0 commit comments