Как использование кодировщиков намного быстрее, чем сериализация Java?
Как использование кодировщиков намного быстрее, чем сериализация java и kryo?
2 ответа
Так как
Encoders
жертвовать общностью ради производительности. Идея не нова. Почему Kryo быстрее сериализации Java? По той же причине. Рассмотрим эту стенограмму:scala> val spark = SparkSession.builder.config("spark.serializer", "org.apache.spark.serializer.JavaSerializer").getOrCreate() spark: org.apache.spark.sql.SparkSession = org.apache.spark.sql.SparkSession@1ed28f57 scala> val map = Map[String, Int]("foo" -> 1).withDefaultValue(0) map: scala.collection.immutable.Map[String,Int] = Map(foo -> 1) scala> map("bar") res1: Int = 0 scala> val mapSerDe = spark.sparkContext.parallelize(Seq(map)).first mapSerDe: scala.collection.immutable.Map[String,Int] = Map(foo -> 1) scala> mapSerDe("bar") res2: Int = 0
по сравнению с
scala> val spark = SparkSession.builder.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer").getOrCreate() spark: org.apache.spark.sql.SparkSession = org.apache.spark.sql.SparkSession@5cef3456 scala> val map = Map[String, Int]("foo" -> 1).withDefaultValue(0) map: scala.collection.immutable.Map[String,Int] = Map(foo -> 1) scala> map("bar") res7: Int = 0 scala> val mapSerDe = spark.sparkContext.parallelize(Seq(map)).first mapSerDe: scala.collection.immutable.Map[String,Int] = Map(foo -> 1) scala> mapSerDe("bar") java.util.NoSuchElementException: key not found: bar at scala.collection.MapLike$class.default(MapLike.scala:228) at scala.collection.AbstractMap.default(Map.scala:59) at scala.collection.MapLike$class.apply(MapLike.scala:141) at scala.collection.AbstractMap.apply(Map.scala:59) ... 48 elided
(Я не смог найти точный пост, но идея этого примера взята из списка разработчиков).
Как видите, Kryo, хотя и быстрее, не обрабатывает все возможные случаи. Он фокусируется на самых распространенных и делает это правильно.
искра
Encoders
сделать то же самое, но еще менее общего. Если вы поддерживаете только 16 типов или около того и не заботитесь о совместимости (должно быть с реальными библиотеками сериализации), у вас есть много возможностей для оптимизации.Отсутствие необходимости взаимодействия позволяет вам двигаться дальше. Кодеры для атомарных типов - это просто идентичность. Там нет необходимости каких-либо преобразований вообще.
Знание схемы, как объяснил himanshuIIITian, является еще одним фактором.
Почему это имеет значение? Потому что, имея четко определенную форму, позволяет оптимизировать сериализацию и хранение. Если вы знаете, что ваши данные структурированы, вы можете переключаться между измерениями - вместо гетерогенных строк, которые дорого хранить и получать к ним доступ, вы можете использовать столбчатое хранилище.
Как только данные сохранены в столбцах, вы открываете новый набор возможностей оптимизации:
- Доступ к данным в полях фиксированного размера очень быстрый, потому что вы можете напрямую получить доступ к определенному адресу (помните все волнения по поводу внеполосной памяти / родной памяти / вольфрама?).
- Вы можете использовать широкий спектр методов сжатия и кодирования, чтобы минимизировать размер данных.
Эти идеи тоже не новы. Столбчатые базы данных, форматы хранения (например, Parquet) или современные форматы сериализации, разработанные для аналитики (например, Arrow), используют те же идеи и часто продвигают их еще дальше (обмен данными без копирования).
К сожалению, кодировщики - не серебряная пуля. Хранение нестандартного объекта - это беспорядок, коллекционные кодеры могут быть очень неэффективными.
Просто - кодировщики знают схему записей. Таким образом они предлагают значительно более быструю сериализацию и десериализацию (по сравнению с сериализаторами Java или Kryo по умолчанию).
Для справки - https://jaceklaskowski.gitbooks.io/mastering-spark-sql/spark-sql-Encoder.html