एक एकल RDD में कई पाठ फ़ाइलों को कैसे पढ़ें?


179

मैं एक hdfs स्थान से पाठ फ़ाइलों का एक गुच्छा पढ़ना चाहता हूं और चिंगारी का उपयोग करके एक पुनरावृत्ति में उस पर मानचित्रण करना चाहता हूं।

JavaRDD<String> records = ctx.textFile(args[1], 1); एक समय में केवल एक फ़ाइल पढ़ने में सक्षम है।

मैं एक से अधिक फ़ाइल पढ़ना और उन्हें एक ही RDD के रूप में संसाधित करना चाहता हूं। कैसे?

जवाबों:


299

आप पूरी निर्देशिका निर्दिष्ट कर सकते हैं, वाइल्डकार्ड और यहां तक ​​कि निर्देशिका और वाइल्डकार्ड के सीएसवी का उपयोग कर सकते हैं। उदाहरण के लिए:

sc.textFile("/my/dir1,/my/paths/part-00[0-5]*,/another/dir,/a/specific/file")

जैसा कि निक चामास बताते हैं कि यह हडोप का एक्सपोज़र है FileInputFormatऔर इसलिए यह हडोप (और स्केलिंग) के साथ भी काम करता है।


10
हां, यह एकल RDD के रूप में कई फ़ाइलों को खोलने का सबसे सुविधाजनक तरीका है। यहाँ एपीआई केवल Hadoop के FileInputFormat एपीआई का एक प्रदर्शन है , इसलिए सभी समान Pathविकल्प लागू होते हैं।
निक चामास

7
sc.wholeTextFilesडेटा के लिए आसान है जो लाइन-सीमांकित नहीं है
मिशाल azizmazia

1
हालांकि यह अजीब है कि यदि आप ऐसा करते हैं और समानता को निर्दिष्ट करते हैं, तो कहें कि sc.textFile(multipleCommaSeparatedDirs,320)यह 19430कुल कार्यों की ओर जाता है 320... यह ऐसा व्यवहार करता है unionजिससे बहुत कम समानता से कार्यों की संख्या
घट जाती है

2
मैंने अंत में पाया कि यह बुराई फ़ाइल पैटर्न मिलान कैसे काम करता है stackoverflow.com/a/33917492/306488 इसलिए मुझे अब सीमांकित करने की आवश्यकता नहीं है
lisak

@femibyte मुझे ऐसा नहीं लगता, हालाँकि मुझे नहीं पता कि आप फ़ाइल का नाम किसी अन्य स्थिति में क्यों जानना चाहते हैं wholeTextFiles। आपका उपयोग मामला क्या है? मैं एक समाधान के बारे में सोच सकता हूं बशर्ते आप फाइलों के समान विभाजन का उपयोग करें ...
samthebest

35

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सभी फाइलों के साथ आरडीडी है।


धन्यवाद बादल, इस तरह से मैं अपनी इच्छित सभी फ़ाइलों को पढ़ सकता हूं, लेकिन एक! लेकिन फिर भी, मुझे बहुत सारी चीजें
लिखनी

30

आप कई फ़ाइलों को पढ़ने के लिए एक एकल टेक्स्टफाइल कॉल का उपयोग कर सकते हैं। स्काला:

sc.textFile(','.join(files)) 

5
और समान पायथन सिंटेक्स
patricksurry

8
मुझे लगता है कि केवल अजगर वाक्यविन्यास है। स्काला समतुल्य होगाsc.textFile(files.mkString(","))
दावोस

9

आप इसका उपयोग कर सकते हैं

पहले आप 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
  }

अब इस सूची ऑब्जेक्ट को कोड के निम्नलिखित टुकड़े पर पास करें, ध्यान दें: sc SQLContext का एक ऑब्जेक्ट है

var df: DataFrame = null;
  for (file <- files) {
    val fileDf= sc.textFile(file)
    if (df!= null) {
      df= df.unionAll(fileDf)
    } else {
      df= fileDf
    }
  }

अब आपको एक अंतिम यूनिफ़ाइड RDD यानी df मिला

वैकल्पिक, और आप इसे एकल BigRDD में भी पुन: प्रस्तुत कर सकते हैं

val files = sc.textFile(filename, 1).repartition(1)

पुनर्मूल्यांकन हमेशा काम करता है: डी


क्या इसका मतलब यह नहीं है कि फ़ाइल सूची अपेक्षाकृत छोटी होनी चाहिए? लाखों फाइलें नहीं।
मैथ्यू लॉन्गटिन

2
क्या हम सूचीबद्ध फ़ाइलों को पढ़ने के संचालन को समानांतर कर सकते हैं? sc.parallelize जैसी कोई चीज़?
lazzwiz

1
@MathieuLongtin: यदि आप अपने स्पार्क कोड में विभाजन की खोज को लागू कर सकते हैं तो यह बहुत अच्छा होगा, आपको इसे पसंद करने की आवश्यकता है। मैं एक मिनट में लगभग 10k फाइलें खोलता था।
मुर्तजा कांचवाला

