Как пропустить заголовок из файлов CSV в Spark?

Предположим, что я даю три файла пути к контексту Spark для чтения, и каждый файл имеет схему в первой строке. Как мы можем пропускать строки схемы из заголовков?

val rdd=sc.textFile("file1,file2,file3")

Теперь, как мы можем пропустить строки заголовка из этого rdd?

Ответ 1

Если бы в первой записи была только одна строка заголовка, то самый эффективный способ отфильтровать ее:

rdd.mapPartitionsWithIndex {
  (idx, iter) => if (idx == 0) iter.drop(1) else iter 
}

Это не поможет, если, конечно, есть много файлов с большим количеством строк заголовка. Вы можете объединить три RDD, которые вы делаете таким образом.

Вы также можете просто написать filter который соответствует только строке, которая может быть заголовком. Это довольно просто, но менее эффективно.

Эквивалент Python:

from itertools import islice

rdd.mapPartitionsWithIndex(
    lambda idx, it: islice(it, 1, None) if idx == 0 else it 
)

Ответ 2

data = sc.textFile('path_to_data')
header = data.first() #extract header
data = data.filter(row => row != header)   #filter out header

Ответ 3

В Spark 2.0 считыватель CSV встроен в Spark, поэтому вы можете легко загрузить CSV файл следующим образом:

spark.read.option("header","true").csv("filePath")

Ответ 4

Начиная с Spark 2.0, вы можете использовать SparkSession, чтобы сделать это как один лайнер:

val spark = SparkSession.builder.config(conf).getOrCreate()

а затем как @SandeepPurohit сказал:

val dataFrame = spark.read.format("CSV").option("header","true").load(csvfilePath)

Я надеюсь, что он решил ваш вопрос!

P.S: SparkSession - это новая точка входа, введенная в Spark 2.0, и ее можно найти в пакете spark_sql

Ответ 5

В PySpark вы можете использовать dataframe и задавать заголовок как True:

df = spark.read.csv(dataPath, header=True)

Ответ 6

Вы можете загружать каждый файл отдельно, фильтровать их с помощью file.zipWithIndex().filter(_._2 > 0), а затем объединять все файлы RDD.

Если количество файлов слишком велико, объединение может выполнить команду StackOverflowExeption.

Ответ 7

Используйте метод filter() в PySpark, отфильтровывая первое имя столбца, чтобы удалить заголовок:

# Read file (change format for other file formats)
contentRDD = sc.textfile(<filepath>)

# Filter out first column of the header
filterDD = contentRDD.filter(lambda l: not l.startswith(<first column name>)

# Check your result
for i in filterDD.take(5) : print (i)

Ответ 8

Это опция, которую вы передаете команде read():

context = new org.apache.spark.sql.SQLContext(sc)

var data = context.read.option("header","true").csv("<path>")

Ответ 9

Работаю в 2018 году (Spark 2.3)

питон

df = spark.read
    .option("header", "true")
    .format("csv")
    .schema(myManualSchema)
    .load("mycsv.csv")

Scala

val myDf = spark.read
  .option("header", "true")
  .format("csv")
  .schema(myManualSchema)
  .load("mycsv.csv")

PD1: myManualSchema - предопределенная схема, написанная мной, вы можете пропустить эту часть кода

Ответ 10

В качестве альтернативы вы можете использовать пакет spark-csv (или в Spark 2.0 это более или менее доступно изначально CSV). Обратите внимание, что это ожидает заголовок для каждого файла (по вашему желанию):

schema = StructType([
        StructField('lat',DoubleType(),True),
        StructField('lng',DoubleType(),True)])

df = sqlContext.read.format('com.databricks.spark.csv'). \
     options(header='true',
             delimiter="\t",
             treatEmptyValuesAsNulls=True,
             mode="DROPMALFORMED").load(input_file,schema=schema)

Ответ 11

Это должно работать нормально

def dropHeader(data: RDD[String]): RDD[String] = {

     data.filter(r => r!=data.first)
 }

Ответ 12

//Find header from the files lying in the directory
val fileNameHeader = sc.binaryFiles("E:\\sss\\*.txt",1).map{
    case (fileName, stream)=>
        val header = new BufferedReader(new InputStreamReader(stream.open())).readLine()
        (fileName, header)
}.collect().toMap

val fileNameHeaderBr = sc.broadcast(fileNameHeader)

// Now let skip the header. mapPartition will ensure the header
// can only be the first line of the partition
sc.textFile("E:\\sss\\*.txt",1).mapPartitions(iter =>
    if(iter.hasNext){
        val firstLine = iter.next()
        println(s"Comparing with firstLine $firstLine")
        if(firstLine == fileNameHeaderBr.value.head._2)
            new WrappedIterator(null, iter)
        else
            new WrappedIterator(firstLine, iter)
    }
    else {
        iter
    }
).collect().foreach(println)

class WrappedIterator(firstLine:String,iter:Iterator[String]) extends Iterator[String]{
    var isFirstIteration = true
    override def hasNext: Boolean = {
        if (isFirstIteration && firstLine != null){
            true
        }
        else{
            iter.hasNext
        }
    }

    override def next(): String = {
        if (isFirstIteration){
            println(s"For the first time $firstLine")
            isFirstIteration = false
            if (firstLine != null){
                firstLine
            }
            else{
                println(s"Every time $firstLine")
                iter.next()
            }
        }
        else {
          iter.next()
        }
    }
}

Ответ 13

Для разработчиков python. Я тестировал с помощью spark2.0. Скажем, вы хотите удалить первые 14 строк.

sc = spark.sparkContext
lines = sc.textFile("s3://folder_location_of_csv/")
parts = lines.map(lambda l: l.split(","))
parts.zipWithIndex().filter(lambda tup: tup[1] > 14).map(lambda x:x[0])

withColumn - это функция df. Поэтому ниже не будет работать в стиле RDD, как указано выше.

parts.withColumn("index",monotonically_increasing_id()).filter(index > 14)