Introduction
Spark SQL provides built-in standard map functions defined in the DataFrame API, which come in handy when you need to perform operations on map (MapType) columns. All these functions accept input as a map column and several other arguments based on the functions.
Spark SQL map functions are grouped as “collection_funcs” in Spark SQL along with several array functions. These map functions are useful when you want to concatenate two or more map columns, convert arrays of StructType entries to a map column, etc.
| Function | Description | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | map_keys | Returns an array containing the keys of the map. | | map_values | Returns an array containing the values of the map. | | map_concat | Merges maps specified in the arguments. | | map_from_entries | Returns a map from the given array of StructType entries. | | map_entries | Returns an array of all StructType in the given map. | | explode() | Creates a new row for every key-value pair in the map by ignoring null & empty values. It creates two new columns, one for key and one for value. | | explode_outer() | Creates a new row for every key-value pair in the map, including null & empty values. It creates two new columns, one for key and one for value. | | posexplode() | Creates a new row for each key-value pair in a map by ignoring null & empty values. It also creates 3 columns: “pos” to hold the position of the map element, and “key” and “value” columns for every row. | | posexplode_outer() | Creates a new row for each key-value pair in a map, including null & empty values. It also creates 3 columns: “pos” to hold the position of the map element, and “key” and “value” columns for every row. | | transform_keys() | Transforms a map by applying functions to every key-value pair and returns a transformed map. | | transform_value() | Transforms a map by applying functions to every key-value pair and returns a transformed map. | | map_zip_with() | Merges two maps into a single map. | | element_at() | Returns a value of a key in a map. | | size() | Returns the length of a map column. |
Example: Using map_keys and map_values
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.functions;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
import static org.apache.spark.sql.functions.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class SparkMapFunctions {
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.appName("Java Spark SQL Map Functions")
.config("spark.master", "local")
.getOrCreate();
List<Row> data = Arrays.asList(
RowFactory.create(1, Map.of("key1", "value1", "key2", "value2")),
RowFactory.create(2, Map.of("key3", "value3", "key4", "value4"))
);
StructType schema = new StructType(new StructField[]{
DataTypes.createStructField("id", DataTypes.IntegerType, false),
DataTypes.createStructField("map", DataTypes.createMapType(DataTypes.StringType, DataTypes.StringType), false)
});
Dataset<Row> df = spark.createDataFrame(data, schema);
df.select(col("id"), map_keys(col("map")).as("keys"), map_values(col("map")).as("values")).show(false);
}
}
+---+----------+----------+
|id |keys |values |
+---+----------+----------+
|1 |[key1,key2]|[value1,value2]|
|2 |[key3,key4]|[value3,value4]|
+---+----------+----------+
Example: Using map_concat
import org.apache.spark.sql.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static org.apache.spark.sql.functions.*;
public class SparkMapConcat {
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.appName("Java Spark SQL Map Concat")
.config("spark.master", "local")
.getOrCreate();
List<Row> data1 = Arrays.asList(
RowFactory.create(1, Map.of("key1", "value1")),
RowFactory.create(2, Map.of("key2", "value2"))
);
List<Row> data2 = Arrays.asList(
RowFactory.create(1, Map.of("key3", "value3")),
RowFactory.create(2, Map.of("key4", "value4"))
);
StructType schema = new StructType(new StructField[]{
DataTypes.createStructField("id", DataTypes.IntegerType, false),
DataTypes.createStructField("map", DataTypes.createMapType(DataTypes.StringType, DataTypes.StringType), false)
});
Dataset<Row> df1 = spark.createDataFrame(data1, schema);
Dataset<Row> df2 = spark.createDataFrame(data2, schema);
Dataset<Row> df = df1.join(df2, "id");
df.withColumn("map_concat", map_concat(col("map"), df2.col("map"))).show(false);
}
}
+---+----------+----------+-------------------------+
|id |map1 |map2 |map_concat |
+---+----------+----------+-------------------------+
|1 |[key1 -> value1]|[key3 -> value3]|[key1 -> value1, key3 -> value3]|
|2 |[key2 -> value2]|[key4 -> value4]|[key2 -> value2, key4 -> value4]|
+---+----------+----------+-------------------------+
Example: Using map_from_entries
import org.apache.spark.sql.*;
import java.util.Arrays;
import java.util.List;
import static org.apache.spark.sql.functions.*;
public class SparkMapFromEntries {
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.appName("Java Spark SQL Map From Entries")
.config("spark.master", "local")
.getOrCreate();
List<Row> data = Arrays.asList(
RowFactory.create(1, new Tuple2[]{new Tuple2<>("key1", "value1"), new Tuple2<>("key2", "value2")}),
RowFactory.create(2, new Tuple2[]{new Tuple2<>("key3", "value3"), new Tuple2<>("key4", "value4")})
);
StructType schema = new StructType(new StructField[]{
DataTypes.createStructField("id", DataTypes.IntegerType, false),
DataTypes.createStructField("entries", DataTypes.createArrayType(DataTypes.createStructType(new StructField[]{
DataTypes.createStructField("_1", DataTypes.StringType, false),
DataTypes.createStructField("_2", DataTypes.StringType, false)
})), false)
});
Dataset<Row> df = spark.createDataFrame(data, schema);
df.withColumn("map", map_from_entries(col("entries"))).show(false);
}
}
+---+------------------------+-------------------------+
|id |entries |map |
+---+------------------------+-------------------------+
|1 |[[key1,value1],[key2,value2]]|[key1 -> value1, key2 -> value2]|
|2 |[[key3,value3],[key4,value4]]|[key3 -> value3, key4 -> value4]|
+---+------------------------+-------------------------+
Example: Using posexplode
import org.apache.spark.sql.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static org.apache.spark.sql.functions.*;
public class SparkPosExplode {
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.appName("Java Spark SQL PosExplode")
.config("spark.master", "local")
.getOrCreate();
List<Row> data = Arrays.asList(
RowFactory.create(1, Map.of("key1", "value1", "key2", "value2")),
RowFactory.create(2, Map.of("key3", "value3", "key4", "value4"))
);
StructType schema = new StructType(new StructField[]{
DataTypes.createStructField("id", DataTypes.IntegerType, false),
DataTypes.createStructField("map", DataTypes.createMapType(DataTypes.StringType, DataTypes.StringType), false)
});
Dataset<Row> df = spark.createDataFrame(data, schema);
df.select(col("id"), posexplode(col("map"))).show(false);
}
}
+---+---+----+------+
|id |pos|key |value |
+---+---+----+------+
|1 |0 |key1|value1|
|1 |1 |key2|value2|
|2 |0 |key3|value3|
|2 |1 |key4|value4|
+---+---+----+------+
