Пустая строка в смешанном столбце обнуляет строку при загрузке с использованием Spark - PullRequest
0 голосов
/ 18 марта 2020

Рассмотрим следующее JSON:

{"col1": "yoyo", "col2": 1.5}
{"col1": "",     "col2": 6}
{"col1": "456",  "col2": ""}
{"col1": 444,    "col2": 12}
{"col1": null,   "col2": 1.7}
{"col1": 3.14,   "col2": null}

, которое я загружаю с помощью (Py) Spark следующим образом:

from pyspark.sql import SparkSession
spark = SparkSession.builder.master("local[*]").getOrCreate()
df = spark.read.json("my.json")
df.show()

, что дает:

+----+----+
|col1|col2|
+----+----+
|yoyo| 1.5|
|    | 6.0|
|null|null|  <---===***
| 444|12.0|
|null| 1.7|
|3.14|null|
+----+----+

Мне трудно понять, почему 3-я строка обнуляется. Похоже, причина в том, что единственной строкой во втором столбце является пустая строка "", и это как-то вызывает обнуление. Обратите внимание, что col1 содержит также пустую строку во 2-й строке, но строка не обнуляется.

Для меня это очень запутанное и неожиданное поведение. Мне не удалось найти подсказки в документации.

  • Ожидается ли такое поведение? Почему так происходит?
  • Я бы ожидал, что 3-я строка будет содержать строку "456" для col1 и пустую строку "" для col2. Как я могу добиться такого поведения (которое кажется мне гораздо более естественным)?

1 Ответ

3 голосов
/ 18 марта 2020

Невозможно смешивать разные типы данных в одном столбце при использовании Spark.

При чтении файла json Spark попытается определить тип данных каждого столбца (см. примечание внизу для более подробной информации). Здесь Спарк считает, что col1 имеет строковый тип, а col2 - двойной. Это может быть подтверждено чтением файла json и использованием printSchema на фрейме данных.
Это означает, что данные анализируются на основе этих предполагаемых типов данных. Поэтому Spark попытается проанализировать "" как двойное число, которое явно не получается. (Для второй строки в col1 это работает, поскольку col1 выводится как строковый тип, поэтому "" является допустимым входным сигналом.)

При использовании spark.read.json возможно установить различные режимы , Из документации мы имеем:

mode -
позволяет режим для работы с поврежденными записями во время синтаксического анализа. Если None установлен, он использует значение по умолчанию, PERMISSIVE.

  • PERMISSIVE: когда он встречает поврежденную запись, помещает искаженную строку в поле, настроенное columnNameOfCorruptRecord, и устанавливает другие поля к нулю. Чтобы сохранить поврежденные записи, пользователь может установить поле строкового типа columnNameOfCorruptRecord в определенной пользователем схеме. Если схема не имеет поля, она удаляет поврежденные записи во время анализа. При выводе схемы она неявно добавляет поле columnNameOfCorruptRecord в выходную схему.
  • DROPMALFORMED: игнорирует все поврежденные записи.
  • FAILFAST: выдает исключение при обнаружении поврежденных записей.

Из приведенного выше видно, что режим PERMISSIVE используется по умолчанию и что если обнаружена поврежденная запись, все поля установлены на null. Это то, что происходит в этом случае. Для подтверждения можно установить mode на FAILFAST,

spark.read.json("my.json", mode='FAILFAST')

, что приведет к исключению.

Это можно решить, не выводя типы данных и читая все как Строки вместо.

spark.read.json("my.json", primitivesAsString='true')

Примечание: Вывод схемы для json немного отличается от других источников, таких как csv и txt, см. здесь . Для файлов json и "", и null имеют специальную обработку для работы с генераторами json, которые не делают различий между ними. Для файлов csv столбец с пустой строкой "" все равно будет означать, что весь столбец будет строкой, но это не относится к json.

В качестве примечания, заменяющего "" например, "5" в col2 сделает выводимый тип столбца строковым.

...