This is an automated email from the ASF dual-hosted git repository. agrove pushed a commit to branch comet-parquet-exec in repository https://gitbox.apache.org/repos/asf/datafusion-comet.git
commit 9535117d0d094ce0d7b381e778b0a0195bb9bacd Author: Matt Butrovich <[email protected]> AuthorDate: Fri Nov 8 13:54:27 2024 -0500 Stash changes. Maybe runs TPC-H q1? --- native/Cargo.lock | 68 ++++++++++++++++++++-- native/Cargo.toml | 4 +- native/core/Cargo.toml | 4 +- native/core/src/execution/datafusion/planner.rs | 66 +++++++++++++++++++++ native/proto/src/proto/operator.proto | 3 + .../org/apache/comet/serde/QueryPlanSerde.scala | 41 ++++++++++++- 6 files changed, 179 insertions(+), 7 deletions(-) diff --git a/native/Cargo.lock b/native/Cargo.lock index 39db7f9d..95595848 100644 --- a/native/Cargo.lock +++ b/native/Cargo.lock @@ -436,7 +436,18 @@ checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", - "brotli-decompressor", + "brotli-decompressor 2.5.1", +] + +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor 4.0.1", ] [[package]] @@ -449,6 +460,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -841,6 +862,7 @@ dependencies = [ "num_cpus", "object_store", "parking_lot", + "parquet", "paste", "pin-project-lite", "rand", @@ -877,7 +899,7 @@ dependencies = [ "arrow-schema", "assertables", "async-trait", - "brotli", + "brotli 3.5.0", "bytes", "crc32fast", "criterion", @@ -901,6 +923,7 @@ dependencies = [ "lz4", "mimalloc", "num", + "object_store", "once_cell", "parquet", "paste", @@ -914,7 +937,8 @@ dependencies = [ "tempfile", "thiserror", "tokio", - "zstd", + "url", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] @@ -964,6 +988,7 @@ dependencies = [ "libc", "num_cpus", "object_store", + "parquet", "paste", "sqlparser", "tokio", @@ -2175,16 +2200,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "310c46a70a3ba90d98fec39fa2da6d9d731e544191da6fb56c9d199484d0dd3e" dependencies = [ "ahash", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ipc", + "arrow-schema", + "arrow-select", + "base64", + "brotli 6.0.0", "bytes", "chrono", + "flate2", + "futures", "half", "hashbrown", + "lz4_flex", "num", "num-bigint", + "object_store", "paste", "seq-macro", + "snap", "thrift", + "tokio", "twox-hash 1.6.3", + "zstd 0.13.2", + "zstd-sys", ] [[package]] @@ -3395,7 +3437,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe 7.2.1", ] [[package]] @@ -3408,6 +3459,15 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.13+zstd.1.5.6" diff --git a/native/Cargo.toml b/native/Cargo.toml index 943d591d..f9af172e 100644 --- a/native/Cargo.toml +++ b/native/Cargo.toml @@ -40,7 +40,7 @@ arrow-data = { version = "53.1.0" } arrow-schema = { version = "53.1.0" } parquet = { version = "53.1.0", default-features = false, features = ["experimental"] } datafusion-common = { git = "https://github.com/apache/datafusion.git", rev = "3b6aac2" } -datafusion = { git = "https://github.com/apache/datafusion.git", rev = "3b6aac2", default-features = false, features = ["unicode_expressions", "crypto_expressions"] } +datafusion = { git = "https://github.com/apache/datafusion.git", rev = "3b6aac2", default-features = false, features = ["unicode_expressions", "crypto_expressions", "parquet"] } datafusion-functions = { git = "https://github.com/apache/datafusion.git", rev = "3b6aac2", features = ["crypto_expressions"] } datafusion-functions-nested = { git = "https://github.com/apache/datafusion.git", rev = "3b6aac2", default-features = false } datafusion-expr = { git = "https://github.com/apache/datafusion.git", rev = "3b6aac2", default-features = false } @@ -55,6 +55,8 @@ num = "0.4" rand = "0.8" regex = "1.9.6" thiserror = "1" +object_store = "0.11.0" +url = "2.2" [profile.release] debug = true diff --git a/native/core/Cargo.toml b/native/core/Cargo.toml index daa0837c..8d30b38c 100644 --- a/native/core/Cargo.toml +++ b/native/core/Cargo.toml @@ -65,7 +65,7 @@ tempfile = "3.8.0" ahash = { version = "0.8", default-features = false } itertools = "0.11.0" paste = "1.0.14" -datafusion-common = { workspace = true } +datafusion-common = { workspace = true, features= ["object_store"] } datafusion = { workspace = true } datafusion-functions-nested = { workspace = true } datafusion-expr = { workspace = true } @@ -77,6 +77,8 @@ crc32fast = "1.3.2" simd-adler32 = "0.3.7" datafusion-comet-spark-expr = { workspace = true } datafusion-comet-proto = { workspace = true } +object_store = { workspace = true } +url = { workspace = true } [dev-dependencies] pprof = { version = "0.13.0", features = ["flamegraph"] } diff --git a/native/core/src/execution/datafusion/planner.rs b/native/core/src/execution/datafusion/planner.rs index 5b53cb39..65ad73f8 100644 --- a/native/core/src/execution/datafusion/planner.rs +++ b/native/core/src/execution/datafusion/planner.rs @@ -84,6 +84,10 @@ use datafusion::{ }; use datafusion_physical_expr::aggregate::{AggregateExprBuilder, AggregateFunctionExpr}; +use datafusion::datasource::file_format::FileFormat; +use datafusion::datasource::listing::PartitionedFile; +use datafusion::datasource::physical_plan::parquet::ParquetExecBuilder; +use datafusion::datasource::physical_plan::FileScanConfig; use datafusion_comet_proto::{ spark_expression::{ self, agg_expr::ExprStruct as AggExprStruct, expr::ExprStruct, literal::Value, AggExpr, @@ -105,6 +109,7 @@ use datafusion_common::{ tree_node::{Transformed, TransformedResult, TreeNode, TreeNodeRecursion, TreeNodeRewriter}, JoinType as DFJoinType, ScalarValue, }; +use datafusion_execution::object_store::ObjectStoreUrl; use datafusion_expr::expr::find_df_window_func; use datafusion_expr::{ AggregateUDF, WindowFrame, WindowFrameBound, WindowFrameUnits, WindowFunctionDefinition, @@ -114,8 +119,11 @@ use datafusion_physical_expr::window::WindowExpr; use itertools::Itertools; use jni::objects::GlobalRef; use num::{BigInt, ToPrimitive}; +use object_store::path::Path; +use parquet::schema::parser::parse_message_type; use std::cmp::max; use std::{collections::HashMap, sync::Arc}; +use url::Url; // For clippy error on type_complexity. type ExecResult<T> = Result<T, ExecutionError>; @@ -941,6 +949,64 @@ impl PhysicalPlanner { OpStruct::Scan(scan) => { let data_types = scan.fields.iter().map(to_arrow_datatype).collect_vec(); + if scan.source == "CometScan parquet (unknown)" { + let data_schema = parse_message_type(&*scan.data_schema).unwrap(); + let required_schema = parse_message_type(&*scan.required_schema).unwrap(); + println!("data_schema: {:?}", data_schema); + println!("required_schema: {:?}", required_schema); + + let data_schema_descriptor = + parquet::schema::types::SchemaDescriptor::new(Arc::new(data_schema)); + let data_schema_arrow = parquet::arrow::schema::parquet_to_arrow_schema( + &data_schema_descriptor, + None, + ) + .unwrap(); + println!("data_schema_arrow: {:?}", data_schema_arrow); + + let required_schema_descriptor = + parquet::schema::types::SchemaDescriptor::new(Arc::new(required_schema)); + let required_schema_arrow = parquet::arrow::schema::parquet_to_arrow_schema( + &required_schema_descriptor, + None, + ) + .unwrap(); + println!("required_schema_arrow: {:?}", required_schema_arrow); + + assert!(!required_schema_arrow.fields.is_empty()); + + let mut projection_vector: Vec<usize> = + Vec::with_capacity(required_schema_arrow.fields.len()); + // TODO: could be faster with a hashmap rather than iterating over data_schema_arrow with index_of. + required_schema_arrow.fields.iter().for_each(|field| { + projection_vector.push(data_schema_arrow.index_of(field.name()).unwrap()); + }); + println!("projection_vector: {:?}", projection_vector); + + assert_eq!(projection_vector.len(), required_schema_arrow.fields.len()); + + let object_store_url = ObjectStoreUrl::local_filesystem(); + let path = Url::parse(&*scan.path).unwrap(); + + let object_store = object_store::local::LocalFileSystem::new(); + // register the object store with the runtime environment + let url = Url::try_from("file://").unwrap(); + self.session_ctx + .runtime_env() + .register_object_store(&url, Arc::new(object_store)); + + let file = PartitionedFile::from_path(path.path().to_string())?; + + let file_scan_config = + FileScanConfig::new(object_store_url, Arc::new(data_schema_arrow)) + .with_file(file) + .with_projection(Some(projection_vector)); + + let builder = ParquetExecBuilder::new(file_scan_config); + let scan = builder.build(); + return Ok((vec![], Arc::new(scan))); + } + // If it is not test execution context for unit test, we should have at least one // input source if self.exec_context_id != TEST_EXEC_CONTEXT_ID && inputs.is_empty() { diff --git a/native/proto/src/proto/operator.proto b/native/proto/src/proto/operator.proto index 533d504c..950b35ae 100644 --- a/native/proto/src/proto/operator.proto +++ b/native/proto/src/proto/operator.proto @@ -52,6 +52,9 @@ message Scan { // is purely for informational purposes when viewing native query plans in // debug mode. string source = 2; + string path = 3; + string required_schema = 4; + string data_schema = 5; } message Projection { diff --git a/spark/src/main/scala/org/apache/comet/serde/QueryPlanSerde.scala b/spark/src/main/scala/org/apache/comet/serde/QueryPlanSerde.scala index abb138b0..3775c7b2 100644 --- a/spark/src/main/scala/org/apache/comet/serde/QueryPlanSerde.scala +++ b/spark/src/main/scala/org/apache/comet/serde/QueryPlanSerde.scala @@ -29,12 +29,13 @@ import org.apache.spark.sql.catalyst.optimizer.{BuildLeft, BuildRight, Normalize import org.apache.spark.sql.catalyst.plans._ import org.apache.spark.sql.catalyst.plans.physical.{HashPartitioning, Partitioning, RangePartitioning, RoundRobinPartitioning, SinglePartition} import org.apache.spark.sql.catalyst.util.CharVarcharCodegenUtils -import org.apache.spark.sql.comet.{CometBroadcastExchangeExec, CometSinkPlaceHolder, CometSparkToColumnarExec, DecimalPrecision} +import org.apache.spark.sql.comet.{CometBroadcastExchangeExec, CometScanExec, CometSinkPlaceHolder, CometSparkToColumnarExec, DecimalPrecision} import org.apache.spark.sql.comet.execution.shuffle.CometShuffleExchangeExec import org.apache.spark.sql.execution import org.apache.spark.sql.execution._ import org.apache.spark.sql.execution.adaptive.{BroadcastQueryStageExec, ShuffleQueryStageExec} import org.apache.spark.sql.execution.aggregate.{BaseAggregateExec, HashAggregateExec, ObjectHashAggregateExec} +import org.apache.spark.sql.execution.datasources.parquet.SparkToParquetSchemaConverter import org.apache.spark.sql.execution.exchange.{BroadcastExchangeExec, ReusedExchangeExec, ShuffleExchangeExec} import org.apache.spark.sql.execution.joins.{BroadcastHashJoinExec, HashJoin, ShuffledHashJoinExec, SortMergeJoinExec} import org.apache.spark.sql.execution.window.WindowExec @@ -3151,6 +3152,44 @@ object QueryPlanSerde extends Logging with ShimQueryPlanSerde with CometExprShim // Sink operators don't have children result.clearChildren() + op match { + case cometScan: CometScanExec => + // scalastyle:off println +// System.out.println(op.simpleStringWithNodeId()) +// System.out.println(scanTypes.asJava) // Spark types for output. +// System.out.println(cometScan.output) // This is the names of the output columns. +// System.out.println(cometScan.requiredSchema); // This is the projected columns. +// System.out.println( +// cometScan.dataFilters +// ); // This is the filter expressions that have been pushed down. +// System.out.println(cometScan.relation.location.inputFiles(0)) +// System.out.println(cometScan.partitionFilters); +// System.out.println(cometScan.relation.partitionSchema) +// System.out.println(cometScan.metadata); + +// System.out.println("requiredSchema:") +// cometScan.requiredSchema.fields.foreach(field => { +// System.out.println(field.dataType) +// }) + +// System.out.println("relation.dataSchema:") +// cometScan.relation.dataSchema.fields.foreach(field => { +// System.out.println(field.dataType) +// }) + // scalastyle:on println + + val requiredSchemaParquet = + new SparkToParquetSchemaConverter(conf).convert(cometScan.requiredSchema) + val dataSchemaParquet = + new SparkToParquetSchemaConverter(conf).convert(cometScan.relation.dataSchema) + + scanBuilder.setRequiredSchema(requiredSchemaParquet.toString) + scanBuilder.setDataSchema(dataSchemaParquet.toString) + scanBuilder.setPath(cometScan.relation.location.inputFiles(0)) + case _ => + scanBuilder.setPath("") + } + Some(result.setScan(scanBuilder).build()) } else { // There are unsupported scan type --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
