use arrow_schema::{Schema, SchemaRef};
#[cfg(feature = "datafusion")]
use datafusion_expr::Expr as DfExpr;
use parquet::{
arrow::async_reader::{AsyncFileReader, ParquetRecordBatchStreamBuilder},
file::metadata::ParquetMetaData,
};
#[cfg(feature = "datafusion")]
use crate::AisleError;
#[cfg(feature = "datafusion")]
use crate::compile::{
SchemaPathIndex, build_schema_path_index, collect_columns_from_df_expr,
compile_pruning_ir_with_index,
};
use crate::{
AisleResult,
expr::Expr,
prune::{
AsyncBloomFilterProvider, PruneOptions, PruneResult, prune_compiled,
prune_compiled_with_bloom_provider,
},
};
#[derive(Debug, Clone)]
pub struct Pruner {
schema: SchemaRef,
#[cfg(feature = "datafusion")]
schema_index: SchemaPathIndex,
options: PruneOptions,
}
impl Pruner {
#[cfg(feature = "datafusion")]
pub fn try_compile(&self, expr: &DfExpr) -> Result<CompiledPruner, Vec<AisleError>> {
let compile = compile_pruning_ir_with_index(expr, self.schema.as_ref(), &self.schema_index);
if compile.has_errors() {
Err(compile.errors().to_vec())
} else {
Ok(CompiledPruner {
schema: self.schema.clone(),
options: self.options.clone(),
compile,
})
}
}
pub fn try_new(schema: SchemaRef) -> Result<Self, String> {
Self::try_with_options(schema, PruneOptions::default())
}
pub fn try_with_options(schema: SchemaRef, options: PruneOptions) -> Result<Self, String> {
if schema.fields().is_empty() {
return Err("Schema must have at least one field".to_string());
}
#[cfg(feature = "datafusion")]
let schema_index = build_schema_path_index(schema.as_ref());
Ok(Self {
schema,
#[cfg(feature = "datafusion")]
schema_index,
options,
})
}
pub fn schema(&self) -> &Schema {
self.schema.as_ref()
}
pub fn options(&self) -> &PruneOptions {
&self.options
}
#[cfg(feature = "datafusion")]
pub fn prune(&self, metadata: &ParquetMetaData, expr: &DfExpr) -> PruneResult {
let compile = compile_pruning_ir_with_index(expr, self.schema.as_ref(), &self.schema_index);
let predicate_columns = collect_columns_from_df_expr(expr);
prune_compiled(
metadata,
self.schema.as_ref(),
compile,
&self.options,
None,
predicate_columns,
)
}
pub fn prune_ir(&self, metadata: &ParquetMetaData, predicates: &[Expr]) -> PruneResult {
let compile = AisleResult::from_ir_slice(predicates);
prune_compiled(
metadata,
self.schema.as_ref(),
compile,
&self.options,
None,
None,
)
}
#[cfg(feature = "datafusion")]
pub async fn prune_with_async_reader<T: AsyncFileReader + 'static>(
&self,
builder: &mut ParquetRecordBatchStreamBuilder<T>,
expr: &DfExpr,
) -> PruneResult {
let compile = compile_pruning_ir_with_index(expr, self.schema.as_ref(), &self.schema_index);
let predicate_columns = collect_columns_from_df_expr(expr);
let metadata = builder.metadata().clone();
prune_compiled_with_bloom_provider(
metadata.as_ref(),
self.schema.as_ref(),
compile,
&self.options,
builder,
None,
predicate_columns,
)
.await
}
pub async fn prune_ir_with_async_reader<T: AsyncFileReader + 'static>(
&self,
builder: &mut ParquetRecordBatchStreamBuilder<T>,
predicates: &[Expr],
) -> PruneResult {
let compile = AisleResult::from_ir_slice(predicates);
let metadata = builder.metadata().clone();
prune_compiled_with_bloom_provider(
metadata.as_ref(),
self.schema.as_ref(),
compile,
&self.options,
builder,
None,
None,
)
.await
}
#[cfg(feature = "datafusion")]
pub async fn prune_with_bloom_provider<P: AsyncBloomFilterProvider>(
&self,
metadata: &ParquetMetaData,
expr: &DfExpr,
provider: &mut P,
) -> PruneResult {
let compile = compile_pruning_ir_with_index(expr, self.schema.as_ref(), &self.schema_index);
let predicate_columns = collect_columns_from_df_expr(expr);
prune_compiled_with_bloom_provider(
metadata,
self.schema.as_ref(),
compile,
&self.options,
provider,
None,
predicate_columns,
)
.await
}
pub async fn prune_ir_with_bloom_provider<P: AsyncBloomFilterProvider>(
&self,
metadata: &ParquetMetaData,
predicates: &[Expr],
provider: &mut P,
) -> PruneResult {
let compile = AisleResult::from_ir_slice(predicates);
prune_compiled_with_bloom_provider(
metadata,
self.schema.as_ref(),
compile,
&self.options,
provider,
None,
None,
)
.await
}
}
#[derive(Debug, Clone)]
pub struct CompiledPruner {
schema: SchemaRef,
options: PruneOptions,
compile: AisleResult,
}
impl CompiledPruner {
pub fn compile_result(&self) -> &AisleResult {
&self.compile
}
pub fn options(&self) -> &PruneOptions {
&self.options
}
pub fn prune(&self, metadata: &ParquetMetaData) -> PruneResult {
prune_compiled(
metadata,
self.schema.as_ref(),
self.compile.clone(),
&self.options,
None,
None,
)
}
pub async fn prune_with_async_reader<T: AsyncFileReader + 'static>(
&self,
builder: &mut ParquetRecordBatchStreamBuilder<T>,
) -> PruneResult {
let metadata = builder.metadata().clone();
prune_compiled_with_bloom_provider(
metadata.as_ref(),
self.schema.as_ref(),
self.compile.clone(),
&self.options,
builder,
None,
None,
)
.await
}
pub async fn prune_with_bloom_provider<P: AsyncBloomFilterProvider>(
&self,
metadata: &ParquetMetaData,
provider: &mut P,
) -> PruneResult {
prune_compiled_with_bloom_provider(
metadata,
self.schema.as_ref(),
self.compile.clone(),
&self.options,
provider,
None,
None,
)
.await
}
}