Spark (scala) dataframes - Check whether strings in column contain any items from a set

Viewed 11697

I'm pretty new to scala and spark and I've been trying to find a solution for this issue all day - it's doing my head in. I've tried 20 different variations of the following code and keep getting type mismatch errors when I try to perform calculations on a column.

I have a spark dataframe, and I wish to check whether each string in a particular column contains any number of words from a pre-defined List (or Set) of words.

Here is some example data for replication:

// sample data frame
val df = Seq(
      (1, "foo"),
      (2, "barrio"),
      (3, "gitten"),
      (4, "baa")).toDF("id", "words")

// dictionary Set of words to check 
val dict = Set("foo","bar","baaad")

Now, i am trying to create a third column with the results of a comparison to see if the strings in the $"words" column within them contain any of the words in the dict Set of words. So the result should be:

+---+-----------+-------------+
| id|      words|   word_check| 
+---+-----------+-------------+
|  1|        foo|         true|     
|  2|      bario|         true|
|  3|     gitten|        false|
|  4|        baa|        false|
+---+-----------+-------------+

First, I tried to see if i could do it natively without using UDFs, since the dict Set will actually be a large dictionary of > 40K words, and as I understand it this would be more efficient than a UDF:

df.withColumn("word_check", dict.exists(d => $"words".contains(d)))

But i get the error:

type mismatch;
found   : org.apache.spark.sql.Column
required: Boolean

I have also tried to create a UDF to do this (using both mutable.Set and mutable.WrappedArray to describe the Set - not sure which is correct but neither work):

val checker: ((String, scala.collection.mutable.Set[String]) => Boolean) = (col: String, array: scala.collection.mutable.Set[String] ) =>  array.exists(d => col.contains(d))

val udf1 = udf(checker)

df.withColumn("word_check", udf1($"words", dict )).show()

But get another type mismatch:

 found   : scala.collection.immutable.Set[String]
 required: org.apache.spark.sql.Column

If the set was a fixed number, I should be able to use Lit(Int) in the expression? But I don't really understand performing more complex functions on a column by mixing different data types works in scala.

Any help greatly appreciated, especially if it can be done efficiently (it is a large df of > 5m rows).

3 Answers
Related