Heyo StackOverflow,
В настоящее время я пытаюсь найти элегантный способ выполнить конкретное c преобразование.
Итак, у меня есть блок данных действий, который выглядит следующим образом:
+---------+----------+----------+---------+
|timestamp| user_id| action| value|
+---------+----------+----------+---------+
| 100| 1| click| null|
| 101| 2| click| null|
| 103| 1| drag| AAA|
| 101| 1| click| null|
| 108| 1| click| null|
| 100| 2| click| null|
| 106| 1| drag| BBB|
+---------+----------+----------+---------+
Контекст: пользователи могут выполнять действия: щелчки и перетаскивания. Клики не имеют значения, перетаскивают. Перетаскивание подразумевает, что был щелчок, но не наоборот. Также предположим, что событие перетаскивания может быть записано после или до события щелчка. Таким образом, у меня есть для каждого перетаскивания соответствующее действие щелчка. То, что я хотел бы сделать, это объединить действия перетаскивания и щелчка в 1, ie. Удалите действие перетаскивания после присвоения его value
действию щелчка.
Чтобы узнать, какой щелчок соответствует какому перетаскиванию, я должен взять щелчок, отметка времени которого ближе всего к timestamp
перетаскивания. Я также хочу убедиться, что перетаскивание не может быть связано с кликом, если разница между отметками времени превышает 5 (и это означает, что некоторые перетаскивания могут быть не связаны, это нормально). Конечно, я не хочу, чтобы перетаскивание пользователя 1 соответствовало клику пользователя 2.
Здесь результат будет выглядеть следующим образом:
+---------+----------+----------+---------+
|timestamp| user_id| action| value|
+---------+----------+----------+---------+
| 100| 1| click| null|
| 101| 2| click| null|
| 101| 1| click| AAA|
| 108| 1| click| BBB|
| 100| 2| click| null|
+---------+----------+----------+---------+
Перетаскивание с помощью AAA
(timestamp
= 103) был связан с кликом, который произошел в 101, потому что он ближе всего к 103. Те же логы c для BBB
.
Так что я хотел бы выполнить эти операции, гладко / эффективно. Пока что у меня есть что-то вроде этого:
val window = Window partitionBy ($"user_id") orderBy $"timestamp".asc
myDF
.withColumn("previous_value", lag("value", 1, null) over window)
.withColumn("previous_timestamp", lag("timestamp", 1, null) over window)
.withColumn("next_value", lead("value", 1, null) over window)
.withColumn("next_timestamp", lead("timestamp", 1, null) over window)
.withColumn("value",
when(
$"previous_value".isNotNull and
// If there is more than 5 sec. difference, it shouldn't be joined
$"timestamp" - $"previous_timestamp" < 5 and
(
$"next_timestamp".isNull or
$"next_timestamp" - $"timestamp" > $"timestamp" - $"previous_timestamp"
), $"previous_value")
.otherwise(
when($"next_timestamp" - $"timestamp" < 5, $"next_value")
.otherwise(null)
)
)
.filter($"action" === "click")
.drop("previous_value")
.drop("previous_timestamp")
.drop("next_value")
.drop("next_timestamp")
Но я чувствую, что это довольно неэффективно. Есть лучший способ сделать это ? (что-то, что можно сделать, не создавая 4 временных столбца ...) Можно ли, например, манипулировать строкой со смещением -1 и +1 в одном и том же выражении?
Заранее спасибо!