[sql] Concatenate columns in Apache Spark DataFrame

How do we concatenate two columns in an Apache Spark DataFrame? Is there any function in Spark SQL which we can use?

This question is related to sql apache-spark dataframe apache-spark-sql

The answer is


With raw SQL you can use CONCAT:

  • In Python

    df = sqlContext.createDataFrame([("foo", 1), ("bar", 2)], ("k", "v"))
    df.registerTempTable("df")
    sqlContext.sql("SELECT CONCAT(k, ' ',  v) FROM df")
    
  • In Scala

    import sqlContext.implicits._
    
    val df = sc.parallelize(Seq(("foo", 1), ("bar", 2))).toDF("k", "v")
    df.registerTempTable("df")
    sqlContext.sql("SELECT CONCAT(k, ' ',  v) FROM df")
    

Since Spark 1.5.0 you can use concat function with DataFrame API:

  • In Python :

    from pyspark.sql.functions import concat, col, lit
    
    df.select(concat(col("k"), lit(" "), col("v")))
    
  • In Scala :

    import org.apache.spark.sql.functions.{concat, lit}
    
    df.select(concat($"k", lit(" "), $"v"))
    

There is also concat_ws function which takes a string separator as the first argument.


Here's how you can do custom naming

import pyspark
from pyspark.sql import functions as sf
sc = pyspark.SparkContext()
sqlc = pyspark.SQLContext(sc)
df = sqlc.createDataFrame([('row11','row12'), ('row21','row22')], ['colname1', 'colname2'])
df.show()

gives,

+--------+--------+
|colname1|colname2|
+--------+--------+
|   row11|   row12|
|   row21|   row22|
+--------+--------+

create new column by concatenating:

df = df.withColumn('joined_column', 
                    sf.concat(sf.col('colname1'),sf.lit('_'), sf.col('colname2')))
df.show()

+--------+--------+-------------+
|colname1|colname2|joined_column|
+--------+--------+-------------+
|   row11|   row12|  row11_row12|
|   row21|   row22|  row21_row22|
+--------+--------+-------------+

One option to concatenate string columns in Spark Scala is using concat.

It is necessary to check for null values. Because if one of the columns is null, the result will be null even if one of the other columns do have information.

Using concat and withColumn:

val newDf =
  df.withColumn(
    "NEW_COLUMN",
    concat(
      when(col("COL1").isNotNull, col("COL1")).otherwise(lit("null")),
      when(col("COL2").isNotNull, col("COL2")).otherwise(lit("null"))))

Using concat and select:

val newDf = df.selectExpr("concat(nvl(COL1, ''), nvl(COL2, '')) as NEW_COLUMN")

With both approaches you will have a NEW_COLUMN which value is a concatenation of the columns: COL1 and COL2 from your original df.


If you want to do it using DF, you could use a udf to add a new column based on existing columns.

val sqlContext = new SQLContext(sc)
case class MyDf(col1: String, col2: String)

//here is our dataframe
val df = sqlContext.createDataFrame(sc.parallelize(
    Array(MyDf("A", "B"), MyDf("C", "D"), MyDf("E", "F"))
))

//Define a udf to concatenate two passed in string values
val getConcatenated = udf( (first: String, second: String) => { first + " " + second } )

//use withColumn method to add a new column called newColName
df.withColumn("newColName", getConcatenated($"col1", $"col2")).select("newColName", "col1", "col2").show()

From Spark 2.3(SPARK-22771) Spark SQL supports the concatenation operator ||.

For example;

val df = spark.sql("select _c1 || _c2 as concat_column from <table_name>")

concat(*cols)

v1.5 and higher

Concatenates multiple input columns together into a single column. The function works with strings, binary and compatible array columns.

Eg: new_df = df.select(concat(df.a, df.b, df.c))


concat_ws(sep, *cols)

v1.5 and higher

Similar to concat but uses the specified separator.

Eg: new_df = df.select(concat_ws('-', df.col1, df.col2))


map_concat(*cols)

v2.4 and higher

Used to concat maps, returns the union of all the given maps.

Eg: new_df = df.select(map_concat("map1", "map2"))


Using string concat operator (||):

v2.3 and higher

Eg: df = spark.sql("select col_a || col_b || col_c as abc from table_x")

Reference: Spark sql doc


Here is another way of doing this for pyspark:

