This is an automated email from the ASF dual-hosted git repository.
lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-paimon.git
The following commit(s) were added to refs/heads/master by this push:
new 28d7fbefa [spark] optimize description of scan (#2505)
28d7fbefa is described below
commit 28d7fbefaae9def02a92eb297335ad1a3c08df99
Author: Yann Byron <[email protected]>
AuthorDate: Fri Dec 15 17:37:54 2023 +0800
[spark] optimize description of scan (#2505)
---
.../scala/org/apache/paimon/spark/PaimonScan.scala | 13 +++--
.../org/apache/paimon/spark/PaimonBaseScan.scala | 55 ++++++++++++++++++----
.../paimon/spark/PaimonBaseScanBuilder.scala | 42 ++++-------------
.../scala/org/apache/paimon/spark/PaimonScan.scala | 12 +++--
.../apache/paimon/spark/PaimonScanBuilder.scala | 12 -----
5 files changed, 74 insertions(+), 60 deletions(-)
diff --git
a/paimon-spark/paimon-spark-3.1/src/main/scala/org/apache/paimon/spark/PaimonScan.scala
b/paimon-spark/paimon-spark-3.1/src/main/scala/org/apache/paimon/spark/PaimonScan.scala
index 01aabe3ca..049730291 100644
---
a/paimon-spark/paimon-spark-3.1/src/main/scala/org/apache/paimon/spark/PaimonScan.scala
+++
b/paimon-spark/paimon-spark-3.1/src/main/scala/org/apache/paimon/spark/PaimonScan.scala
@@ -17,8 +17,15 @@
*/
package org.apache.paimon.spark
+import org.apache.paimon.predicate.Predicate
import org.apache.paimon.table.Table
-import org.apache.paimon.table.source.ReadBuilder
-case class PaimonScan(table: Table, readBuilder: ReadBuilder, desc: String)
- extends PaimonBaseScan(table, readBuilder, desc)
+import org.apache.spark.sql.sources.Filter
+import org.apache.spark.sql.types.StructType
+
+case class PaimonScan(
+ table: Table,
+ requiredSchema: StructType,
+ filters: Array[(Filter, Predicate)],
+ pushDownLimit: Option[Int])
+ extends PaimonBaseScan(table, requiredSchema, filters, pushDownLimit)
diff --git
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonBaseScan.scala
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonBaseScan.scala
index 4258df483..eb055ccf4 100644
---
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonBaseScan.scala
+++
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonBaseScan.scala
@@ -17,6 +17,7 @@
*/
package org.apache.paimon.spark
+import org.apache.paimon.predicate.{Predicate, PredicateBuilder}
import org.apache.paimon.spark.sources.PaimonMicroBatchStream
import org.apache.paimon.table.{DataTable, FileStoreTable, Table}
import org.apache.paimon.table.source.{ReadBuilder, Split}
@@ -24,20 +25,51 @@ import org.apache.paimon.table.source.{ReadBuilder, Split}
import org.apache.spark.sql.connector.metric.CustomMetric
import org.apache.spark.sql.connector.read.{Batch, Scan, Statistics,
SupportsReportStatistics}
import org.apache.spark.sql.connector.read.streaming.MicroBatchStream
+import org.apache.spark.sql.sources.Filter
import org.apache.spark.sql.types.StructType
import scala.collection.JavaConverters._
-abstract class PaimonBaseScan(table: Table, readBuilder: ReadBuilder, desc:
String)
+abstract class PaimonBaseScan(
+ table: Table,
+ requiredSchema: StructType,
+ filters: Array[(Filter, Predicate)],
+ pushDownLimit: Option[Int])
extends Scan
with SupportsReportStatistics {
+ private val tableRowType = table.rowType
+
+ private lazy val tableSchema = SparkTypeUtils.fromPaimonRowType(tableRowType)
+
+ protected var runtimeFilters: Array[Filter] = Array.empty
+
protected var splits: Array[Split] = _
- override def description(): String = desc
+ protected lazy val readBuilder: ReadBuilder = {
+ val _readBuilder = table.newReadBuilder()
+
+ val projection = readSchema().fieldNames.map(field =>
tableRowType.getFieldNames.indexOf(field))
+ _readBuilder.withProjection(projection)
+ if (filters.nonEmpty) {
+ val pushedPredicate = PredicateBuilder.and(filters.map(_._2): _*)
+ _readBuilder.withFilter(pushedPredicate)
+ }
+ pushDownLimit.foreach(_readBuilder.withLimit)
+
+ _readBuilder
+ }
+
+ def getSplits: Array[Split] = {
+ if (splits == null) {
+ splits = readBuilder.newScan().plan().splits().asScala.toArray
+ }
+ splits
+ }
override def readSchema(): StructType = {
- SparkTypeUtils.fromPaimonRowType(readBuilder.readType())
+ val requiredFieldNames = requiredSchema.fieldNames
+ StructType(tableSchema.filter(field =>
requiredFieldNames.contains(field.name)))
}
override def toBatch: Batch = {
@@ -52,13 +84,6 @@ abstract class PaimonBaseScan(table: Table, readBuilder:
ReadBuilder, desc: Stri
PaimonStatistics(this)
}
- def getSplits: Array[Split] = {
- if (splits == null) {
- splits = readBuilder.newScan().plan().splits().asScala.toArray
- }
- splits
- }
-
override def supportedCustomMetrics: Array[CustomMetric] = {
val paimonMetrics: Array[CustomMetric] = table match {
case _: FileStoreTable =>
@@ -72,4 +97,14 @@ abstract class PaimonBaseScan(table: Table, readBuilder:
ReadBuilder, desc: Stri
}
super.supportedCustomMetrics() ++ paimonMetrics
}
+
+ override def description(): String = {
+ val pushedFiltersStr = if (filters.nonEmpty) {
+ ", PushedFilters: [" + filters.map(_._1).mkString(",") + "]"
+ } else {
+ ""
+ }
+ s"PaimonScan: [${table.name}]" + pushedFiltersStr +
+ pushDownLimit.map(limit => s", Limit: [$limit]").getOrElse("")
+ }
}
diff --git
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonBaseScanBuilder.scala
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonBaseScanBuilder.scala
index 0a29f9d76..53fe78b20 100644
---
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonBaseScanBuilder.scala
+++
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonBaseScanBuilder.scala
@@ -19,7 +19,6 @@ package org.apache.paimon.spark
import org.apache.paimon.predicate.{PartitionPredicateVisitor, Predicate,
PredicateBuilder}
import org.apache.paimon.table.Table
-import org.apache.paimon.table.source.ReadBuilder
import org.apache.spark.internal.Logging
import org.apache.spark.sql.connector.read.{Scan, ScanBuilder,
SupportsPushDownFilters, SupportsPushDownRequiredColumns}
@@ -34,29 +33,14 @@ abstract class PaimonBaseScanBuilder(table: Table)
with SupportsPushDownRequiredColumns
with Logging {
- protected var predicates: Option[Predicate] = None
+ protected var requiredSchema: StructType =
SparkTypeUtils.fromPaimonRowType(table.rowType())
- protected var pushed: Option[Array[Filter]] = None
+ protected var pushed: Array[(Filter, Predicate)] = Array.empty
- protected var projectedIndexes: Option[Array[Int]] = None
-
- protected def getReadBuilder: ReadBuilder = {
- val readBuilder = table.newReadBuilder()
- projectedIndexes.foreach(readBuilder.withProjection)
- predicates.foreach(readBuilder.withFilter)
-
- readBuilder
- }
-
- protected def getDescription: String = {
- val description = s"PaimonTable: [${table.name()}]"
- description + pushed
- .map(filters => s" PushedFilters: [${filters.mkString(", ")}]")
- .getOrElse("")
- }
+ protected var pushDownLimit: Option[Int] = None
override def build(): Scan = {
- PaimonScan(table, getReadBuilder, getDescription)
+ PaimonScan(table, requiredSchema, pushed, pushDownLimit)
}
/**
@@ -65,9 +49,8 @@ abstract class PaimonBaseScanBuilder(table: Table)
* filters must be interpreted as ANDed together.
*/
override def pushFilters(filters: Array[Filter]): Array[Filter] = {
- val pushable = mutable.ArrayBuffer.empty[Filter]
+ val pushable = mutable.ArrayBuffer.empty[(Filter, Predicate)]
val postScan = mutable.ArrayBuffer.empty[Filter]
- val predicates = mutable.ArrayBuffer.empty[Predicate]
val converter = new SparkFilterConverter(table.rowType)
val visitor = new PartitionPredicateVisitor(table.partitionKeys())
@@ -75,8 +58,7 @@ abstract class PaimonBaseScanBuilder(table: Table)
filter =>
try {
val predicate = converter.convert(filter)
- pushable.append(filter)
- predicates.append(predicate)
+ pushable.append((filter, predicate))
if (!predicate.visit(visitor)) postScan.append(filter)
} catch {
case e: UnsupportedOperationException =>
@@ -85,21 +67,17 @@ abstract class PaimonBaseScanBuilder(table: Table)
}
}
- if (predicates.nonEmpty) {
- this.predicates = Some(PredicateBuilder.and(predicates: _*))
+ if (pushable.nonEmpty) {
+ this.pushed = pushable.toArray
}
- this.pushed = Some(pushable.toArray)
postScan.toArray
}
override def pushedFilters(): Array[Filter] = {
- pushed.getOrElse(Array.empty)
+ pushed.map(_._1)
}
override def pruneColumns(requiredSchema: StructType): Unit = {
- val pruneFields = requiredSchema.fieldNames
- val fieldNames = table.rowType.getFieldNames
- val projected = pruneFields.map(field => fieldNames.indexOf(field))
- this.projectedIndexes = Some(projected)
+ this.requiredSchema = requiredSchema
}
}
diff --git
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonScan.scala
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonScan.scala
index a51d09a7d..c8ca07484 100644
---
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonScan.scala
+++
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonScan.scala
@@ -17,18 +17,23 @@
*/
package org.apache.paimon.spark
+import org.apache.paimon.predicate.Predicate
import org.apache.paimon.table.Table
-import org.apache.paimon.table.source.ReadBuilder
import org.apache.spark.sql.Utils.fieldReference
import org.apache.spark.sql.connector.expressions.NamedReference
import org.apache.spark.sql.connector.read.SupportsRuntimeFiltering
import org.apache.spark.sql.sources.{Filter, In}
+import org.apache.spark.sql.types.StructType
import scala.collection.JavaConverters._
-case class PaimonScan(table: Table, readBuilder: ReadBuilder, desc: String)
- extends PaimonBaseScan(table, readBuilder, desc)
+case class PaimonScan(
+ table: Table,
+ requiredSchema: StructType,
+ filters: Array[(Filter, Predicate)],
+ pushDownLimit: Option[Int])
+ extends PaimonBaseScan(table, requiredSchema, filters, pushDownLimit)
with SupportsRuntimeFiltering {
override def filterAttributes(): Array[NamedReference] = {
@@ -49,6 +54,7 @@ case class PaimonScan(table: Table, readBuilder: ReadBuilder,
desc: String)
case _ => None
}
if (partitionFilter.nonEmpty) {
+ this.runtimeFilters = filters
readBuilder.withFilter(partitionFilter.head)
splits = readBuilder.newScan().plan().splits().asScala.toArray
}
diff --git
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonScanBuilder.scala
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonScanBuilder.scala
index 6c9071ed7..64f22d91f 100644
---
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonScanBuilder.scala
+++
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/PaimonScanBuilder.scala
@@ -26,18 +26,6 @@ class PaimonScanBuilder(table: Table)
extends PaimonBaseScanBuilder(table)
with SupportsPushDownLimit {
- private var pushDownLimit: Option[Int] = None
-
- override protected def getReadBuilder: ReadBuilder = {
- val readBuilder = super.getReadBuilder
- pushDownLimit.foreach(readBuilder.withLimit)
- readBuilder
- }
-
- override protected def getDescription: String = {
- super.getDescription + pushDownLimit.map(limit => s" Limit:
[$limit]").getOrElse("")
- }
-
override def pushLimit(limit: Int): Boolean = {
if (table.isInstanceOf[AppendOnlyFileStoreTable]) {
pushDownLimit = Some(limit)