#scala #dataframe #apache-spark #apache-spark-sql
Вопрос:
У меня есть этот фрейм данных :
----- ---------- ---------
|num |Timestamp |frequency|
----- ---------- ---------
|20.0 |1632899456|4 |
|20.0 |1632901256|4 |
|20.0 |1632901796|4 |
|20.0 |1632899155|4 |
|10.0 |1632901743|2 |
|10.0 |1632899933|2 |
|91.0 |1632899756|3 |
|32.0 |1632900776|6 |
|41.0 |1632900176|1 |
----- ---------- ---------
Я хочу отфильтровать его, используя содержимое этой карты :
val filter : Map[String, Seq[String]] = Map("num"-> Seq("20.0", "41.0"), "frequency" -> Seq("6"))
Новый фрейм данных будет выглядеть следующим образом :
----- ---------- ---------
|num |Timestamp |frequency|
----- ---------- ---------
|20.0 |1632899456|4 |
|20.0 |1632901256|4 |
|20.0 |1632901796|4 |
|20.0 |1632899155|4 |
|32.0 |1632900776|6 |
|41.0 |1632900176|1 |
----- ---------- ---------
Я использую Spark версии 3.0.2 и SQLContext с языком scala.
Комментарии:
1. Ваш вопрос не ясен. Я думаю, вы хотите отфильтровать записи по предикатам (число 20,0 или 41,0) или (частота 6), верно?
2. Да, это будут предикаты : (число равно 20,0 или 41,0) или (частота равна 6)
3. Если ваши предикаты исправлены, очень прямой путь
df.filter($ "num" === "20.0" || $"num" === "41.0" || $"frequency" === "6")
Ответ №1:
Вы можете использовать фильтр с isin
функцией
val filter: Map[String, Seq[String]] = Map("num" -> Seq("20.0", "41.0"), "frequency" -> Seq("6"))
df.filter(($"num" isin (filter("num"):_*)) or
($"frequency" isin (filter("frequency"):_*)))
.show(false)
Если у вас есть карта, которая соответствует названию столбца, вы можете использовать
val filterQuery = filter.map(rec => col(rec._1) isin(rec._2:_*)).reduce(_ or _)
df.filter(filterQuery).show(false)
Выход:
---- ---------- ---------
|num |Timestamp |frequency|
---- ---------- ---------
|20.0|1632899456|4 |
|20.0|1632901256|4 |
|20.0|1632901796|4 |
|20.0|1632899155|4 |
|32.0|1632900776|6 |
|41.0|1632900176|1 |
---- ---------- ---------
Комментарии:
1. Большое спасибо за ваш ответ. Есть ли какой-нибудь способ перебирать ключи карты вместо того, чтобы вызывать их по одному ?
2. если имя столбца и ключ карты совпадают, вы можете выполнить итерацию
Ответ №2:
Вы можете построить строковый запрос с картой в качестве источника следующим образом:
val filterQuery = filter
.map{case (k,v) => v.map(v1 => (k,v1))}
.flatten
.map{ case (k,v) => s"$k = $v" }
.mkString(" or ")
df.filter(filterQuery)
Однако это не элегантно