@lazywiz यदि आप एक भी आरडीडी नहीं बनाना चाहते हैं, तो सिर्फ रिप्रजेंटेशन एक्शन हटा दें।
मुर्तजा कांचवाला

3

PySpark में, मुझे फ़ाइलों को पार्स करने का एक अतिरिक्त उपयोगी तरीका मिला है। शायद स्काला में एक समकक्ष है, लेकिन मैं एक कामकाजी अनुवाद के साथ आने में सहज नहीं हूं। यह वास्तव में, लेबल के अतिरिक्त के साथ एक टेक्स्टफाइल कॉल है (नीचे उदाहरण में कुंजी = फ़ाइल नाम, मान = फ़ाइल से 1 पंक्ति)।

"लेबल" टेक्स्ट फ़ाइल

इनपुट:

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)

आउटपुट: फ़ाइल नाम-की-कुंजी का उपयोग करके और फ़ाइल की प्रत्येक पंक्ति = का उपयोग करके प्रत्येक प्रविष्टि के साथ सरणी। (तकनीकी रूप से, इस पद्धति का उपयोग करके आप वास्तविक फ़ाइलपथ नाम के अलावा एक अलग कुंजी का उपयोग भी कर सकते हैं- शायद मेमोरी पर सहेजने के लिए हैशिंग प्रतिनिधित्व)। अर्थात।

[('/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'])]

या एकल स्ट्रिंग्स पर वापस संपूर्ण फ़ाइलों को पुन: संयोजित करें (इस उदाहरण में परिणाम वही है जो आपको संपूर्ण टेक्स्ट से मिलता है, लेकिन स्ट्रिंग "फ़ाइल:" फ़ाइलपथ से छीन लिया गया है।)।

Spark_Full.groupByKey().map(lambda x: (x[0], ' '.join(list(x[1])))).collect()


जब मैंने इस कोड ऑफ़ लाइन को चलाया - Spark_Full += sc.textFile(filename).keyBy(lambda x: filename) मुझे त्रुटि मिली अर्थात TypeError: 'PipelinedRDD' object is not iterable। मेरी समझ यह है कि, यह पंक्ति एक RDD बनाता है जो अपरिवर्तनीय है, इसलिए मैं सोच रहा था कि आप इसे दूसरे चर में कैसे जोड़ पाएंगे?
कार्तिककानपुर

3

आप उपयोग कर सकते हैं

JavaRDD<String , String> records = sc.wholeTextFiles("path of your directory")

यहां आपको अपनी फ़ाइल का पथ और उस फ़ाइल की सामग्री मिल जाएगी। इसलिए आप ओवरहेड को सहेजने के समय एक पूरी फ़ाइल की कोई भी क्रिया कर सकते हैं


2

सभी उत्तर सही हैं sc.textFile

मैं सोच रहा था कि क्यों नहीं wholeTextFilesउदाहरण के लिए, इस मामले में ...

