Я хочу упорядочить по времени некоторые авро-файлы, которые я получаю из HDFS.
Схема моих файлов avro:
Заголовки: Map [String, String], тело: String
Сложность в том, что отметка времени является одной из ключа / значения на карте. Итак, у меня есть временная метка на карте:
ключ_1 -> значение_1, ключ_2 -> значение_2, отметка времени -> 1234567, ключ_n -> значение_n
Обратите внимание, что тип значений - String.
Я создал класс case для создания набора данных с этой схемой:
case class Root(headers : Map[String,String], body: String)
Создание моего набора данных:
val ds = spark
.read
.format("com.databricks.spark.avro")
.load(pathToHDFS)
.as[Root]
Я действительно не знаю, как начать с этой проблемы, так как я могу получить только заголовки столбцов и тело. Как я могу получить вложенные значения для окончательной сортировки по отметке времени?
Я хотел бы сделать что-то вроде этого:
ds.select("headers").doSomethingToGetTheMapStructure.doSomeConversionStringToTimeStampForTheColumnTimeStamp("timestamp").orderBy("timestamp")
Немного точности: я не хочу терять какие-либо данные из моего начального набора данных, просто операция сортировки.
Я использую Spark 2.3.0.
3 ответа
Загруженный Dataset
должен выглядеть примерно так, как показано в примере набора данных ниже:
case class Root(headers : Map[String, String], body: String)
val ds = Seq(
Root(Map("k11"->"v11", "timestamp"->"1554231600", "k12"->"v12"), "body1"),
Root(Map("k21"->"v21", "timestamp"->"1554134400", "k22"->"v22"), "body2")
).toDS
Вы можете просто найти Map
с помощью клавиши timestamp
, cast
значения Long
и выполнить orderBy
следующим образом:
ds.
withColumn("ts", $"headers"("timestamp").cast("Long")).
orderBy("ts").
show(false)
// +-------------------------------------------------+-----+----------+
// |headers |body |ts |
// +-------------------------------------------------+-----+----------+
// |[k21 -> v21, timestamp -> 1554134400, k22 -> v22]|body2|1554134400|
// |[k11 -> v11, timestamp -> 1554231600, k12 -> v12]|body1|1554231600|
// +-------------------------------------------------+-----+----------+
Обратите внимание, что $"headers"("timestamp")
точно так же, как и использование apply
метод столбца (т. е. $"headers".apply("timestamp")
).
В качестве альтернативы вы также можете использовать getItem
для доступа к Map
по ключу, например:
$"headers".getItem("timestamp")
Вы можете использовать Scala sortBy, который принимает функцию. Я бы посоветовал вам явно объявить val ds как Vector (или другую коллекцию), чтобы вы увидели применимые функции в IntelliJ (если вы используете IntelliJ), и он обязательно скомпилируется.
Смотрите мой пример ниже на основе вашего кода:
case class Root(headers : Map[String,String], body: String)
val ds: Vector[Root] = spark
.read
.format("com.databricks.spark.avro")
.load(pathToHDFS)
.as[Root]
val sorted = ds.sortBy(r => r.headers.get("timestamp").map(PROCESSING) ).reverse
Редактировать: добавлено обратное (при условии, что вы хотите, чтобы он по убыванию). Внутри функции, которую вы передаете в качестве аргумента, вы также поместите обработку в метку времени.
import org.apache.spark.sql.{Encoders, Encoder, Dataset}
import org.apache.spark.sql.functions.{col, desc}
import java.sql.Timestamp
case class Nested(key_1: String,key_2: String,timestamp: Timestamp,key_n: String)
case class Root(headers:Nested,body:String)
implicit val rootCodec: Encoder[Root] = Encoders.product[Root]
val avroDS:Dataset[Root] = spark.read
.format("com.databricks.spark.avro")
.load(pathToHDFS)
.as[Root]
val sortedDF: DataFrame = avroDS.orderBy(desc(col("timestamp")))
Этот фрагмент кода будет напрямую преобразовывать ваши данные Avro в Dataset[Root]
. Вам не нужно полагаться на импорт sparksession.implicits
, и вы исключите шаг приведения вашего поля timestamp к TimestampType . Внутренне, тип данных Spark Timestamp реализован с использованием java.sql.Timestamp
.
Похожие вопросы
Новые вопросы
scala
Scala - это язык программирования общего назначения, в основном предназначенный для виртуальной машины Java. Разработанный для краткого, элегантного и безопасного для типов представления общих шаблонов программирования, он сочетает в себе как императивный, так и функциональный стили программирования. Его ключевые особенности: продвинутая система статического типа с выводом типа; типы функций; сопоставления с образцом ; неявные параметры и преобразования; перегрузка оператора; полная совместимость с Java; совпадение