有限制的SparkSQL中的嵌套查询

时间:2018-08-16 14:24:04

标签: java apache-spark apache-spark-sql

我有一个表,需要根据某些列的相同共享值将当前事件与先前事件进行匹配。这是一个简化的示例:

e5028218-eea8-41b0-951c-ccd006f35bc8    1533648871.77204    braden  NULL
120cd0fd-15d2-40e8-8285-53499a5aa294    1533648871.77262    gracelyn    NULL
78a40fdd-f361-4929-ad6b-1ee411300c84    1533648871.77274    cruz    NULL
ec463751-22ca-4776-9cff-f7a332bab8b6    1533648871.77285    bob NULL
b824c942-bfc5-4cee-90d3-26686e7ace2e    1533648871.77296    amara   NULL
527170df-1499-4cfa-be2c-f484a8cf01f4    1533648871.77307    jerry   NULL
2116e07b-14ea-4760-be3e-f9db7f051831    1533648871.77318    bob ec463751-22ca-4776-9cff-f7a332bab8b6
951df6c9-5a7b-4208-a8bb-8075a37f61ba    1533648871.7733 gael    NULL
3859a175-f16b-4fd1-9e66-03f5f3b295f4    1533648871.77341    bob 2116e07b-14ea-4760-be3e-f9db7f051831
6d60a51b-c822-45b3-8a4a-5f535372e11b    1533648871.77351    jaime   NULL
0becf14b-442b-4ac7-9819-2144c50bc611    1533648871.77362    brock   NULL
001eea59-751f-4b51-ba1d-f706190cbae3    1533648871.77373    kyleigh NULL

Bob有几个与他相关联的transID,因此对于每一行,transID列中显示的是timeStamp,其中transIDPred来自前几行。对于其他行,该列应保持为空。

通过运行这样的简单SQL语句,我可以在MySQL中使用transIDPred轻松地创建一个表:

create table Events1 as
select 
    transID, 
    timeStamp,
    principal,
    (select transID from Events sub 
        where (sub.principal = main.principal and sub.timeStamp < main.timeStamp)
        order by timeStamp desc limit 1) as 
    transIDPred 
from Events as main  order by transID asc

但是,如果我尝试在SparkSQL中运行类似的查询,则会出现以下错误:

Exception in thread "main" org.apache.spark.sql.AnalysisException: Accessing outer query column is not allowed in....

根据这篇有用的文章,我设法部分重写了与该查询相对应的Spark(JAVA): How to write a nested query?

但是我无法使其完全正常工作,因为我不知道如何只选择最新的前身ID,而不是全部。

代码看起来像这样:

    Dataset<Row> ds = ... (load from SQL)
    ds.createOrReplaceTempView("Events");

    Dataset<Row> dsSub = ds
            .withColumnRenamed("transID", "subTransID") 
            .withColumnRenamed("timeStamp", "subTimeStamp")
            .withColumnRenamed("principal", "subPrincipal")
            .orderBy(org.apache.spark.sql.functions.desc("subTimeStamp"));
    Dataset<Row> trnJoin = ds
            .join(dsSub)
            .where("subPrincipal = principal and timeStamp > subTimeStamp")
            .select("transID", "timeStamp", "principal", "subTransID");

但是我不知道如何将1的限制应用于子查询(似乎Spark只能将.limit()应用于查询的外部,这似乎理解为这种情况?在这种情况下,它只是创建为Dataset只能有1行。否则,如果没有.limit()子句,它将匹配所有匹配的行,而不是所有前任中的最新行。我需要在JAVA中做到这一点。

谢谢您的任何建议!另外,如果您对大型数据集(例如1亿至10亿个元素)上的SparkSQL中的这种连接的潜在性能有任何看法-甚至建议在Spark中执行此操作,还是我应该针对整个数据库? >

0 个答案:

没有答案