Using Faker with PySpark Dataframe to Anonymise Data

Viewed 1842

I am trying to change a few columns in my Spark DataFrame, I have a few columns like :

  • First Name
  • Last Name
  • Email

I want to anonymise this and generate meaningful values for which am using Faker.
But if i use

df.withColumn('FirstName', lit(fake.first_name()))

It adds the same name for all rows , something like : enter image description here

As you can see it has the same value for each first name, ideally i would like to have different faker value and not a constant. How would I achieve this ?

Update 1 :

I looked at Steven's suggestion and here is my updated code

import pyspark.sql.functions as sf
from faker import Faker
from pyspark.sql import functions as F


MSG_FORMAT = '%(asctime)s %(levelname)s %(name)s: %(message)s'
DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
logging.basicConfig(format=MSG_FORMAT, datefmt=DATETIME_FORMAT)
logger = logging.getLogger("[SFDC-GLUE-LOG]")
fake = Faker()
source_df = spark.read.format("jdbc").option("url",connection_url).option("query",query).option("driver", driver_name).option("user", user_name).option("password", password).option("StmtCallLimit",0).load()
         


fake_firstname = F.udf(fake.first_name)
        
masked_df=source_df.withColumn("FirstName", fake_firstname())

Now i Get

Traceback (most recent call last):
  File "script_2020-08-05-17-15-26.py", line 52, in <module>
    masked_df=source_df.withColumn("FirstName", fake_firstname())
  File "/mnt/yarn/usercache/root/appcache/application_1596647211940_0002/container_1596647211940_0002_01_000001/pyspark.zip/pyspark/sql/udf.py", line 189, in wrapper
    return self(*args)
  File "/mnt/yarn/usercache/root/appcache/application_1596647211940_0002/container_1596647211940_0002_01_000001/pyspark.zip/pyspark/sql/udf.py", line 167, in __call__
    judf = self._judf
  File "/mnt/yarn/usercache/root/appcache/application_1596647211940_0002/container_1596647211940_0002_01_000001/pyspark.zip/pyspark/sql/udf.py", line 151, in _judf
    self._judf_placeholder = self._create_judf()
  File "/mnt/yarn/usercache/root/appcache/application_1596647211940_0002/container_1596647211940_0002_01_000001/pyspark.zip/pyspark/sql/udf.py", line 160, in _create_judf
    wrapped_func = _wrap_function(sc, self.func, self.returnType)
  File "/mnt/yarn/usercache/root/appcache/application_1596647211940_0002/container_1596647211940_0002_01_000001/pyspark.zip/pyspark/sql/udf.py", line 35, in _wrap_function
    pickled_command, broadcast_vars, env, includes = _prepare_for_python_RDD(sc, command)
  File "/mnt/yarn/usercache/root/appcache/application_1596647211940_0002/container_1596647211940_0002_01_000001/pyspark.zip/pyspark/rdd.py", line 2420, in _prepare_for_python_RDD
    pickled_command = ser.dumps(command)
  File "/mnt/yarn/usercache/root/appcache/application_1596647211940_0002/container_1596647211940_0002_01_000001/pyspark.zip/pyspark/serializers.py", line 600, in dumps
    raise pickle.PicklingError(msg)
_pickle.PicklingError: Could not serialize object: TypeError: can't pickle weakref objects
2 Answers

you need to use an UDF for that :

from pyspark.sql import functions as F

fake_firstname = F.udf(fake.first_name)

df.withColumn("FirstName", fake_firstname())

I had the same problem, follow the solution that worked for me.

from pyspark.sql.functions import udf
from pyspark.sql.types import StringType
from faker import Factory

def fake_name():
    faker = Factory.create()
    return faker.name()

fake_name_udf = udf(fake_name, StringType())
df = df.withColumn('name', fake_name_udf())
Related