#import concat and lit functions from pyspark.sql.functions 
from pyspark.sql.functions import concat, lit

#Create your data frame
countryDF = sqlContext.createDataFrame([('Ethiopia',), ('Kenya',), ('Uganda',), ('Rwanda',)], ['East Africa'])

#Use select, concat, and lit functions to do the concatenation
personDF = countryDF.select(concat(countryDF['East Africa'], lit('n')).alias('East African'))

#Show the new data frame
personDF.show()

----------RESULT-------------------------

84
+------------+
|East African|
+------------+
|   Ethiopian|
|      Kenyan|
|     Ugandan|
|     Rwandan|
+------------+

Here is a suggestion for when you don't know the number or name of the columns in the Dataframe.

val dfResults = dfSource.select(concat_ws(",",dfSource.columns.map(c => col(c)): _*))

In Spark 2.3.0, you may do:

spark.sql( """ select '1' || column_a from table_a """)

Do we have java syntax corresponding to below process

val dfResults = dfSource.select(concat_ws(",",dfSource.columns.map(c => col(c)): _*))

In Java you can do this to concatenate multiple columns. The sample code is to provide you a scenario and how to use it for better understanding.

SparkSession spark = JavaSparkSessionSingleton.getInstance(rdd.context().getConf());
Dataset<Row> reducedInventory = spark.sql("select * from table_name")
                        .withColumn("concatenatedCol",
                                concat(col("col1"), lit("_"), col("col2"), lit("_"), col("col3")));


class JavaSparkSessionSingleton {
    private static transient SparkSession instance = null;

    public static SparkSession getInstance(SparkConf sparkConf) {
        if (instance == null) {
            instance = SparkSession.builder().config(sparkConf)
                    .getOrCreate();
        }
        return instance;
    }
}

The above code concatenated col1,col2,col3 seperated by "_" to create a column with name "concatenatedCol".


In my case, I wanted a Tab delimited row.

from pyspark.sql import functions as F
df.select(F.concat_ws('|','_c1','_c2','_c3','_c4')).show()

This worked well like a hot knife over butter.


We can simple use SelectExpr as well.

df1.selectExpr("*","upper(_2||_3) as new")


Another way to do it in pySpark using sqlContext...

#Suppose we have a dataframe:
df = sqlContext.createDataFrame([('row1_1','row1_2')], ['colname1', 'colname2'])

# Now we can concatenate columns and assign the new column a name 
df = df.select(concat(df.colname1, df.colname2).alias('joined_colname'))

Indeed, there are some beautiful inbuilt abstractions for you to accomplish your concatenation without the need to implement a custom function. Since you mentioned Spark SQL, so I am guessing you are trying to pass it as a declarative command through spark.sql(). If so, you can accomplish in a straight forward manner passing SQL command like: SELECT CONCAT(col1, '<delimiter>', col2, ...) AS concat_column_name FROM <table_name>;

Also, from Spark 2.3.0, you can use commands in lines with: SELECT col1 || col2 AS concat_column_name FROM <table_name>;

Wherein, is your preferred delimiter (can be empty space as well) and is the temporary or permanent table you are trying to read from.


val newDf =
  df.withColumn(
    "NEW_COLUMN",
    concat(
      when(col("COL1").isNotNull, col("COL1")).otherwise(lit("null")),
      when(col("COL2").isNotNull, col("COL2")).otherwise(lit("null"))))

Note: For this code to work you need to put the parentheses "()" in the "isNotNull" function. -> The correct one is "isNotNull()".

val newDf =
  df.withColumn(
    "NEW_COLUMN",
    concat(
      when(col("COL1").isNotNull(), col("COL1")).otherwise(lit("null")),
      when(col("COL2").isNotNull(), col("COL2")).otherwise(lit("null"))))

Questions with sql tag:

