Это включает в себя кодек в соответствии с запросом, необходимые импорты и сутенером в соответствии с запросом.
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SQLContext
// TODO Need a macro to generate for each Tuple length, or perhaps can use shapeless
implicit class PimpedRDD[T1, T2](rdd: RDD[(T1, T2)]) {
def writeAsMultiple(prefix: String, codec: String,
keyName: String = "key")
(implicit sqlContext: SQLContext): Unit = {
import sqlContext.implicits._
rdd.toDF(keyName, "_2").write.partitionBy(keyName)
.format("text").option("codec", codec).save(prefix)
}
}
val myRdd = sc.makeRDD(Seq((1, "a"), (1, "b"), (2, "c")))
myRdd.writeAsMultiple("prefix", "org.apache.hadoop.io.compress.GzipCodec")
Одно тонкое отличие от OP состоит в том, что оно будет префикс <keyName>=
к именам каталогов. Например,
myRdd.writeAsMultiple("prefix", "org.apache.hadoop.io.compress.GzipCodec")
дал бы:
prefix/key=1/part-00000
prefix/key=2/part-00000
, где prefix/my_number=1/part-00000
будет содержать строки a
и b
, а prefix/my_number=2/part-00000
будет содержать строку c
].
И
myRdd.writeAsMultiple("prefix", "org.apache.hadoop.io.compress.GzipCodec", "foo")
Дает:
prefix/foo=1/part-00000
prefix/foo=2/part-00000
Должно быть ясно, как отредактировать для parquet
.
Наконец, ниже приведен пример для Dataset
, что, возможно, лучше, чем использование Tuples.
implicit class PimpedDataset[T](dataset: Dataset[T]) {
def writeAsMultiple(prefix: String, codec: String, field: String): Unit = {
dataset.write.partitionBy(field)
.format("text").option("codec", codec).save(prefix)
}
}
Я не думаю, что есть какие-то предопределенные символы препроцессора. Однако вы можете добиться того, чего хотите, вот так:
Создайте различные конфигурации вашего проекта, по одной для каждой версии CLR, которую вы хотите поддерживать.
Выберите символ, например VERSION2
, VERSION3
и т. Д. Для каждой версии CLR.
В каждой конфигурации определите один символ, связанный с ним, и отмените определение всех остальных.
Используйте эти символы в блоках условной компиляции.
Нет, любой встроил, но можно предоставить собственное.
Для этого определенного сценария, Вы могли бы хотеть инкапсулировать логику в (например), обертке (блокировка) класс, так, чтобы Вы не имели #if
рассеянный через весь код; конечно, если Вы только делаете немного блокировки, это не могло бы стоить проблемы.
я использую различные конфигурации и/или проекты создать для множества платформ - т.е. protobuf-сеть сборки для.NET 2.0.NET 3.0, моно, CF 2.0, CF 3.5 с помощью этого приема. Код имеет #if
, блоки на основе различных символов к управляющей логике - так, например, BinaryFormatter
не доступны на CF, WCF
только доступно с.NET 3.0, Delegate.CreateDelegate
не находится на CF 2.0, и т.д.
Вы можете использовать отражение, чтобы динамически проверять, доступен ли определенный тип, такой как ReaderWriterLockSlim (вместо использования препроцессора).
Это даст вам преимущество в том, что вы сможете развернуть одну версию своего продукта, и пользователи, имеющие (или обновляющие) .NET 3.5, получат выгоду от оптимизированного кода.
Вы могли вручную установить этот символ с помощью / определяют переключатель компилятора . Тогда Вы создаете различные конфигурации сборки для каждой желаемой версии сброса.
Если это все, что вам нужно было сделать, я полагаю, что вы могли бы использовать Environment.Version, но, как и в решении divo , оно, похоже, оставляет там много ненужного кода.