私は、hdfsの場所からたくさんのテキストファイルを読み、それをsparkを使って繰り返しマッピングしたい。
JavaRDD<String> records = ctx.textFile(args[1], 1);
は一度に1つのファイルしか読み込むことができません。
複数のファイルを読み、それらを単一のRDDとして処理したい。どうやって?
ディレクトリ全体を指定したり、ワイルドカードを使用したり、ディレクトリやワイルドカードのCSVを使用することもできます。例えば。:
sc.textFile("/my/dir1,/my/paths/part-00[0-5]*,/another/dir,/a/specific/file")
Nick Chammasが指摘しているように、これはHadoopの FileInputFormat
の表現であり、したがってこれはHadoop(およびScalding)でも機能します。
以下のようにunion
を使用します。
val sc = new SparkContext(...)
val r1 = sc.textFile("xxx1")
val r2 = sc.textFile("xxx2")
...
val rdds = Seq(r1, r2, ...)
val bigRdd = sc.union(rdds)
それからbigRdd
はすべてのファイルのRDDです。
1つのテキストファイル呼び出しを使って複数のファイルを読み取ることができます。 Scala:
sc.textFile(','.join(files))
これが使えます
まず、S3パスのバッファ/リストを取得できます。
import scala.collection.JavaConverters._
import Java.util.ArrayList
import com.amazonaws.services.s3.AmazonS3Client
import com.amazonaws.services.s3.model.ObjectListing
import com.amazonaws.services.s3.model.S3ObjectSummary
import com.amazonaws.services.s3.model.ListObjectsRequest
def listFiles(s3_bucket:String, base_prefix : String) = {
var files = new ArrayList[String]
//S3 Client and List Object Request
var s3Client = new AmazonS3Client();
var objectListing: ObjectListing = null;
var listObjectsRequest = new ListObjectsRequest();
//Your S3 Bucket
listObjectsRequest.setBucketName(s3_bucket)
//Your Folder path or Prefix
listObjectsRequest.setPrefix(base_prefix)
//Adding s3:// to the paths and adding to a list
do {
objectListing = s3Client.listObjects(listObjectsRequest);
for (objectSummary <- objectListing.getObjectSummaries().asScala) {
files.add("s3://" + s3_bucket + "/" + objectSummary.getKey());
}
listObjectsRequest.setMarker(objectListing.getNextMarker());
} while (objectListing.isTruncated());
//Removing Base Directory Name
files.remove(0)
//Creating a Scala List for same
files.asScala
}
このListオブジェクトを次のコードに渡します。注意:scはSQLContextのオブジェクトです。
var df: DataFrame = null;
for (file <- files) {
val fileDf= sc.textFile(file)
if (df!= null) {
df= df.unionAll(fileDf)
} else {
df= fileDf
}
}
これで、最終的なUnified RDD、つまりdfを取得しました。
オプションです。そして、単一のBigRDDに再分割することもできます。
val files = sc.textFile(filename, 1).repartition(1)
再区画化は常に機能します。D
PySparkでは、ファイルを解析するための追加の便利な方法を見つけました。おそらくScalaにも同等のものがありますが、私は実用的な翻訳を思いつくのに十分に満足していません。それは、事実上、ラベルを追加したtextFile呼び出しです(以下の例では、key = filename、value = fileから1行)。
"ラベル付き" textFile
入力:
import glob
from pyspark import SparkContext
SparkContext.stop(sc)
sc = SparkContext("local","example") # if running locally
sqlContext = SQLContext(sc)
for filename in glob.glob(Data_File + "/*"):
Spark_Full += sc.textFile(filename).keyBy(lambda x: filename)
output:filename-as-keyを使用し、value =ファイルの各行を使用してTupleを含む各エントリを持つ配列。 (技術的には、この方法を使用すると、実際のファイルパス名以外に別のキーを使用することもできます。おそらく、メモリを節約するためのハッシュ表現です)。すなわち。
[('/home/folder_with_text_files/file1.txt', 'file1_contents_line1'),
('/home/folder_with_text_files/file1.txt', 'file1_contents_line2'),
('/home/folder_with_text_files/file1.txt', 'file1_contents_line3'),
('/home/folder_with_text_files/file2.txt', 'file2_contents_line1'),
...]
どちらかを行のリストとして再結合することもできます。
Spark_Full.groupByKey().map(lambda x: (x[0], list(x[1]))).collect()
[('/home/folder_with_text_files/file1.txt', ['file1_contents_line1', 'file1_contents_line2','file1_contents_line3']),
('/home/folder_with_text_files/file2.txt', ['file2_contents_line1'])]
または、ファイル全体を単一の文字列に再結合します(この例では、結果はwholeTextFilesから取得したものと同じですが、文字列 "file:"はファイルパスから削除されています)。
Spark_Full.groupByKey().map(lambda x: (x[0], ' '.join(list(x[1])))).collect()
あなたが使用することができます
JavaRDD<String , String> records = sc.wholeTextFiles("path of your directory")
ここであなたはあなたのファイルのパスとそのファイルの内容を得るでしょう。そのため、オーバーヘッドを削減するために、一度にファイル全体の任意のアクションを実行できます。
すべての答えはsc.textFile
で正しいです
どうしてそうではないのでしょうか wholeTextFiles
.
val minPartitions = 2
val path = "/pathtohdfs"
sc.wholeTextFiles(path,minPartitions)
.flatMap{case (path, text)
...
1つの制限は、小さなファイルをロードしなければならないということです。
注:
訪問 へのさらなる参照
利用可能な率直なきれいな解決策があります。 wholeTextFiles()メソッドを使用してください。これはディレクトリを取り、キーと値のペアを形成します。返されたRDDはペアRDDになります。 Spark docs からの説明の下にあります。
SparkContext.wholeTextFilesを使用すると、複数の小さなテキストファイルを含むディレクトリを読み取ることができ、それぞれを(ファイル名、コンテンツ)のペアとして返します。これは、各ファイルの1行に1レコードを返すtextFileとは対照的です。
TRY THIS DataFrameを外部ストレージシステム(ファイルシステム、Key-Valueストアなど)に書き込むために使用されるインタフェース。これにアクセスするにはDataFrame.write()を使用してください。
バージョン1.4の新機能.
csv(パス、モード=なし、圧縮=なし、sep =なし、引用=なし、エスケープ=なし、ヘッダー=なし、nullValue =なし、escapeQuotes =なし、quoteAll =なし、dateFormat =なし、timestampFormat =なし)指定されたパスにあるCSV形式のDataFrameの内容。
パラメータ:path - Hadoopがサポートするファイルシステムモードのパス - データがすでに存在する場合の保存操作の動作を指定します。
append:このDataFrameの内容を既存のデータに追加します。上書き:既存のデータを上書きします。 ignore:データがすでに存在する場合は、この操作をサイレントに無視します。 error(デフォルトケース):データが既に存在する場合は例外を投げます。 compression - ファイルに保存するときに使う圧縮コーデック。これは、大文字と小文字を区別しない既知の短縮名(none、bzip2、gzip、lz4、snappy、およびdeflate)のいずれかになります。 sep - 各フィールドと値の区切り文字として単一の文字を設定します。 Noneが設定されている場合は、デフォルト値の、、が使用されます。 quote - 区切り文字を値の一部にすることができる場合、引用符付き値をエスケープするために使用される単一文字を設定します。 Noneが設定されている場合は、デフォルト値 ""が使用されます。引用符をオフにしたい場合は、空の文字列を設定する必要があります。escape - すでに引用符で囲まれた値内の引用符のエスケープに使用される単一文字を設定します。\escapeQuotes - 引用符を含む値を常に引用符で囲むかどうかを示すフラグNoneが設定されている場合は、デフォルト値のtrueを使用し、引用符文字を含むすべての値をエスケープするかどうかを示すフラグNoneを設定すると、デフォルト値falseが使用され、引用符を含む値のみがエスケープされますheader - 最初の行としてカラムの名前を書き込みますNoneが設定されると、デフォルトを使用します。 value、false nullValue - null値の文字列表現を設定しますNoneが設定されている場合、デフォルト値である空文字列を使用しますdateFormat - 日付フォーマットを示す文字列を設定しますカスタム日付フォーマットはJava.textのフォーマットに従います.SimpleDateフォーマットこれは日付タイプに適用されます。 Noneが設定されている場合は、デフォルト値のyyyy-MM-ddが使用されます。 timestampFormat - タイムスタンプフォーマットを示す文字列を設定します。カスタム日付フォーマットは、Java.text.SimpleDateFormatのフォーマットに従います。これはタイムスタンプ型に適用されます。 Noneが設定されている場合は、デフォルト値のyyyy-MM-dd'T'HH:mm:ss.SSSZZが使用されます。