如果在列表中的任何点集之间过滤Spark DataFrame

时间:2016-08-04 02:04:53

标签: performance scala apache-spark spark-dataframe

我有一个spark数据帧(使用scala接口),它包含时间戳,资产(字符串),标记(字符串)和值(双精度)列。以下是摘录:

00011000

我还有一个+--------------------+-----+--------+-------------------+ | timestamp|asset| tag| value| +--------------------+-----+--------+-------------------+ |2013-01-03 23:36:...| G4| BTGJ2_2| 116.985626221| |2013-01-15 00:36:...| G4| TTXD1_6| 66.887382507| |2013-01-05 13:03:...| G4|TTXD1_22| 40.913497925| |2013-01-12 04:43:...| G4|TTXD1_23| 60.834510803| |2013-01-08 17:54:...| G4| LTB1D| 106.534744263| |2013-01-02 04:15:...| G4| WEXH| 255.981292725| |2013-01-07 10:54:...| G4| BTTA1_7| 100.743843079| |2013-01-05 11:29:...| G4| CDFH_10| 388.560668945| |2013-01-10 09:10:...| G4| LTB1D| 112.226242065| |2013-01-13 15:09:...| G4|TTXD1_15| 63.970848083| |2013-01-15 01:23:...| G4| TTIB| 67.993904114| ,其中每个Array[List[Timestamp]]的大小为2,并保存感兴趣区间的开始和结束时间。例如:

List

持有两个感兴趣的间隔:一个是2013-01-02的午夜到12:00,另一个是2013-01-10午夜到2013-01-12的6:00

以下是我的问题:如何过滤数据框以返回值,以便时间戳位于任何的时间间隔内?对于任何一个区间,我都可以做到

event_times: Array[List[java.sql.Timestamp]] = Array(List(2013-01-02 00:00:00.0, 2013-01-02 12:00:00.0), List(2013-01-10 00:00:00.0, 2013-01-12 06:00:00.0))

由于我不知道df.filter(df("timestamp").between(start, end)) 中有多少元素(我有多少个区间),我不能只有一长串过滤器。

对于上面的示例,我希望保留第4,6和9行。

我现在拥有的是Array上的循环,并为每个循环获取相应的子集。但是,这可能比将它们都放在一个大过滤器中要慢一些吗?

1 个答案:

答案 0 :(得分:3)

您可以将时间戳列表转换为DataFrame,并将其与相应时间戳上的初始DataFrame相关联。我已经创建了一个简单的例子来说明这个过程:

//Dummy data
val data = List(
  ("2013-01-02 00:30:00.0", "116.985626221"),
  ("2013-01-03 00:30:00.0", "66.887382507"),
  ("2013-01-11 00:30:00.0", "12.3456")
)

//Convert data to DataFrame
val dfData = sc.parallelize(data).toDF("timestamp", "value")

//Timestamp intervals list
val filterList = Array(
  List("2013-01-02 00:00:00.0", "2013-01-02 12:00:00.0"), 
  List("2013-01-10 00:00:00.0", "2013-01-12 06:00:00.0")
)

//Convert the intervals list to a DataFrame
val dfIntervals = sc.parallelize(
  filterList.map(l => (l(0),l(1)))
).toDF("start_ts","end_ts")

//Join both dataframes (inner join, since you only want matching rows)
val joined = dfData.as("data").join(
  dfIntervals.as("inter"), 
  $"data.timestamp".between($"inter.start_ts", $"inter.end_ts")
)