火花可以忽略不可读的文件吗?

时间:2018-12-14 15:56:07

标签: apache-spark pyspark apache-spark-sql

我具有以下格式的文件结构

s3://<bucket>/year=2018/month=11/day=26/hour=10/department=x/part-xxxxx.gz.parquet

我的AWS凭证无法访问所有department=值,只有少数几个。

我正在尝试

df = spark.read.parquet("s3://<bucket>/year=2018/") 

失败
java.io.IOException: Could not read footer: java.io.IOException: Could not read footer for file FileStatus{path=s3://<bucket>/year=2018/month=11/day=26/hour=10/department=yyyyyy/part-xxxxx.gz.parquet; isDirectory=false; length=104448; replication=0; blocksize=0; modification_time=0; access_time=0; owner=; group=; permission=rw-rw-rw-; isSymlink=false}

它显然失败了,因为我只能访问department=x而不能访问department=yyyy,我的问题是:有没有办法让它们默默地忽略那些内容?

我当前的解决方法是像这样构造仅有效路径

   tmpl = 's3://<bucket>/year=2018/month=11/day=26/hour={hour}/department=x/'
   df = spark.read.parquet(*list(tmpl.format(hour=hour) for hour in range(1,24)))

非常麻烦,因为

  1. 某些路径可能不存在(有时会丢失数据等)。
  2. spark.read.parquet不会将列表或生成器作为输入,因此我被迫使用splat / unpack运算符将所有内容转换为单独的参数。不确定是否可以在数千条路径中使用。

有没有更好的方式来加载此数据而无需更改文件结构(我不控制)?

1 个答案:

答案 0 :(得分:1)

  

它显然失败了,因为我只能访问部门= x而不能访问   department = yyyy,我的问题是:有没有办法默默地   忽略那些?

根据文件状态对象,您对日志中提到的文件具有读写访问权限(permission=rw-rw-rw-)。文件路径可能是其他问题。

  

java.io.IOException:无法读取页脚:java.io.IOException:无法   无法读取文件的页脚   FileStatus {path = s3:///year=2018/month=11/day=26/hour=10/department=yyyyyy/part-xxxxx.gz.parquet; isDirectory = false;长度= 104448;复制= 0;块大小= 0;   modify_time = 0; access_time = 0;所有者=;组=;   权限= rw-rw-rw-; isSymlink = false}

由于上述错误,您正在以不正确的字符串格式传递fileStatus对象。

您必须通过fileStat.getPath.toString,也就是说,您必须通过path=s3:///year=2018/month=11/day=26/hour=10/department=yyyyyy/part-xxxxx.gz.parquet;

df = spark.read.parquet(...)将起作用。

如果要传递镶木地板文件夹,则可以传递。

或者您想在示例代码scala片段下方过滤某些文件,您可以使用

/**
    * getAllFilePath.
    *
    * @param filePath Path
    * @param fs       FileSystem
    * @return list of absolute file path present in given path
    * @throws FileNotFoundException
    * @throws IOException
    */
  @throws[FileNotFoundException]
  @throws[IOException]
  def getAllFilePath(filePath: Path, fs: FileSystem): ListBuffer[String] = {
    val fileList = new ListBuffer[String]
    val fileStatus = fs.listStatus(filePath)
    for (fileStat <- fileStatus) {
      logInfo(s"file path Name : ${fileStat.getPath.toString} length is  ${fileStat.getLen}")
      if (fileStat.isDirectory) fileList ++= (getAllFilePath(fileStat.getPath, fs))
      else if (fileStat.getLen > 0 && !fileStat.getPath.toString.isEmpty) {
        logInfo("fileStat.getPath.toString" + fileStat.getPath.toString)
        fileList.foreach(println)
        fileList += fileStat.getPath.toString
      } else if (fileStat.getLen == 0) {
        logInfo(" length zero files \n " + fileStat)

        // fs.rename(fileStat.getPath, new Path(fileStat.getPath+"1"))
      }
    }
    fileList
  }

像这个例子

    val fs = FileSystem.get(new URI(inputPath), spark.sparkContext.hadoopConfiguration)
 yourFiles = getAllFilePath(new Path(inputPath), fs)

val df = spark.read.parquet(yourFiles:_*)