Passing multiple values for same variable in stored procedure SQL permissions for roles Generic XSLT Search and Replace template Access And/Or exclusions Pyspark: Filter dataframe based on multiple conditions Subtracting 1 day from a timestamp date PYODBC--Data source name not found and no default driver specified select rows in sql with latest date for each ID repeated multiple times ALTER TABLE DROP COLUMN failed because one or more objects access this column Create Local SQL Server database Export result set on Dbeaver to CSV How to create temp table using Create statement in SQL Server? SQL Query Where Date = Today Minus 7 Days How do I pass a list as a parameter in a stored procedure? #1273 – Unknown collation: ‘utf8mb4_unicode_520_ci’ MySQL Error: : 'Access denied for user 'root'@'localhost' SQL Server IF EXISTS THEN 1 ELSE 2 How to add a boolean datatype column to an existing table in sql? Presto SQL - Converting a date string to date format What is the meaning of <> in mysql query? Change Date Format(DD/MM/YYYY) in SQL SELECT Statement Convert timestamp to date in Oracle SQL #1292 - Incorrect date value: '0000-00-00' Postgresql tables exists, but getting "relation does not exist" when querying SQL query to check if a name begins and ends with a vowel Find the number of employees in each department - SQL Oracle Error in MySQL when setting default value for DATE or DATETIME Drop view if exists Could not find server 'server name' in sys.servers. SQL Server 2014 How to create a Date in SQL Server given the Day, Month and Year as Integers TypeError: tuple indices must be integers, not str Select Rows with id having even number SELECT list is not in GROUP BY clause and contains nonaggregated column IN vs ANY operator in PostgreSQL How to insert date values into table Error related to only_full_group_by when executing a query in MySql How to select the first row of each group? Connecting to Microsoft SQL server using Python eloquent laravel: How to get a row count from a ->get() How to execute raw queries with Laravel 5.1? In Oracle SQL: How do you insert the current date + time into a table? Extract number from string with Oracle function Rebuild all indexes in a Database SQL: Two select statements in one query DB2 SQL error sqlcode=-104 sqlstate=42601 What difference between the DATE, TIME, DATETIME, and TIMESTAMP Types How to run .sql file in Oracle SQL developer tool to import database? Concatenate columns in Apache Spark DataFrame How Stuff and 'For Xml Path' work in SQL Server? Fatal error: Call to a member function query() on null

Questions with apache-spark tag:

Select Specific Columns from Spark DataFrame Select columns in PySpark dataframe What is the difference between spark.sql.shuffle.partitions and spark.default.parallelism? How to find count of Null and Nan values for each column in a PySpark dataframe efficiently? Spark dataframe: collect () vs select () How does createOrReplaceTempView work in Spark? Spark difference between reduceByKey vs groupByKey vs aggregateByKey vs combineByKey Filter df when values matches part of a string in pyspark Filtering a pyspark dataframe using isin by exclusion Convert date from String to Date format in Dataframes Joining Spark dataframes on the key PySpark: withColumn() with two conditions and three outcomes Provide schema while reading csv file as a dataframe how to filter out a null value from spark dataframe Spark RDD to DataFrame python Split Spark Dataframe string column into multiple columns Fetching distinct values on a column using Spark DataFrame Spark - SELECT WHERE or filtering? Convert spark DataFrame column to python list How to check Spark Version Convert pyspark string to date format Spark - Error "A master URL must be set in your configuration" when submitting an app PySpark: multiple conditions in when clause How to import multiple csv files in a single load? Converting Pandas dataframe into Spark dataframe error Concatenate two PySpark dataframes Filter Pyspark dataframe column with None value Add jars to a Spark Job - spark-submit Pyspark replace strings in Spark dataframe column How to sum the values of one column of a dataframe in spark/scala How to create a DataFrame from a text file in Spark how to loop through each row of dataFrame in pyspark multiple conditions for filter in spark data frames Filter spark DataFrame on string contains java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries. spark Eclipse on windows 7 Renaming column names of a DataFrame in Spark Scala get specific row from spark dataframe Spark: Add column to dataframe conditionally Spark DataFrame groupBy and sort in the descending order (pyspark) Is there a way to take the first 1000 rows of a Spark Dataframe? How to change dataframe column names in pyspark? Spark SQL: apply aggregate functions to a list of columns How to select the first row of each group? Spark Dataframe distinguish columns with duplicated name How to join on multiple columns in Pyspark? How to show full column content in a Spark Dataframe? How do I add a new column to a Spark DataFrame (using PySpark)? Best way to get the max value in a Spark dataframe column How to save a spark DataFrame as csv on disk? How to add a constant column in a Spark DataFrame?

Questions with dataframe tag:

