【问题标题】:java.io.IOException: No FileSystem for scheme: s3java.io.IOException:方案没有文件系统:s3
【发布时间】:2021-12-12 11:39:35
【问题描述】:

我正在尝试从 pyspark 代码中的 s3 存储桶中读取数据,并且我正在使用 jupyter notebook。我在我的机器上设置了 Spark,并通过导入 findspark

在 jupyter 中使用它
import findspark
findspark.init()

from pyspark.sql import *

spark = SparkSession.builder.appName("my_app").getOrCreate()

但是当我尝试从存储桶中读取数据时,我收到错误 java.io.IOException: No FileSystem for scheme: s3

input_bucket = "s3://bucket_name"
data = spark.read.csv(input_bucket + '/file_name', header=True, inferSchema=True)

我在互联网上找到了一些解决方案,说要添加这 2 个包(hadoop-awsaws-java-sdk)。我在 Spark 的 jars 文件夹中下载并添加了这些 jar 文件,但仍然出现相同的错误。

不知道是版本兼容性问题还是有其他问题。如果是兼容性问题,如何根据我们的pyspark、python和java版本来决定使用哪个版本的jar文件呢?

版本

pyspark 2.4.8
python 3.7.9
java version "1.8.0_301"
Java(TM) SE Runtime Environment (build 1.8.0_301-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.301-b09, mixed mode)
javac 1.8.0_301

Jar 文件

hadoop-aws-2.7.3.jar
aws-java-sdk-1.8.2.jar

PS:我正在开发 WINdows。

【问题讨论】:

    标签: amazon-web-services apache-spark amazon-s3 pyspark


    【解决方案1】:

    为了在 spark 中实现 java 和 python 之间的这种融合,还有很多工作要做。

    主要是不同 jar 之间的版本兼容性问题。确保不同组件的一致性可以成为您解决此类问题的起点

    Hadoop 版本

    导航到安装spark 的位置,确保*hadoop* 的版本一致是迈向spark 的第一步

    [? vaebhav@localhost:/usr/local/Cellar/apache-spark/3.1.2/libexec/jars - 10:39 PM ?]$ ls -lthr *hadoop-*
    -rw-r--r--  1 vaebhav  root    79K May 24 10:15 hadoop-yarn-server-web-proxy-3.2.0.jar
    -rw-r--r--  1 vaebhav  root   1.3M May 24 10:15 hadoop-yarn-server-common-3.2.0.jar
    -rw-r--r--  1 vaebhav  root   221K May 24 10:15 hadoop-yarn-registry-3.2.0.jar
    -rw-r--r--  1 vaebhav  root   2.8M May 24 10:15 hadoop-yarn-common-3.2.0.jar
    -rw-r--r--  1 vaebhav  root   310K May 24 10:15 hadoop-yarn-client-3.2.0.jar
    -rw-r--r--  1 vaebhav  root   3.1M May 24 10:15 hadoop-yarn-api-3.2.0.jar
    -rw-r--r--  1 vaebhav  root    84K May 24 10:15 hadoop-mapreduce-client-jobclient-3.2.0.jar
    -rw-r--r--  1 vaebhav  root   1.6M May 24 10:15 hadoop-mapreduce-client-core-3.2.0.jar
    -rw-r--r--  1 vaebhav  root   787K May 24 10:15 hadoop-mapreduce-client-common-3.2.0.jar
    -rw-r--r--  1 vaebhav  root   4.8M May 24 10:15 hadoop-hdfs-client-3.2.0.jar
    -rw-r--r--  1 vaebhav  root   3.9M May 24 10:15 hadoop-common-3.2.0.jar
    -rw-r--r--  1 vaebhav  root    43K May 24 10:15 hadoop-client-3.2.0.jar
    -rw-r--r--  1 vaebhav  root   136K May 24 10:15 hadoop-auth-3.2.0.jar
    -rw-r--r--  1 vaebhav  root    59K May 24 10:15 hadoop-annotations-3.2.0.jar
    -rw-r--r--@ 1 vaebhav  root   469K Oct  9 00:30 hadoop-aws-3.2.0.jar
    [? vaebhav@localhost:/usr/local/Cellar/apache-spark/3.1.2/libexec/jars - 10:39 PM ?]$ 
    
    

    对于像 S3 这样的进一步的 3rd 方连接,您可以通过搜索相应的 jar 来检查来自 MVN Repository 的相应编译依赖项,在您的情况下 - hadoop-aws-2.7.3.jar

    MVN 编译依赖

    通过在 mvn 存储库下搜索相应的工件,应该检查相应的 aws jdk jar 在编译依赖项下

    这些检查点可以作为您确保正确依赖关系的入口点

    依赖关系排序后,S3连接还有额外的步骤

    PySpark S3 示例

    AWS SDK 目前支持 s3a 或 s3n ,我已经演示了如何建立s3a,后一个也很容易实现

    实现之间的差异可以在这个精彩的answer中找到

    from pyspark import SparkContext
    from pyspark.sql import SQLContext
    import configparser
    
    sc = SparkContext.getOrCreate()
    sql = SQLContext(sc)
    
    hadoop_conf = sc._jsc.hadoopConfiguration()
    
    config = configparser.ConfigParser()
    
    config.read(os.path.expanduser("~/.aws/credentials"))
    
    access_key = config.get("<aws-account>", "aws_access_key_id")
    secret_key = config.get("<aws-account>", "aws_secret_access_key")
    session_key = config.get("<aws-account>", "aws_session_token")
    
    sc._jsc.hadoopConfiguration().set("fs.s3a.endpoint", "s3.amazonaws.com")
    sc._jsc.hadoopConfiguration().set("fs.s3a.connection.ssl.enabled", "true")
    sc._jsc.hadoopConfiguration().set("fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem");
    
    hadoop_conf.set("fs.s3a.aws.credentials.provider", "org.apache.hadoop.fs.s3a.TemporaryAWSCredentialsProvider")
    hadoop_conf.set("fs.s3a.access.key", access_key)
    hadoop_conf.set("fs.s3a.secret.key", secret_key)
    hadoop_conf.set("fs.s3a.session.token", session_key)
    
    s3_path = "s3a://<s3-path>/"
    
    sparkDF = sql.read.parquet(s3_path)
    

    【讨论】:

    • 这是一个很好的答案。但是请切掉设置 fs.s3a.impl 的 conf 位...这只是一些民间传说复制并粘贴在堆栈溢出答案中
    • 有没有更好的建立连接的方法,按照上面提到的过程-github.com/databricks/…
    • 数据库文档是针对他们的产品的。 s3a 连接器附带端点、连接和 fs.s3a impl set out the box(在 hadoop-common 的 core-default.xml 中;临时凭据提供程序在凭据提供程序列表中排在首位(后跟:完整的凭据、环境变量、EC2 IAM 机密)。去掉所有的 _sc._jsc 设置,一切都会正常
    • @Vaebhav 我也面临同样的问题 - java.io.IOException: No FileSystem for scheme: s3 我正在尝试从 java spark 连接 hive。这种相同的方法是否适用于 hive 连接? .enableHiveSupport()
    • 是的,同样的方法也适用于 hive
    猜你喜欢
    • 2016-03-06
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    • 2018-08-20
    • 2018-03-26
    • 1970-01-01
    • 2020-05-13
    • 2021-05-25
    相关资源
    最近更新 更多