繁体   English   中英

pyspark中的DataFilter是什么?

[英]What is DataFilter in pyspark?

我在查询执行计划中看到名为DataFilter的东西:

FileScan parquet [product_id#12,price#14] Batched: true, DataFilters: [isnotnull(product_id#12)], Format: Parquet, Location: InMemoryFileIndex[gs://monsoon-credittech.appspot.com/spark_datasets/products_parquet_dtc], PartitionFilters: [], PushedFilters: [IsNotNull(product_id)], ReadSchema: struct<product_id:int,price:int>

有一个

  • 分区过滤器:[]
  • 推送过滤器:[IsNotNull(product_id)]
  • 数据过滤器:[isnotnull(product_id#12)]

我了解PartitionFilterPushedFilter 但是,这里显示的DataFilter是什么? 这里有一个类似问题的答案。 但是,给出的DataFilter的定义正是我认为的PushedFilter是什么(此外,该答案有 1 个反对票)。 那么,我对PushedFilter的理解是错误的吗? 如果不是,那么DataFilter是什么?

此说明适用于本文发布时 Spark 的最新版本 (3.3.1)。

PushedFiltersDataFilters的一个子集,您可以在DataSourceScanExec.scala中看到这一点。 它们是DataFilters ,我们可以下推其谓词以过滤您尝试读入的文件的元数据,而不是针对数据本身。 对元数据进行过滤当然比对数据本身进行过滤要快得多,因为这样做时您可以跳过读取大块数据。

因此,为了构造一切,我们有:

  • PartitionFilters :分区列上的过滤器。 使您能够忽略 parquet 文件中的目录。
  • DataFilters :非分区列的过滤器。
    • PushedFilters :那些我们可以下推其谓词的DataFilters
    • 因此,当过滤器是DataFilter而不是PushedFilter时,这意味着我们无法下推谓词来过滤基础文件的元数据。

例子

让我们以镶木地板文件为例(并非所有文件格式都支持谓词下推,但镶木地板文件支持):

import org.apache.spark.sql.functions.col

val df = Seq(
  (1,2,3),
  (2,2,3),
  (3,20,300),
  (1,24,299),
).toDF("colA", "colB", "colC")

df.write.partitionBy("colA").mode("overwrite").parquet("datafilter.parquet")

所以我们只是在编写一个由colA列分区的镶木地板文件。 文件结构如下所示:

datafilter.parquet/
├── colA=1
│   ├── part-00000-55cb3320-f145-4d64-8cba-55a72111c0c8.c000.snappy.parquet
│   └── part-00003-55cb3320-f145-4d64-8cba-55a72111c0c8.c000.snappy.parquet
├── colA=2
│   └── part-00001-55cb3320-f145-4d64-8cba-55a72111c0c8.c000.snappy.parquet
├── colA=3
│   └── part-00002-55cb3320-f145-4d64-8cba-55a72111c0c8.c000.snappy.parquet
└── _SUCCESS

让我们看一下 3 种过滤器类型:

分区过滤器

spark.read.parquet("./datafilter.parquet").filter(col("colA") < 10).explain

== Physical Plan ==
*(1) ColumnarToRow
+- FileScan parquet [colB#165,colC#166,colA#167] Batched: true, DataFilters: [], Format: Parquet, Location: InMemoryFileIndex(1 paths)[file:somePath/spark-tests/datafilter.parquet], PartitionFilters: [isnotnull(colA#167), (colA#167 < 10)], PushedFilters: [], ReadSchema: struct<colB:int,colC:int>

在这里你看到我们的过滤器是一个PartitionFilter ,因为我们的数据已经被colA分区,我们可以很容易地过滤目录。

压入过滤器

spark.read.parquet("./datafilter.parquet").filter(col("colB") < 10).explain

== Physical Plan ==
*(1) Filter (isnotnull(colB#172) AND (colB#172 < 10))
+- *(1) ColumnarToRow
   +- FileScan parquet [colB#172,colC#173,colA#174] Batched: true, DataFilters: [isnotnull(colB#172), (colB#172 < 10)], Format: Parquet, Location: InMemoryFileIndex(1 paths)[file:somePath/spark-tests/datafilter.parquet], PartitionFilters: [], PushedFilters: [IsNotNull(colB), LessThan(colB,10)], ReadSchema: struct<colB:int,colC:int>

在这里您可以看到我们的过滤器 ( colB < 10 ) 构成了DataFilters的一部分。 这是因为colB不是分区列。

它也是PushedFilters的一部分,因为这是我们可以下推的谓词。 Parquet 文件将块的最小值和最大值存储为元数据。 所以如果一个块的最小值大于 10,我们知道我们可以跳过读取这个块。

非推送过滤器

spark.read.parquet("./datafilter.parquet").filter(col("colB") < col("colC")).explain

== Physical Plan ==
*(1) Filter ((isnotnull(colB#179) AND isnotnull(colC#180)) AND (colB#179 < colC#180))
+- *(1) ColumnarToRow
   +- FileScan parquet [colB#179,colC#180,colA#181] Batched: true, DataFilters: [isnotnull(colB#179), isnotnull(colC#180), (colB#179 < colC#180)], Format: Parquet, Location: InMemoryFileIndex(1 paths)[file:somePath/spark-tests/datafilter.parquet], PartitionFilters: [], PushedFilters: [IsNotNull(colB), IsNotNull(colC)], ReadSchema: struct<colB:int,colC:int>

这个过滤器比较复杂。 colB < colC不是我们可以下推以过滤到 parquet 文件的元数据的过滤器。 这意味着我们需要在 memory 中读取完整数据并进行过滤。

问题未解决?试试以下方法:

pyspark中的DataFilter是什么?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2023 STACKOOM.COM