Trying to merge 2 dataframes but get ValueError How to show all of columns name on pandas dataframe? Python Pandas - Find difference between two data frames Pandas get the most frequent values of a column Display all dataframe columns in a Jupyter Python Notebook How to convert column with string type to int form in pyspark data frame? Display/Print one column from a DataFrame of Series in Pandas Binning column with python pandas Selection with .loc in python Set value to an entire column of a pandas dataframe Pandas create empty DataFrame with only column names Python: pandas merge multiple dataframes Spark dataframe: collect () vs select () 'DataFrame' object has no attribute 'sort' Remove Unnamed columns in pandas dataframe Convert float64 column to int64 in Pandas Python Pandas iterate over rows and access column names Display rows with one or more NaN values in pandas dataframe ValueError: Length of values does not match length of index | Pandas DataFrame.unique() Convert List to Pandas Dataframe Column Pandas Split Dataframe into two Dataframes at a specific row Pandas dataframe groupby plot Removing space from dataframe columns in pandas Get total of Pandas column Python - How to convert JSON File to Dataframe Strip / trim all strings of a dataframe Merge two dataframes by index pandas how to check dtype for all columns in a dataframe? Joining Spark dataframes on the key Provide schema while reading csv file as a dataframe Pandas group-by and sum PySpark 2.0 The size or shape of a DataFrame How to concatenate multiple column values into a single column in Panda dataframe Convert Pandas DataFrame to JSON format pandas dataframe convert column type to string or categorical How to add multiple columns to pandas dataframe in one assignment? Fetching distinct values on a column using Spark DataFrame How to Add Incremental Numbers to a New Column Using Pandas Pandas KeyError: value not in index How to split data into 3 sets (train, validation and test)? Split / Explode a column of dictionaries into separate columns with pandas Group dataframe and get sum AND count? Save Dataframe to csv directly to s3 Python Pandas dataframe fillna() only some columns in place how to sort pandas dataframe from one column PySpark: multiple conditions in when clause What is dtype('O'), in pandas? Filter Pyspark dataframe column with None value Truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all() How to create a DataFrame from a text file in Spark

Questions with apache-spark-sql tag:

Select Specific Columns from Spark DataFrame Pyspark: Filter dataframe based on multiple conditions Select columns in PySpark dataframe What is the difference between spark.sql.shuffle.partitions and spark.default.parallelism? How to find count of Null and Nan values for each column in a PySpark dataframe efficiently? Spark dataframe: collect () vs select () How does createOrReplaceTempView work in Spark? Filter df when values matches part of a string in pyspark Convert date from String to Date format in Dataframes Take n rows from a spark dataframe and pass to toPandas() Joining Spark dataframes on the key PySpark: withColumn() with two conditions and three outcomes Provide schema while reading csv file as a dataframe how to filter out a null value from spark dataframe Split Spark Dataframe string column into multiple columns Fetching distinct values on a column using Spark DataFrame Spark - SELECT WHERE or filtering? Convert pyspark string to date format PySpark: multiple conditions in when clause How to import multiple csv files in a single load? Filter Pyspark dataframe column with None value How to create a DataFrame from a text file in Spark how to loop through each row of dataFrame in pyspark Join two data frames, select all columns from one and some columns from the other multiple conditions for filter in spark data frames Filter spark DataFrame on string contains Renaming column names of a DataFrame in Spark Scala get specific row from spark dataframe Spark: Add column to dataframe conditionally Spark DataFrame groupBy and sort in the descending order (pyspark) Spark SQL: apply aggregate functions to a list of columns How to select the first row of each group? Spark Dataframe distinguish columns with duplicated name How to join on multiple columns in Pyspark? How do I add a new column to a Spark DataFrame (using PySpark)? Best way to get the max value in a Spark dataframe column How to save a spark DataFrame as csv on disk? How to add a constant column in a Spark DataFrame? How to check if spark dataframe is empty? How to change a dataframe column from String type to Double type in PySpark? dataframe: how to groupBy/count then filter on count in Scala Extract column values of Dataframe as List in Apache Spark Filtering a spark dataframe based on date How to export data from Spark SQL to CSV Difference between DataFrame, Dataset, and RDD in Spark How to create an empty DataFrame with a specified schema? Concatenate columns in Apache Spark DataFrame How to export a table dataframe in PySpark to csv? How do I check for equality using Spark Dataframe without SQL Query? Spark specify multiple column conditions for dataframe join