Проблема с вашим foldLeft
приложением заключается в том, что оно не эквивалентно выражению, которое вы хотите использовать.
Как вы уже сказали, вы ищете
sha2(b, 256) = b_hash OR sha2(c, 256) = c_hash OR sha2(d, 256) = d_hash
, тогда как цепочечный фильтр на DataFrame
приводит к
sha2(b, 256) = b_hash AND sha2(c, 256) = c_hash AND sha2(d, 256) = d_hash
Для достижения первого вам нужно заменить аккумулятор:
import org.apache.spark.sql.functions.{col, lit}
import org.apache.spark.sql.Column
val atLeastOneMatch: Column = map.foldLeft(lit(false)) {
case (acc, (c, h)) => acc or (sha2(col(c), 256) === h)
}
, а затем использовать результат для фильтрации данных
df.filter(atLeastOneMatch).count
Это будет считать все строки , где хотя бы один столбец соответствует хешу , предоставленному map
. По законам де Моргана его отрицание
!atLeastOneMatch
будет эквивалентно
sha2(b, 256) != b_hash AND sha2(c, 256) != c_hash AND sha2(d, 256) = d_hash
Другими словами, он будет соответствовать случаям, когда ни одно из значений не соответствует соответствующему хешу.
Если вы хотите найти строки, в которых хотя бы одно значение не соответствует хешу , вам следует использовать
sha2(b, 256) != b_hash OR sha2(c, 256) != c_hash OR sha2(d, 256) != d_hash
, который может быть составлен, как показано ниже
val atLeastOneMismatch: Column = map.foldLeft(lit(false)) {
case (acc, (c, h)) => acc or (sha2(col(c), 256) =!= h)
}
Это отрицание
!atLeastOneMismatch
эквивалентно (законы де Моргана еще раз)
sha2(b, 256) = b_hash AND sha2(c, 256) = c_hash AND sha2(d, 256) = d_hash
и далее эквивалентно foldLeft
с DataFrame
аккумулятором и ===
.
Итак, подведем итог - если C
является набором столбцов, то:
- ∈c∈C map (c) = sha2 (c, 256) -
atLeastOneMatch
- ∈c∈C map (c)! = Sha2 (c, 256) -
!atLeastOneMatch
- ∈c∈C map (c)! = Sha2 (c, 256) -
atLeastOneMismatch
- ∈c∈C map (c) = sha2 (c, 256) -
!atLeastOneMismatch