Une instruction SQL DDL peut-elle être analysée en un simple fichier de schéma JSON comme indiqué ci-dessous sans utiliser d'outils, uniquement des scripts Scala / Python / shell?
CREATE TABLE TEMP ( ID INT, NAME STRING) [ { "tableName": "temp", "columns": [ { "columnname": "id", "datatype": "int" }, { "columnname": "name", "datatype": "string" } ] } ]
4 Réponses :
Avec quelques correspondances comme par exemple décrites ici: Comment créer un modèle match en utilisant une expression régulière dans Scala? le code pour cela pourrait ressembler à celui ci-dessous, en supposant que votre expression initiale est passée sous forme de séquence de lignes (notez que JSONObject tel qu'utilisé ci-dessous est obsolète, remplacez-le par une alternative).
val data: (String, Seq[(String, String)]) = Parser.parse(Seq("CREATE TABLE TEMP (", "ID INT,", "NAME STRING)")) println(Parser.toJson(data._1, data._2))
Pour tester cela avec votre chaîne de test:
object Parser { implicit class Regex(sc: StringContext) { def r = new util.matching.Regex(sc.parts.mkString, sc.parts.tail.map(_ => "x"): _*) } def toJson(tablename: String, columns: Seq[(String,String)]): String = { val columnList: List[JSONObject] = columns.toStream.map(x => JSONObject(Map("columnname" -> x._1, "datatype" -> x._2))).toList JSONArray(List(JSONObject(Map("tableName" -> tablename, "columns" -> JSONArray(columnList))))).toString() } def parse(lines: Seq[String]): (String, Seq[(String,String)]) = { lines.mkString("").toLowerCase match { case r"create\s+table\s+(\S+)${tablename}\s+\((.+)${columns}\).*" => val columnWithType: immutable.Seq[(String, String)] = columns.split(",").toStream .map(x => x.split("\\s+")) .map(x => (x.head.toLowerCase, x(1).toLowerCase)) (tablename, columnWithType) case _ => ("",Seq.empty) } } }
Vous pouvez créer une chaîne au format JSON à partir de votre DDL en utilisant la logique ci-dessous (code Scala). Une fois la chaîne créée, elle est convertie en Dataframe
. Ce Dataframe
est ensuite enregistré dans un HDFS / Amazon S3 en tant que fichier JSON à l'aide de l'API intégrée de Dataframe
appelée write.json
import org.apache.spark.sql.types._ import spark.implicits._ val createSql = "CREATE TABLE TEMP (ID INT, NAME STRING)" var jsonString = """[{"tableName":"""" + createSql.split(" ")(2).toLowerCase + "\"," + "\"columns\":[" createSql.split(s"\\(")(1).split(s"\\)")(0).split(",").map(r => { jsonString += "{" + "\"columnname\": " + "\"" + r.trim.split(" ")(0).toLowerCase + "\"," + "\"datatype\": " + "\"" + r.trim.split(" ")(1).toLowerCase + "\"}," }) jsonString = jsonString.patch(jsonString.lastIndexOf(','), "", 1) + "]}]" val schema: StructType = null val reader = spark.read Option(schema).foreach(reader.schema) val df = reader.json(sc.parallelize(Array(jsonString))) df.coalesce(1).write.json("<targetlocation>")
Cela a parfaitement fonctionné pour moi. Si j'ai un pli sql dans un fichier avec plusieurs instructions DDL et qu'il y a des commentaires entre les deux à éviter dans le même fichier. ex: --- table 1 createSQL1 --table 2 createSql2 --table createSql3
Avec le package scala.util.parsing.combinator, vous pouvez définir votre analyseur Lexer et Grammer avec DDL comme ceci,
import scala.util.parsing.combinator._ class JSON extends JavaTokenParsers { def value: Parser[Any] = obj | arr | stringLiteral | floatingPointNumber | "null" | "true" | "false" def obj: Parser[Any] = "{"~repsep(member, ",")~"}" def arr: Parser[Any] = "["~repsep(value, ",")~"]" def member: Parser[Any] = stringLiteral~":"~value }
Le code ci-dessus serait utilisé pour analyser la chaîne JSON dans un flux lexel pour une autre procession. Lisez la documentation vous pourrez définir votre analyseur SQL DDL.
Nous venons de publier ce package dans https://github.com/deepstartup/jsonutils . Peut-être que vous le trouverez utile. Si vous avez besoin de nous pour mettre à jour quelque chose, ouvrez un JIRA.
Essayez:
pip install DDLJ from DDLj import genddl genddl(*param1,param2,*param3,*param4) Where param1= JSON Schema File param2=Database (Default Oracle) Param3= Glossary file Param4= DDL output script