如何将行号生成为现有表的列?

时间:2017-10-16 06:11:12

标签: mysql scala apache-spark apache-spark-sql

我想通过spark创建行号(row_num)作为MySql中现有表的列,以便并行读取数据库(即分区列,因为表中的所有列都是String)。

当我尝试执行此查询时:

val query = SELECT @row_number:=@row_number+1 as rowid,d.* FROM destination d, (SELECT @row_number:=0) as init

我遇到了如下例外情况:

17/10/16 10:50:00 INFO SparkSqlParser: Parsing command: SELECT @row_number:=@row_number+1 as rowid,d. FROM destination d, (SELECT @row_number:=0) as init
Exception in thread "main" org.apache.spark.sql.catalyst.parser.ParseException:
no viable alternative at input 'SELECT @'(line 1, pos 7)

== SQL ==
SELECT @row_number:=@row_number+1 as rowid,d. FROM destination d, (SELECT @row_number:=0) as init
-------^^^

at org.apache.spark.sql.catalyst.parser.ParseException.withCommand(ParseDriver.scala:197)
at org.apache.spark.sql.catalyst.parser.AbstractSqlParser.parse(ParseDriver.scala:99)
at org.apache.spark.sql.execution.SparkSqlParser.parse(SparkSqlParser.scala:45)
at org.apache.spark.sql.catalyst.parser.AbstractSqlParser.parsePlan(ParseDriver.scala:53)
at org.apache.spark.sql.SparkSession.sql(SparkSession.scala:592)
at com.syntel.spark.sparkDVT$.main(sparkDVT.scala:61)
at com.syntel.spark.sparkDVT.main(sparkDVT.scala)

我尝试的代码:

val p2 = "@row_number"
val a = s"""SELECT $p2:=$p2+1 as rowid,d.* FROM destination d, (SELECT $p2:=0) as init"""
val df1 = spark.sql(a)

参考:

https://forums.databricks.com/questions/115/how-do-i-pass-parameters-to-my-sql-statements.html

如何从mysql中的spark执行以下查询

val query = SELECT @row_number:=@row_number+1 as rowid,d.* FROM destination d, (SELECT @row_number:=0) as init

谢谢

2 个答案:

答案 0 :(得分:1)

  

我想通过spark创建行号(row_num)作为MySql中现有表的列

row_number函数

使用row_number

  

row_number():列窗口函数:在窗口分区中返回从1开始的序号。

您可以按如下方式使用它:

val input = spark.range(10)
scala> input.printSchema
root
 |-- id: long (nullable = false)

import org.apache.spark.sql.expressions.Window
val byId = Window.orderBy($"id".asc)
scala> input.withColumn("index", row_number over byId).show
17/10/16 08:27:01 WARN WindowExec: No Partition Defined for Window operation! Moving all data to a single partition, this can cause serious performance degradation.
+---+-----+
| id|index|
+---+-----+
|  0|    1|
|  1|    2|
|  2|    3|
|  3|    4|
|  4|    5|
|  5|    6|
|  6|    7|
|  7|    8|
|  8|    9|
|  9|   10|
+---+-----+

要小心,因为它是一个窗口函数,需要一个有序窗口,并将属于窗口分区的所有行移动到单个Spark分区,如警告所示:

  

17/10/16 08:27:01 WARN WindowExec:没有为窗口操作定义分区!将所有数据移动到单个分区,这可能会导致严重的性能下降。

这意味着对于一个非常大的数据集,由于OutOfMemoryError,您可能会产生很长的GC,甚至根本无法完成。

monotonically_increasing_id()函数

还有另一个功能monotonically_increasing_id

  

monotonically_increasing_id():Column 生成单调递增的64位整数的列表达式。

请注意......

  

生成的ID保证单调增加且唯一,但不是连续的。当前实现将分区ID放在高31位中,将每个分区中的记录号放在低33位中。假设数据框的分区少于10亿,每个分区的记录少于80亿。

答案 1 :(得分:0)

如果要执行mySQL查询,则需要使用标准JDBC API。

Spark SQL API与DataFrame ou DataSet(Spark对象)相关。

主题How do I pass parameters to my SQL statements?并未谈及mySql,而是my SQL