web-dev-qa-db-fra.com

Créer Spark Dataframe from SQL Query

Je suis sûr que c'est une simple question SQLContext, mais je ne trouve aucune réponse dans les documents Spark ou Stackoverflow

Je veux créer un Spark Dataframe à partir d'une requête SQL sur MySQL

Par exemple, j'ai une requête MySQL compliquée comme

SELECT a.X,b.Y,c.Z FROM FOO as a JOIN BAR as b ON ... JOIN ZOT as c ON ... WHERE ...

et je veux un Dataframe avec les colonnes X, Y et Z

J'ai compris comment charger des tables entières dans Spark, et je pouvais toutes les charger, puis faire la jonction et la sélection là-bas. Cependant, c'est très inefficace. Je veux juste charger la table générée par ma requête SQL.

Voici mon approximation actuelle du code, cela ne fonctionne pas. Mysql-connector a une option "dbtable" qui peut être utilisée pour charger une table entière. J'espère qu'il existe un moyen de spécifier une requête

  val df = sqlContext.format("jdbc").
    option("url", "jdbc:mysql://localhost:3306/local_content").
    option("driver", "com.mysql.jdbc.Driver").
    option("useUnicode", "true").
    option("continueBatchOnError","true").
    option("useSSL", "false").
    option("user", "root").
    option("password", "").
    sql(
"""
select dl.DialogLineID, dlwim.Sequence, wi.WordRootID from Dialog as d
join DialogLine as dl on dl.DialogID=d.DialogID
join DialogLineWordInstanceMatch as dlwim o n dlwim.DialogLineID=dl.DialogLineID
join WordInstance as wi on wi.WordInstanceID=dlwim.WordInstanceID
join WordRoot as wr on wr.WordRootID=wi.WordRootID
where d.InSite=1 and dl.Active=1
limit 100
"""
    ).load()

Merci Peter

13
user1902291

OK, voici la réponse ...

J'ai trouvé cela ici Migration de données en masse via Spark SQL

Le paramètre dbname peut être n'importe quelle requête enveloppée entre parenthèses avec un alias. Donc dans mon cas, je dois faire ça ...

val query = """
  (select dl.DialogLineID, dlwim.Sequence, wi.WordRootID from Dialog as d
    join DialogLine as dl on dl.DialogID=d.DialogID
    join DialogLineWordInstanceMatch as dlwim on dlwim.DialogLineID=dl.DialogLineID
    join WordInstance as wi on wi.WordInstanceID=dlwim.WordInstanceID
    join WordRoot as wr on wr.WordRootID=wi.WordRootID
    where d.InSite=1 and dl.Active=1
    limit 100) foo
"""

val df = sqlContext.format("jdbc").
  option("url", "jdbc:mysql://localhost:3306/local_content").
  option("driver", "com.mysql.jdbc.Driver").
  option("useUnicode", "true").
  option("continueBatchOnError","true").
  option("useSSL", "false").
  option("user", "root").
  option("password", "").
  option("dbtable",query).
  load()

Comme prévu, charger chaque table en tant que son propre Dataframe et les joindre dans Spark était très inefficace.

32
user1902291

pour enregistrer la sortie d'une requête dans une nouvelle trame de données, définissez simplement le résultat égal à une variable:

val newDataFrame = spark.sql("SELECT a.X,b.Y,c.Z FROM FOO as a JOIN BAR as b ON ... JOIN ZOT as c ON ... WHERE ...")

et maintenant newDataFrame est une trame de données avec toutes les fonctionnalités de trame de données à sa disposition.

1
Kristian

Si votre table est déjà enregistré dans votre SQLContext , vous pouvez simplement utiliser la méthode sql.

val resultDF = sqlContext.sql("SELECT a.X,b.Y,c.Z FROM FOO as a JOIN BAR as b ON ... JOIN ZOT as c ON ... WHERE ...")
1
Alberto Bonsanto

avec MYSQL lire/charger des données quelque chose comme ci-dessous

val conf = new SparkConf().setAppName("SparkMe Application").setMaster("local[2]")
    val sc = new SparkContext(conf)
    sc.setLogLevel("ERROR")
    val sqlContext = new org.Apache.spark.sql.SQLContext(sc)
    val jdbcDF = sqlContext.read.format("jdbc").options(
      Map("url" -> "jdbc:mysql://<Host>:3306/corbonJDBC?user=user&password=password",
        "dbtable" -> "TABLE_NAME")).load()

écrire des données dans le tableau comme ci-dessous

import Java.util.Properties
    val prop = new Properties()
    prop.put("user", "<>")
    prop.put("password", "simple$123")
    val dfWriter = jdbcDF.write.mode("append")
    dfWriter.jdbc("jdbc:mysql://<Host>:3306/corbonJDBC?user=user&password=password", "tableName", prop)

pour créer un cadre de données à partir d'une requête, faites quelque chose comme ci-dessous

val finalModelDataDF = {
      val query = "select * from table_name"
      sqlContext.sql(query)
    };

    finalModelDataDF.show()
0
Santhosh Hirekerur

TL; DR: créez simplement une vue dans votre base de données.

Détail: J'ai une table t_city dans ma base de données postgres, sur laquelle je crée une vue:

create view v_city_3500 as
    select asciiname, country, population, elevation
    from t_city
    where elevation>3500
    and population>100000

select * from v_city_3500;

 asciiname | country | population | elevation
-----------+---------+------------+-----------
 Potosi    | BO      |     141251 |      3967
 Oruro     | BO      |     208684 |      3936
 La Paz    | BO      |     812799 |      3782
 Lhasa     | CN      |     118721 |      3651
 Puno      | PE      |     116552 |      3825
 Juliaca   | PE      |     245675 |      3834

Dans l'étincelle:

val sx= new org.Apache.spark.sql.SQLContext(sc)

var props=new Java.util.Properties()
props.setProperty("driver", "org.postgresql.Driver" )
val url="jdbc:postgresql://buya/dmn?user=dmn&password=dmn"

val city_df=sx.read.jdbc(url=url,table="t_city",props)
val city_3500_df=sx.read.jdbc(url=url,table="v_city_3500",props)

Résultat:

city_df.count()
Long = 145725

city_3500_df.count()
Long = 6
0
WillemM