Spark - carregar arquivo CSV como DataFrame?

141

Gostaria de ler um CSV no spark e convertê-lo como DataFrame e armazená-lo no HDFS com df.registerTempTable("table_name")

Eu tentei:

scala> val df = sqlContext.load("hdfs:///csv/file/dir/file.csv")

Erro que recebi:

java.lang.RuntimeException: hdfs:///csv/file/dir/file.csv is not a Parquet file. expected magic number at tail [80, 65, 82, 49] but found [49, 59, 54, 10]
    at parquet.hadoop.ParquetFileReader.readFooter(ParquetFileReader.java:418)
    at org.apache.spark.sql.parquet.ParquetRelation2$MetadataCache$$anonfun$refresh$6.apply(newParquet.scala:277)
    at org.apache.spark.sql.parquet.ParquetRelation2$MetadataCache$$anonfun$refresh$6.apply(newParquet.scala:276)
    at scala.collection.parallel.mutable.ParArray$Map.leaf(ParArray.scala:658)
    at scala.collection.parallel.Task$$anonfun$tryLeaf$1.apply$mcV$sp(Tasks.scala:54)
    at scala.collection.parallel.Task$$anonfun$tryLeaf$1.apply(Tasks.scala:53)
    at scala.collection.parallel.Task$$anonfun$tryLeaf$1.apply(Tasks.scala:53)
    at scala.collection.parallel.Task$class.tryLeaf(Tasks.scala:56)
    at scala.collection.parallel.mutable.ParArray$Map.tryLeaf(ParArray.scala:650)
    at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask$class.compute(Tasks.scala:165)
    at scala.collection.parallel.AdaptiveWorkStealingForkJoinTasks$WrappedTask.compute(Tasks.scala:514)
    at scala.concurrent.forkjoin.RecursiveAction.exec(RecursiveAction.java:160)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

Qual é o comando certo para carregar o arquivo CSV como DataFrame no Apache Spark?

Donbeo
fonte
verifique este link para fazê-lo no Spark 2.0
mrsrinivas

Respostas:

179

O spark-csv faz parte da funcionalidade principal do Spark e não requer uma biblioteca separada. Então você poderia fazer, por exemplo

df = spark.read.format("csv").option("header", "true").load("csvfile.csv")

Em scala, (isso funciona para qualquer menção de delimitador de formato "," para csv, "\ t" para tsv etc.)

val df = sqlContext.read.format("com.databricks.spark.csv") .option("delimiter", ",") .load("csvfile.csv")

Shyamendra Solanki
fonte
163

Analisar CSV e carregar como DataFrame / DataSet com Spark 2.x

Primeiro, inicialize o SparkSessionobjeto por padrão, ele estará disponível em shells comospark

val spark = org.apache.spark.sql.SparkSession.builder
        .master("local") # Change it as per your cluster
        .appName("Spark CSV Reader")
        .getOrCreate;

Use qualquer uma das seguintes maneiras para carregar o CSV como DataFrame/DataSet

1. Faça isso de maneira programática

 val df = spark.read
         .format("csv")
         .option("header", "true") //first line in file has headers
         .option("mode", "DROPMALFORMED")
         .load("hdfs:///csv/file/dir/file.csv")

Atualização: adicionando todas as opções daqui caso o link seja quebrado no futuro

  • caminho : localização dos arquivos. Semelhante ao Spark, pode aceitar expressões globbing padrão do Hadoop.
  • header : quando definido como true, a primeira linha de arquivos será usada para nomear colunas e não será incluída nos dados. Todos os tipos serão assumidos como string. O valor padrão é falso.
  • delimitador : por padrão, as colunas são delimitadas usando, mas o delimitador pode ser definido como qualquer caractere
  • quote : por padrão, o caractere de citação é ", mas pode ser definido como qualquer caractere. Delimitadores entre aspas são ignorados
  • escape : por padrão, o caractere de escape é, mas pode ser definido como qualquer caractere. Caracteres de aspas escapados são ignorados
  • parserLib : por padrão, são " comuns " que podem ser configurados como " univocidade " para usar essa biblioteca para análise de CSV.
  • mode : determina o modo de análise. Por padrão, é PERMISSIVO. Os valores possíveis são:
    • PERMISSIVO : tenta analisar todas as linhas: nulos são inseridos para tokens ausentes e tokens extras são ignorados.
    • DROPMALFORMED : descarta linhas que possuem menos ou mais tokens do que o esperado ou tokens que não correspondem ao esquema
    • FAILFAST : interrompe com um RuntimeException se encontrar algum conjunto de linhas mal formado: o padrão é 'UTF-8', mas pode ser definido com outros nomes de conjuntos de caracteres válidos
  • inferSchema : infere automaticamente os tipos de coluna. Ele requer uma passagem extra sobre os dados e é falso por comentário padrão: pula as linhas que começam com esse caractere. O padrão é "#". Desative os comentários configurando-o como nulo.
  • nullValue : especifica uma sequência que indica um valor nulo; todos os campos correspondentes a essa sequência serão definidos como nulos no DataFrame
  • dateFormat : especifica uma sequência que indica o formato da data a ser usado ao ler datas ou registros de data e hora. Os formatos de data personalizados seguem os formatos em java.text.SimpleDateFormat. Isso se aplica a DateType e TimestampType. Por padrão, é nulo, o que significa tentar analisar horários e datas por java.sql.Timestamp.valueOf () e java.sql.Date.valueOf ().

