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
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.
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.
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 ...")
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()
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()
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