Kullayappa  M
Kullayappa M

Reputation: 174

Comparing two dataframes in Spark

I'm comparing two dataframes in spark using except().

For exmaple: df.except(df2)

I will get all the records that are not available in df2 from df. However, I would like to list field details also which are not matching.

For example:

df:
------------------
id,name,age,city
101,kp,28,CHN
------------------

df2:
-----------------
id,name,age,city
101,kp,28,HYD
----------------

Expected output:

df3
--------------------------
id,name,age,city,diff
101,kp,28,CHN,City is not matching
--------------------------------

How can I acheive this?

Upvotes: 1

Views: 9197

Answers (2)

Ged
Ged

Reputation: 18013

Newer again attempt on the above but not possible elegantly, but with JOIN as opposed to except. Best I can do.

I believe it does what you need and takes into the fact there are things in one data set or not.

Run under Databricks.

case class Person(personid: Int, personname: String, cityid: Int)
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.functions._

val df1 = Seq(
     Person(0, "AgataZ", 0),
     Person(1, "Iweta", 0),
     Person(2, "Patryk", 2),
     Person(9999, "Maria", 2),
     Person(5, "John", 2),
     Person(6, "Patsy", 2),
     Person(7, "Gloria", 222), 
     Person(3333, "Maksym", 0)).toDF

val df2 = Seq(
     Person(0, "Agata", 0),
     Person(1, "Iweta", 0),
     Person(2, "Patryk", 2),
     Person(5, "John", 2),
     Person(6, "Patsy", 333),
     Person(7, "Gloria", 2), 
     Person(4444, "Hans", 3)).toDF

val joined = df1.join(df2, df1("personid") === df2("personid"), "outer") 
val newNames = Seq("personId1", "personName1", "personCity1", "personId2", "personName2", "personCity2")
val df_Renamed = joined.toDF(newNames: _*)

// Some deliberate variation shown in approach for learning 
val df_temp = df_Renamed.filter($"personCity1" =!= $"personCity2" || $"personName1" =!= $"personName2" || $"personName1".isNull || $"personName2".isNull || $"personCity1".isNull || $"personCity2".isNull).select($"personId1", $"personName1".alias("Name"), $"personCity1", $"personId2", $"personName2".alias("Name2"), $"personCity2").  withColumn("PersonID", when($"personId1".isNotNull, $"personId1").otherwise($"personId2"))

val df_final = df_temp.withColumn("nameChange ?", when($"Name".isNull or $"Name2".isNull or $"Name" =!= $"Name2", "Yes").otherwise("No")).withColumn("cityChange ?", when($"personCity1".isNull or $"personCity2".isNull or $"personCity1" =!= $"personCity2", "Yes").otherwise("No")).drop("PersonId1").drop("PersonId2")

df_final.show()

gives:

+------+-----------+------+-----------+--------+------------+------------+
|  Name|personCity1| Name2|personCity2|PersonID|nameChange ?|cityChange ?|
+------+-----------+------+-----------+--------+------------+------------+
| Patsy|          2| Patsy|        333|       6|          No|         Yes|
|Maksym|          0|  null|       null|    3333|         Yes|         Yes|
|  null|       null|  Hans|          3|    4444|         Yes|         Yes|
|Gloria|        222|Gloria|          2|       7|          No|         Yes|
| Maria|          2|  null|       null|    9999|         Yes|         Yes|
|AgataZ|          0| Agata|          0|       0|         Yes|          No|
+------+-----------+------+-----------+--------+------------+------------+

Upvotes: 1

vaquar khan
vaquar khan

Reputation: 11449

Use intersect to get the values common to both DataFrames,then build your not matching logic

intersect -returns a new Dataset containing rows only in both this Dataset and another Dataset.

df.intersect(df2)
  • return a new RDD that contains the intersection of elements in the source dataset and the argument.

  • intersection(anotherrdd) returns the elements which are present in both the DF.

  • intersection(anotherrdd) remove all the duplicate including duplicated in single DF

Upvotes: 3

Related Questions