2. Você também pode fazer isso da maneira SQL

 val df = spark.sql("SELECT * FROM csv.`hdfs:///csv/file/dir/file.csv`")

Dependências :

 "org.apache.spark" % "spark-core_2.11" % 2.0.0,
 "org.apache.spark" % "spark-sql_2.11" % 2.0.0,

Versão Spark <2.0

val df = sqlContext.read
    .format("com.databricks.spark.csv")
    .option("header", "true") 
    .option("mode", "DROPMALFORMED")
    .load("csv/file/path"); 

Dependências:

"org.apache.spark" % "spark-sql_2.10" % 1.6.0,
"com.databricks" % "spark-csv_2.10" % 1.6.0,
"com.univocity" % "univocity-parsers" % LATEST,
mrsrinivas
fonte
esta sessão requer colméia? Estou recebendo erros de colméia.
Puneet
2
Não há necessidade. Somente spark-core_2.11e spark-sql_2.11da 2.0.1versão está bem. Se possível, adicione a mensagem de erro.
Mrsrinivas
1
podemos converter um arquivo delimitado por canal em um quadro de dados?
Omkar 23/03
3
@OmkarPuttagunta: Sim, claro! tente algo assim spark.read.format("csv").option("delimiter ", "|") ...
mrsrinivas 23/03
1
A outra opção para programmatic wayé deixar de fora .format("csv")e substituir .load(...por .csv(.... O optionmétodo pertence à classe DataFrameReader conforme retornada pelo readmétodo, onde os métodos loade csvretornam um dataframe, portanto, não é possível ter opções marcadas após serem chamadas. Esta resposta é bastante completa, mas você deve vincular a documentação para que as pessoas possam ver todas as outras opções de CSV disponíveis spark.apache.org/docs/latest/api/scala/… *): org.apache.spark.sql.DataFrame
Davos
17

É para quem o Hadoop é 2.6 e o ​​Spark é 1.6 e sem o pacote "databricks".

import org.apache.spark.sql.types.{StructType,StructField,StringType,IntegerType};
import org.apache.spark.sql.Row;

val csv = sc.textFile("/path/to/file.csv")
val rows = csv.map(line => line.split(",").map(_.trim))
val header = rows.first
val data = rows.filter(_(0) != header(0))
val rdd = data.map(row => Row(row(0),row(1).toInt))

val schema = new StructType()
    .add(StructField("id", StringType, true))
    .add(StructField("val", IntegerType, true))

val df = sqlContext.createDataFrame(rdd, schema)
Eric Yiwei Liu
fonte
12

Com o Spark 2.0, a seguir é como você pode ler CSV

val conf = new SparkConf().setMaster("local[2]").setAppName("my app")
val sc = new SparkContext(conf)
val sparkSession = SparkSession.builder
  .config(conf = conf)
  .appName("spark session example")
  .getOrCreate()

val path = "/Users/xxx/Downloads/usermsg.csv"
val base_df = sparkSession.read.option("header","true").
  csv(path)
centavo chan
fonte
5
Existe uma diferença entre spark.read.csv(path)e spark.read.format("csv").load(path)?
Eric
8

Em Java 1.8 Este trecho de código funciona perfeitamente para ler arquivos CSV

POM.xml

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-core_2.11</artifactId>
    <version>2.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-sql_2.10 -->
<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-sql_2.10</artifactId>
    <version>2.0.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.scala-lang/scala-library -->
<dependency>
    <groupId>org.scala-lang</groupId>
    <artifactId>scala-library</artifactId>
    <version>2.11.8</version>
</dependency>
<dependency>
    <groupId>com.databricks</groupId>
    <artifactId>spark-csv_2.10</artifactId>
    <version>1.4.0</version>
</dependency>

Java

SparkConf conf = new SparkConf().setAppName("JavaWordCount").setMaster("local");
// create Spark Context
SparkContext context = new SparkContext(conf);
// create spark Session
SparkSession sparkSession = new SparkSession(context);

Dataset<Row> df = sparkSession.read().format("com.databricks.spark.csv").option("header", true).option("inferSchema", true).load("hdfs://localhost:9000/usr/local/hadoop_data/loan_100.csv");

        //("hdfs://localhost:9000/usr/local/hadoop_data/loan_100.csv");
System.out.println("========== Print Schema ============");
df.printSchema();
System.out.println("========== Print Data ==============");
df.show();
System.out.println("========== Print title ==============");
df.select("title").show();
Rajeev Rathor
fonte
Embora isso possa ser útil para alguém. A pergunta tem uma tag Scala.
OneCricketeer
5

Existem muitos desafios para analisar um arquivo CSV, ele continua aumentando se o tamanho do arquivo for maior, se houver caracteres em inglês / escape / separator / outros nos valores da coluna, que podem causar erros de análise.

A mágica está nas opções usadas. Os que funcionaram para mim e espero que devam cobrir a maioria dos casos extremos estão no código abaixo:

### Create a Spark Session
spark = SparkSession.builder.master("local").appName("Classify Urls").getOrCreate()

### Note the options that are used. You may have to tweak these in case of error
html_df = spark.read.csv(html_csv_file_path, 
                         header=True, 
                         multiLine=True, 
                         ignoreLeadingWhiteSpace=True, 
                         ignoreTrailingWhiteSpace=True, 
                         encoding="UTF-8",
                         sep=',',
                         quote='"', 
                         escape='"',
                         maxColumns=2,
                         inferSchema=True)

Espero que ajude. Para mais informações, consulte: Usando PySpark 2 para ler CSV com código-fonte HTML

Nota: O código acima é da API do Spark 2, onde a API de leitura de arquivo CSV é fornecida com pacotes integrados do Spark instalável.

Nota: PySpark é um wrapper Python para Spark e compartilha a mesma API que Scala / Java.

karthiks
fonte
Muito obrigado, você salvou minha vida: D
Khubaib Raza 06/06
4

O exemplo do Penny's Spark 2 é a maneira de fazê-lo no spark2. Há mais um truque: tenha esse cabeçalho gerado para você fazendo uma varredura inicial dos dados, definindo a opção inferSchemacomotrue

Aqui, supondo que sparkseja uma sessão spark que você configurou, está a operação a carregar no arquivo de índice CSV de todas as imagens do Landsat hospedadas pela Amazon no S3.

  /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *    http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */

val csvdata = spark.read.options(Map(
    "header" -> "true",
    "ignoreLeadingWhiteSpace" -> "true",
    "ignoreTrailingWhiteSpace" -> "true",
    "timestampFormat" -> "yyyy-MM-dd HH:mm:ss.SSSZZZ",
    "inferSchema" -> "true",
    "mode" -> "FAILFAST"))
  .csv("s3a://landsat-pds/scene_list.gz")

A má notícia é: isso desencadeia uma varredura no arquivo; para algo grande como esse arquivo CSV compactado com mais de 20 MB, que pode levar 30 segundos em uma conexão de longo curso. Lembre-se: é melhor codificar manualmente o esquema depois que ele chegar.

(trecho de código Apache Software License 2.0 licenciado para evitar toda ambiguidade; algo que fiz como teste de demonstração / integração da integração com o S3)

stevel
fonte
Eu não tinha visto esse método csv ou passando um mapa para opções. Concordado sempre em fornecer esquema explícito, inferSchema é bom para quick n dirty (também conhecido como ciência de dados), mas terrível para ETL.
Davos
2

Caso você esteja construindo um jar com o scala 2.11 e o Apache 2.0 ou superior.

Não há necessidade de criar um sqlContextou sparkContextobjeto. Apenas umSparkSession objeto é suficiente para todas as necessidades.

A seguir está o meu código, que funciona bem:

import org.apache.spark.sql.{DataFrame, Row, SQLContext, SparkSession}
import org.apache.log4j.{Level, LogManager, Logger}

object driver {

  def main(args: Array[String]) {

    val log = LogManager.getRootLogger

    log.info("**********JAR EXECUTION STARTED**********")

    val spark = SparkSession.builder().master("local").appName("ValidationFrameWork").getOrCreate()
    val df = spark.read.format("csv")
      .option("header", "true")
      .option("delimiter","|")
      .option("inferSchema","true")
      .load("d:/small_projects/spark/test.pos")
    df.show()
  }
}

No caso de você estar executando no cluster, mude .master("local")para .master("yarn")enquanto define osparkBuilder objeto

O Spark Doc cobre isso: https://spark.apache.org/docs/2.2.0/sql-programming-guide.html

swapnil shashank
fonte
Isto é o mesmo que as respostas existentes
mrsrinivas 17/11/19
0

Adicione as seguintes dependências do Spark ao arquivo POM:

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-core_2.11</artifactId>
    <version>2.2.0</version>
</dependency>
<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-sql_2.11</artifactId>
    <version>2.2.0</version>
</dependency>

// Configuração do Spark:

val spark = SparkSession.builder (). master ("local"). appName ("Sample App"). getOrCreate ()

// Leia o arquivo csv:

val df = spark.read.option ("cabeçalho", "true"). csv ("FILE_PATH")

// Exibir saída

df.show ()

S_K
fonte
0

Para ler do caminho relativo no sistema, use o método System.getProperty para obter o diretório atual e outros usos para carregar o arquivo usando o caminho relativo.

scala> val path = System.getProperty("user.dir").concat("/../2015-summary.csv")
scala> val csvDf = spark.read.option("inferSchema","true").option("header", "true").csv(path)
scala> csvDf.take(3)

faísca: 2.4.4 scala: 2.11.12

Venkat Kotra
fonte
0

Com o Spark 2.4+, se você deseja carregar um csv de um diretório local, pode usar 2 sessões e carregá-lo no hive. A primeira sessão deve ser criada com a configuração master () como "local [*]" e a segunda sessão com "yarn" e o Hive habilitado.

O abaixo funcionou para mim.

import org.apache.log4j.{Level, Logger}
import org.apache.spark._
import org.apache.spark.rdd._
import org.apache.spark.sql._

object testCSV { 

  def main(args: Array[String]) {
    Logger.getLogger("org").setLevel(Level.ERROR)
    val spark_local = SparkSession.builder().appName("CSV local files reader").master("local[*]").getOrCreate()

    import spark_local.implicits._
    spark_local.sql("SET").show(100,false)
    val local_path="/tmp/data/spend_diversity.csv"  // Local file
    val df_local = spark_local.read.format("csv").option("inferSchema","true").load("file://"+local_path) // "file://" is mandatory
    df_local.show(false)

    val spark = SparkSession.builder().appName("CSV HDFS").config("spark.sql.warehouse.dir", "/apps/hive/warehouse").enableHiveSupport().getOrCreate()

    import spark.implicits._
    spark.sql("SET").show(100,false)
    val df = df_local
    df.createOrReplaceTempView("lcsv")
    spark.sql(" drop table if exists work.local_csv ")
    spark.sql(" create table work.local_csv as select * from lcsv ")

   }

Quando correu com spark2-submit --master "yarn" --conf spark.ui.enabled=false testCSV.jarele correu bem e criou a tabela na colméia.

stack0114106
fonte
-1

O formato de arquivo padrão é Parquet com spark.read .. e a leitura de arquivo csv é por isso que você está recebendo a exceção. Especifique o formato csv com a API que você está tentando usar

tazak
fonte
-1

Tente isso se estiver usando o spark 2.0+

For non-hdfs file:
df = spark.read.csv("file:///csvfile.csv")


For hdfs file:
df = spark.read.csv("hdfs:///csvfile.csv")

For hdfs file (with different delimiter than comma:
df = spark.read.option("delimiter","|")csv("hdfs:///csvfile.csv")

Nota: - este trabalho para qualquer arquivo delimitado. Basta usar a opção (“delimitador”) para alterar o valor.

Espero que isso seja útil.

Ajay Ahuja
fonte
Isto é o mesmo que as respostas existentes
mrsrinivas
-1

Com o Spark csv incorporado, você pode fazer isso facilmente com o novo objeto SparkSession para Spark> 2.0.

val df = spark.
        read.
        option("inferSchema", "false").
        option("header","true").
        option("mode","DROPMALFORMED").
        option("delimiter", ";").
        schema(dataSchema).
        csv("/csv/file/dir/file.csv")
df.show()
df.printSchema()

Existem várias opções que você pode definir.

  • header: se seu arquivo inclui a linha do cabeçalho na parte superior
  • inferSchema: se você deseja inferir o esquema automaticamente ou não. O padrão é true. Eu sempre prefiro fornecer esquema para garantir tipos de dados adequados.
  • mode: modo de análise, PERMISSIVE, DROPMALFORMED ou FAILFAST
  • delimiter: para especificar delimitador, o padrão é vírgula (',')
Piyush Patel
fonte