加载Parquet文件时无法推断架构

时间:2017-07-06 16:54:38

标签: apache-spark pyspark parquet

response = "mi_or_chd_5"

outcome = sqlc.sql("""select eid,{response} as response
from outcomes
where {response} IS NOT NULL""".format(response=response))
outcome.write.parquet(response, mode="overwrite") # Success
print outcome.schema
StructType(List(StructField(eid,IntegerType,true),StructField(response,ShortType,true)))

但是:

outcome2 = sqlc.read.parquet(response)  # fail

失败了:

AnalysisException: u'Unable to infer schema for Parquet. It must be specified manually.;'

in

/usr/local/lib/python2.7/dist-packages/pyspark-2.1.0+hadoop2.7-py2.7.egg/pyspark/sql/utils.pyc in deco(*a, **kw)

镶木地板的文档说格式是自描述的,并且在保存镶木地板文件时可以使用完整的模式。是什么给了什么?

使用Spark 2.1.1。在2.2.0中也失败了。

找到this bug report,但已修复 2.0.1,2.1.0。

更新:当与master =" local"连接时,此工作在连接到master =" mysparkcluster"时失败。

14 个答案:

答案 0 :(得分:28)

当您尝试将空目录读取为镶木地板时,通常会发生此错误。 您的结果 Dataframe 可能为空。

在编写之前,您可以使用outcome.rdd.isEmpty()检查DataFrame是否为空。

答案 1 :(得分:3)

当您尝试读取空表时,会出现这种情况。如果表格已正确插入数据,则应该没有问题。

除了镶木地板之外,ORC也会发生同样的事情。

答案 2 :(得分:2)

在我的情况下,错误发生是因为我试图读取以下划线开头的镶木地板文件(例如_lots_of_data.parquet)。不知道为什么这是一个问题,但删除前导下划线解决了这个问题。

另见:

答案 3 :(得分:2)

我正在使用AWS Glue,从数据目录表(位置:s3存储桶)读取数据时收到此错误。 经过一点分析,我意识到这是由于文件在文件位置(在我的情况下为s3存储桶路径)中不可用。

Glue试图在不存在的文件上应用数据目录表架构。

将文件复制到s3存储桶文件位置后,问题已解决。

希望这可以帮助遇到或遇到AWS Glue错误的人。

答案 4 :(得分:2)

对我来说,这是在我认为加载正确的文件路径但指向错误的文件夹时发生的

答案 5 :(得分:1)

我在读取csv时遇到了类似的问题

spark.read.csv("s3a://bucket/spark/csv_dir/.")

出现以下错误:

org.apache.spark.sql.AnalysisException: Unable to infer schema for CSV. It must be specified manually.;

我发现是否删除了结尾的.,然后它可以工作。即:

spark.read.csv("s3a://bucket/spark/csv_dir/")

我对此进行了测试,为parquet添加了结尾的.,但出现了以下错误:

org.apache.spark.sql.AnalysisException: Unable to infer schema for Parquet. It must be specified manually.;

答案 6 :(得分:1)

就我而言,发生错误是因为文件名包含下划线。重写/读取文件时不带下划线(连字符可以)解决了该问题...

答案 7 :(得分:1)

仅在注释中强调@Davos答案,如果文件名的文件名开头有点.或下划线_,就会遇到此确切的异常错误

val df = spark.read.format("csv").option("delimiter", "|").option("header", "false")
         .load("/Users/myuser/_HEADER_0")

org.apache.spark.sql.AnalysisException: 
Unable to infer schema for CSV. It must be specified manually.;

解决方案是重命名文件,然后重试(例如_HEADER重命名为HEADER

答案 8 :(得分:0)

我看到已经有很多答案了。但是我遇到的问题是我的Spark作业正在尝试读取一个文件,该文件被先前启动的另一个Spark作业覆盖。听起来很糟糕,但我犯了这个错误。

答案 9 :(得分:0)

正如其他人所提到的,在我的情况下,当我读取不存在的S3密钥时出现此错误。 一种解决方案是存在确实存在的过滤键:

--wrap

,您可以将其用作:

import com.amazonaws.services.s3.AmazonS3URI
import org.apache.hadoop.fs.{FileSystem, Path}
import org.apache.spark.sql.SparkSession
import java.net.URI

def addEndpointToUrl(url: String, domain: String = "s3.amazonaws.com"): String = {
  val uri = new URI(url)
  val hostWithEndpoint = uri.getHost + "." + domain
  new URI(uri.getScheme, uri.getUserInfo, hostWithEndpoint, uri.getPort, uri.getPath, uri.getQuery, uri.getFragment).toString
}

def createS3URI(url: String): AmazonS3URI = {
  try {
    // try to instantiate AmazonS3URI with url
    new AmazonS3URI(url)
  } catch {
    case e: IllegalArgumentException if e.getMessage.
      startsWith("Invalid S3 URI: hostname does not appear to be a valid S3 endpoint") => {
      new AmazonS3URI(addEndpointToUrl(url))
    }
  }
}

def s3FileExists(spark: SparkSession, url: String): Boolean = {
  val amazonS3Uri: AmazonS3URI = createS3URI(url)
  val s3BucketUri = new URI(s"${amazonS3Uri.getURI().getScheme}://${amazonS3Uri.getBucket}")

  FileSystem
    .get(s3BucketUri, spark.sparkContext.hadoopConfiguration)
    .exists(new Path(url))
}

对于该解决方案,我从val partitions = List(yesterday, today, tomorrow) .map(f => somepath + "/date=" + f) .filter(f => s3FileExists(spark, f)) val df = spark.read.parquet(partitions: _*) 项目here中提取了一些代码。

答案 10 :(得分:0)

您正在加载实木复合地板文件,当然实木复合地板有效 模式。否则,它将不会另存为实木复合地板。此错误意味着 -

  • 任何一个拼花文件都不存在。 (99.99%的情况是问题所在。Spark错误消息通常不太明显)
  • 镶木地板文件以某种方式损坏,或者根本不是镶木地板文件

答案 11 :(得分:0)

由于文件夹中的文件夹问题,我遇到了这个问题。

例如folderA.parquet应该具有分区....但是它具有folderB.parquet,内部具有分区。

决议, 将文件传输到父文件夹并删除子文件夹。

答案 12 :(得分:0)

我刚刚遇到了相同的问题,但是这里没有解决方案对我有用。我尝试先读取HDFS上的镶木地板文件的行组,然后将其写到另一个位置:

df = spark.read.parquet('somewhere')
df.write.parquet('somewhere else')

但是稍后我用

查询时
spark.sql('SELECT sth FROM parquet.`hdfs://host:port/parquetfolder/` WHERE .. ')

它显示了相同的问题。 我终于通过使用pyarrow解决了这个问题:

df = spark.read.parquet('somewhere')
pdf = df.toPandas()
adf = pa.Table.from_pandas(pdf)   # import pyarrow as pa
fs = pa.hdfs.connect()
fw = fs.open(path, 'wb')
pq.write_table(adf, fw)           # import pyarrow.parquet as pq
fw.close()

答案 13 :(得分:0)

你可以用/*

阅读
outcome2 = sqlc.read.parquet(f"{response}/*")  # work for me
相关问题