Apache spark 在read.csv期间,Spark推断具有限制的架构

Apache spark 在read.csv期间,Spark推断具有限制的架构,apache-spark,Apache Spark,我想使用一小部分行(比如limit(100))从CSV文件目录中推断Spark.DataFrame模式 但是,将inferSchema设置为True意味着文件canrdd的输入大小/记录数似乎总是等于所有CSV文件中的行数 有没有一种方法可以使文件扫描更具选择性,这样Spark在推断模式时会看到更少的行 注意:将设置为

我想使用一小部分行(比如
limit(100)
)从CSV文件目录中推断Spark.DataFrame模式

但是,将
inferSchema
设置为
True
意味着
文件canrdd
输入大小/记录数似乎总是等于所有CSV文件中的行数

有没有一种方法可以使文件扫描更具选择性,这样Spark在推断模式时会看到更少的行


注意:将设置为<1.0没有所需的行为,尽管很明显,Infreschema只使用采样的行子集。

您可以将输入数据的子集读取到字符串数据集中。 CSV方法允许您将其作为参数传递

下面是一个简单的示例(我将把读取输入文件中的行示例留给您):

在spark shell中运行时,上面的最后一行打印出来(为了可读性,我重新格式化了它):


这是我有限的输入数据集的正确模式。

假设您只对该模式感兴趣,下面是一种基于本文中的帖子的可能方法

与上面的答案不同,这种方法尝试直接推断模式,就像DataFrameReader.csv()在后台所做的那样(但不需要使用该模式构建额外的数据集,我们只会使用该数据集从中检索模式)

模式是基于数据集[String]推断的,该数据集只包含输入文件中作为纯文本字符串的第一行
sampleSize

尝试从数据检索样本时,Spark只有两种类型的方法:

  • 检索给定百分比数据的方法。此操作从所有分区获取随机样本。它得益于更高的并行性,但它必须读取所有输入文件
  • 方法检索特定数量的行。此操作必须收集驱动程序上的数据,但它可以读取单个分区(如果所需的行数足够低)
  • 由于您提到要使用特定的少量行,并且希望避免接触所有数据,因此我提供了一个基于选项2的解决方案


    备注:DataFrameReader.textFile方法接受文件和文件夹的路径,并且它还有一个varargs变量,因此,您可以传入一个或多个文件或文件夹。

    您始终可以在tmp csv文件中写入两百行,然后使用模式推断读取该文件,否则csv源将始终扫描整个文件以推断模式…对;有几种“带外”方法有效;我希望避免这种情况。但是,谢谢@eliasah!这可以在Spark 3+中解决,随机过滤数据,然后将其存储到临时文件中,读回临时文件,然后推断模式?是的,这很聪明!与带外解决方案类似,我没有利用执行器的分布式读取,而是在驱动程序上执行本地读取。但是它完成了任务。谢谢。如果从(比如HDFS)读取数据,您仍然可以从集群读取数据,并在创建csvRDD数据集时使用limit方法。这就是你所说的遗嘱执行人的分布式阅读吗?@绝地,如果这对你有帮助,你能接受它作为答案吗?谢谢!对,这里有一个共同的主题;为了避免从所有分区进行读取,此解决方案和@GMc的解决方案都在驱动程序上构造读取行的子集,并从中创建RDD。
    val data = List("1,2,hello", "2,3,what's up?")
    val csvRDD = sc.parallelize(data)
    val df = spark.read.option("inferSchema","true").csv(csvRDD.toDS)
    df.schema
    
    res4: org.apache.spark.sql.types.StructType = 
        StructType(
          StructField(_c0,IntegerType,true),
          StructField(_c1,IntegerType,true),
          StructField(_c2,StringType,true)
        )
    
    import org.apache.spark.sql.execution.datasources.csv.{CSVOptions, TextInputCSVDataSource}
    def inferSchemaFromSample(sparkSession: SparkSession, fileLocation: String, sampleSize: Int, isFirstRowHeader: Boolean): StructType = {
      // Build a Dataset composed of the first sampleSize lines from the input files as plain text strings
      val dataSample: Array[String] = sparkSession.read.textFile(fileLocation).head(sampleSize)
      import sparkSession.implicits._
      val sampleDS: Dataset[String] = sparkSession.createDataset(dataSample)
      // Provide information about the CSV files' structure
      val firstLine = dataSample.head
      val extraOptions = Map("inferSchema" -> "true",   "header" -> isFirstRowHeader.toString)
      val csvOptions: CSVOptions = new CSVOptions(extraOptions, sparkSession.sessionState.conf.sessionLocalTimeZone)
      // Infer the CSV schema based on the sample data
      val schema = TextInputCSVDataSource.inferFromDataset(sparkSession, sampleDS, Some(firstLine), csvOptions)
      schema
    }