Как указать масштаб и точность BigDecimal в схеме при загрузке коллекции Mon go как набора данных Spark - PullRequest
0 голосов
/ 03 августа 2020

Я пытаюсь загрузить большую коллекцию Mon go в Apache Spark с помощью коннектора Scala Mon go.

Я использую следующие версии:

libraryDependencies += "org.apache.spark" %% "spark-core" % "3.0.0" 
libraryDependencies += "org.apache.spark" %% "spark-sql" % "3.0.0" 
libraryDependencies += "org.mongodb.spark" %% "mongo-spark-connector" % "2.4.2"
scalaVersion := "2.12.12"
openjdk version "11.0.8" 2020-07-14

Коллекция содержит большие целые десятичные значения, превышающие 1e13. Набор данных, который я хотел бы получить, представляет собой коллекцию с соответствующим классом case под названием Output, определенным:

case class Output(time: Long, pubKeyId: Long, value: BigDecimal, outIndex: Long, outTxId: Long)

Если я использую MongoSpark.load без указания класса case:

val ds = MongoSpark.load(sc, rc).toDS[Output]

, затем Mon go определяет схему путем случайной выборки коллекции. Это приводит к случайной шкале для атрибута value, и любые документы, value которых выходит за пределы случайно полученной шкалы, имеют отсутствующий атрибут value в результирующем наборе данных. Это явно нежелательно.

В качестве альтернативы, согласно документации для Mon go Spark connector , я могу явно установить схему, указав класс case как параметризацию типа для load, например:

val ds = MongoSpark.load[Output](sc, rc).toDS[Output]

Однако в определении класса case я могу указать только тип value как BigDecimal, что не позволяет мне явно указать желаемый масштаб и точность. Результирующая схема использует точность и масштаб по умолчанию (38,18), что не всегда желательно:

root
 |-- time: long (nullable = false)
 |-- pubKeyId: long (nullable = false)
 |-- value: decimal(38,18) (nullable = true)
 |-- outIndex: long (nullable = false)
 |-- outTxId: long (nullable = false)

В отличие от API Spark SQL, который позволяет масштаб и точность должно быть указано явно с использованием DecimalType, например:

val mySchema = StructType(StructField("value", DecimalType(30, 0)) :: Nil)

Как я могу запросить конкретный c масштаб и точность для больших десятичных типов в схеме, аналогично коду выше, при загрузке коллекций Mon go в Apache Spark?

Ответы [ 2 ]

0 голосов
/ 05 августа 2020

Мне удалось это сделать, обойдя вспомогательные методы load и вызвав toDF(schema) непосредственно в экземпляре MongoSpark:

 val schema = StructType(
                             List(StructField("time", LongType, false),
                                  StructField("pubKeyId", LongType, false),
                                  StructField("value", DecimalType(30, 0), false),
                                  StructField("outIndex", LongType, false),
                                  StructField("outTxId", LongType, false)
                             ))
    val outputs =    
      builder().sparkContext(sc).readConfig(rc).build().toDF(schema).as[Output]

Это приводит к правильной схеме, и данные правильно читать в Spark без каких-либо пропущенных значений:

    outputs.printSchema()
 |-- time: long (nullable = false)
 |-- pubKeyId: long (nullable = false)
 |-- value: decimal(30,0) (nullable = false)
 |-- outIndex: long (nullable = false)
 |-- outTxId: long (nullable = false)
0 голосов
/ 03 августа 2020

Per this и this , насколько я могу судить, мантисса и экспонента в Decimal128 имеют фиксированный размер. Если вы не найдете доказательств обратного, то для MongoDB не имеет смысла разрешать указание масштаба и точности для десятичных знаков. 32-битные или 64-битные числа с плавающей запятой), но в MongoDB база данных сохраняет заданные типы, поэтому, если вы хотите более короткое число с плавающей запятой, вам нужно заставить ваше приложение отправлять его вместо десятичного типа.

...