繁体   English   中英

如何使用 Spark Session 列出 S3 存储桶中的文件?

[英]How to list files in S3 bucket using Spark Session?

是否可以使用 SparkSession object 列出给定 S3 路径(例如:s3://my-bucket/my-folder/*.extension)中的所有文件?

您可以使用 Hadoop API 访问 S3 上的文件(Spark 也使用它):

import java.net.URI
import org.apache.hadoop.fs.FileSystem
import org.apache.hadoop.fs.Path
import org.apache.hadoop.conf.Configuration

val path = "s3://somebucket/somefolder"
val fileSystem = FileSystem.get(URI.create(path), new Configuration())
val it = fileSystem.listFiles(new Path(path), true)
while (it.hasNext()) {
  ...
}

Lou Zell非常接近,下面最终在 ADLS2 上工作。 但我把它放在这里是因为 Py4J 的魔力:请注意,noopcache 会导致作业运行两次。 一次创建索引和一次调用 listfiles 时:可能会写一篇关于此的博文:

import os

base_path = "/mnt/my_data/"
glob_pattern = "*"
sc = spark.sparkContext
hadoop_base_path = sc._jvm.org.apache.hadoop.fs.Path(base_path)
paths = sc._jvm.PythonUtils.toSeq([hadoop_base_path])

noop_cache_clazz = sc._jvm.java.lang.Class.forName("org.apache.spark.sql.execution.datasources.NoopCache$")
ff = noop_cache_clazz.getDeclaredField("MODULE$")
noop_cache = ff.get(None)

in_memory_file_index = sc._jvm.org.apache.spark.sql.execution.datasources.InMemoryFileIndex(
    spark._jsparkSession,
    paths,
    sc._jvm.PythonUtils.toScalaMap({}),
    sc._jvm.scala.Option.empty(),
    noop_cache,
    sc._jvm.scala.Option.empty(),
    sc._jvm.scala.Option.empty()
)
glob_path = sc._jvm.org.apache.hadoop.fs.Path(os.path.join(base_path, glob_pattern))
glob_paths = sc._jvm.PythonUtils.toSeq([glob_path])
# SparkHadoopUtil.get.globPath(fs, Path.mergePaths(validated(basep), validated(globp))),
status_list = in_memory_file_index.listLeafFiles(glob_paths)
path_list = []
iter = status_list.iterator()
while iter.hasNext():
    path_status = iter.next()
    path_list.append(str(path_status.getPath().toUri().getRawPath()))

path_list.sort()

print(path_list)

您可以将input_file_name与数据帧一起使用,它会为您提供每行的绝对文件路径。

以下代码将为您提供所有文件路径。

spark.read.table("zen.intent_master").select(input_file_name).distinct.collect

我假设。 对于您的用例,您只想从一组文件中读取数据,使用一些正则表达式,然后您可以将其应用到过滤器中。

例如,

val df = spark.read.table("zen.intent_master").filter(input_file_name.rlike("your regex string"))

方法一

对于 pyspark 用户,我已经翻译了 Michael Spector 的回答(我会留给你来决定使用它是否是一个好主意):

sc = spark.sparkContext
myPath = f's3://my-bucket/my-prefix/'
javaPath = sc._jvm.java.net.URI.create(myPath)
hadoopPath = sc._jvm.org.apache.hadoop.fs.Path(myPath)
hadoopFileSystem = sc._jvm.org.apache.hadoop.fs.FileSystem.get(javaPath, sc._jvm.org.apache.hadoop.conf.Configuration())
iterator = hadoopFileSystem.listFiles(hadoopPath, True)

s3_keys = []
while iterator.hasNext():
    s3_keys.append(iterator.next().getPath().toUri().getRawPath())    

s3_keys现在保存在my-bucket/my-prefix找到的所有文件密钥

方法 2这是我发现的替代方法(@forgetso 的帽子提示):

myPath = 's3://my-bucket/my-prefix/*'
hadoopPath = sc._jvm.org.apache.hadoop.fs.Path(myPath)
hadoopFs = hadoopPath.getFileSystem(sc._jvm.org.apache.hadoop.conf.Configuration())
statuses = hadoopFs.globStatus(hadoopPath)

for status in statuses:
  status.getPath().toUri().getRawPath()
  # Alternatively, you can get file names only with:
  # status.getPath().getName()

方法 3(不完整!)

上述两种方法不使用将应用于分布式读取的 Spark 并行机制。 不过,这种逻辑看起来很私密。 在此处查看parallelListLeafFiles 我还没有找到一种方法来强制 pyspark 对 s3 上的分布式ls执行操作,而无需读取文件内容。 我尝试使用 py4j 来实例化InMemoryFileIndex ,但无法正确使用咒语。 如果有人想从这里拿起它,这是我到目前为止所拥有的:

myPath = f's3://my-bucket/my-path/'
paths = sc._gateway.new_array(sc._jvm.org.apache.hadoop.fs.Path, 1)
paths[0] = sc._jvm.org.apache.hadoop.fs.Path(myPath)

emptyHashMap = sc._jvm.java.util.HashMap()
emptyScalaMap = sc._jvm.scala.collection.JavaConversions.mapAsScalaMap(emptyMap)

# Py4J is not happy with this:
sc._jvm.org.apache.spark.sql.execution.datasources.InMemoryFileIndex(
    spark._jsparkSession, 
    paths, 
    emptyScalaMap, 
    sc._jvm.scala.Option.empty() # Optional None
)

暂无
暂无

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

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