val minPartitions = 2
val path = "/pathtohdfs"
    sc.wholeTextFiles(path,minPartitions)
      .flatMap{case (path, text) 
    ...

एक सीमा यह है कि, हमें छोटी फ़ाइलों को लोड करना होगा अन्यथा प्रदर्शन खराब होगा और इससे ओओएम हो सकता है।

ध्यान दें :

  • पूरेfile को स्मृति में फिट होना चाहिए
  • फ़ाइल स्वरूपों के लिए अच्छा है जो लाइन द्वारा विभाजन योग्य नहीं हैं ... जैसे XML फाइलें

यात्रा के लिए आगे संदर्भ


या बसsc.wholeTextFiles(folder).flatMap...
Evhz

sc.wholeTextFiles ( "/ path / to / dir")
राम Ghadiyaram

1

एक सीधे आगे स्वच्छ समाधान उपलब्ध है। पूरेTextFiles () विधि का उपयोग करें। यह एक निर्देशिका लेगा और एक प्रमुख मूल्य युग्म बनाता है। लौटा RDD एक जोड़ा RDD होगा। स्पार्क डॉक्स से विवरण नीचे देखें :

SparkContext.wholeTextFiles आपको कई छोटे पाठ फ़ाइलों वाली एक निर्देशिका पढ़ने देता है, और उनमें से प्रत्येक (फ़ाइल नाम, सामग्री) जोड़े के रूप में देता है। यह textFile के विपरीत है, जो प्रत्येक फ़ाइल में प्रति पंक्ति एक रिकॉर्ड लौटाएगा


-1

TRY THIS इंटरफ़ेस का उपयोग बाह्य भंडारण प्रणालियों (जैसे फ़ाइल सिस्टम, की-वैल्यू स्टोर आदि) के लिए डेटाफ़्रेम लिखने के लिए किया जाता है। इसका उपयोग करने के लिए DataFrame.write () का उपयोग करें।

संस्करण 1.4 में नया।

सीएसवी (पथ, मोड = कोई नहीं, सम्पीडन = कोई नहीं, एसपीपी = कोई नहीं, उद्धरण = कोई नहीं, बचना = कोई नहीं, शीर्ष लेख = कोई नहीं, nullValue = कोई नहीं, एस्केपक्वाट्स = कोई नहीं, उद्धरणप्रमाण = कोई नहीं, दिनांकफ़ॉर्मैट = कोई नहीं, टाइमस्टैम्पफ़ॉर्मैट = कोई नहीं) बचाता है निर्दिष्ट पथ पर CSV प्रारूप में DataFrame की सामग्री।

पैरामीटर: पथ - किसी भी Hadoop समर्थित फ़ाइल सिस्टम मोड में पथ - डेटा के पहले से मौजूद होने पर सेव ऑपरेशन के व्यवहार को निर्दिष्ट करता है।

append: इस DataFrame की सामग्री को मौजूदा डेटा में जोड़ें। ओवरराइट: मौजूदा डेटा को अधिलेखित करें। नजरअंदाज करें: यदि डेटा पहले से मौजूद है तो चुपचाप इस ऑपरेशन को नजरअंदाज कर दें। त्रुटि (डिफ़ॉल्ट मामला): यदि डेटा पहले से मौजूद है तो एक अपवाद को फेंक दें। सम्पीडन - संपीड़न कोडेक जब फ़ाइल को सहेजने के लिए उपयोग करना है। यह ज्ञात केस-असंवेदनशील नामों में से एक हो सकता है (कोई नहीं, bzip2, gzip, lz4, snappy and deflate)। sep - एकल वर्ण को प्रत्येक क्षेत्र और मान के लिए विभाजक के रूप में सेट करता है। यदि कोई भी सेट नहीं है, तो यह डिफ़ॉल्ट मान का उपयोग करता है,,। उद्धरण - उद्धृत मूल्यों से बचने के लिए उपयोग किए जाने वाले एकल चरित्र को सेट करता है जहां विभाजक मूल्य का हिस्सा हो सकता है। यदि कोई भी सेट नहीं है, तो यह डिफ़ॉल्ट मान का उपयोग करता है, "यदि आप कोटेशन बंद करना चाहते हैं, तो आपको एक खाली स्ट्रिंग सेट करने की आवश्यकता है। भागने - पहले से ही उद्धृत मूल्य के अंदर उद्धरण से बचने के लिए उपयोग किए जाने वाले एकल वर्ण को सेट करता है। यदि कोई नहीं है। , यह डिफ़ॉल्ट मान, \ एस्केप का उपयोग करता है - यह दर्शाता है कि क्या उद्धरण वाले मान हमेशा उद्धरणों में संलग्न होने चाहिए। यदि कोई भी सेट नहीं किया गया है, तो वह बोली मूल्य वाले सभी मूल्यों से बचकर, डिफ़ॉल्ट मान का उपयोग करता है। QuoteAll - एक झंडा जो दर्शाता है कि क्या सभी मूल्यों को हमेशा उद्धरण में संलग्न किया जाना चाहिए। यदि कोई भी सेट नहीं किया गया है, तो यह डिफ़ॉल्ट मान का उपयोग करता है झूठे, केवल उद्धरण चरित्र वाले मूल्यों से बचकर। शीर्षलेख - पहली पंक्ति के रूप में स्तंभों के नाम लिखते हैं। यदि कोई भी सेट नहीं है, तो वह डिफ़ॉल्ट मान का उपयोग करता है, गलत। nullValue - एक शून्य मान का स्ट्रिंग प्रतिनिधित्व सेट करता है। यदि कोई भी सेट नहीं है, तो यह डिफ़ॉल्ट मान, खाली स्ट्रिंग का उपयोग करता है। dateFormat - वह स्ट्रिंग सेट करता है जो एक तारीख प्रारूप को इंगित करता है। कस्टम दिनांक स्वरूप java.text.SimpleDateFormat पर स्वरूपों का अनुसरण करते हैं। यह दिनांक प्रकार पर लागू होता है। यदि कोई भी सेट नहीं किया गया है, तो यह डिफ़ॉल्ट मूल्य मान, yyyy-MM-dd का उपयोग करता है। टाइमस्टैम्पफ़ॉर्मैट - वह स्ट्रिंग सेट करता है जो टाइमस्टैम्प प्रारूप को इंगित करता है। कस्टम दिनांक स्वरूप java.text.SimpleDateFormat पर स्वरूपों का अनुसरण करते हैं। यह टाइमस्टैम्प प्रकार पर लागू होता है। यदि कोई भी सेट नहीं है, तो यह डिफ़ॉल्ट मान मान का उपयोग करता है, yyyy-MM-dd'T'HH: mm: ss.SSSZZ।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.