2016-07-23 10 views
5

Ich habe versucht, eine JSON-Datei als kleine DB zu verwenden. Nachdem ich eine Template-Tabelle auf dem DataFrame erstellt hatte, habe ich sie mit SQL abgefragt und eine Exception bekommen. Hier ist mein Code:Lesen mehrzeiliger JSON in Apache Spark

val df = sqlCtx.read.json("/path/to/user.json") 
df.registerTempTable("user_tt") 

val info = sqlCtx.sql("SELECT name FROM user_tt") 
info.show() 

df.printSchema() Ergebnis:

root 
|-- _corrupt_record: string (nullable = true) 

Meine JSON-Datei:

{ 
    "id": 1, 
    "name": "Morty", 
    "age": 21 
} 

Exeption:

Exception in thread "main" org.apache.spark.sql.AnalysisException: cannot resolve 'name' given input columns: [_corrupt_record]; 

Wie kann ich es beheben?

UPD

_corrupt_record ist

+--------------------+ 
|  _corrupt_record| 
+--------------------+ 
|     {| 
|   "id": 1,| 
| "name": "Morty",| 
|   "age": 21| 
|     }| 
+--------------------+ 

UPD2

Es ist seltsam, aber wenn ich meine JSON neu schreiben, um es oneliner, funktioniert alles einwandfrei.

{"id": 1, "name": "Morty", "age": 21} 

So ist das Problem in einem newline.

UPD3

ich in docs fand den nächsten Satz:

Beachten Sie, dass die Datei, die als JSON-Datei angeboten wird, ist keine typische JSON-Datei. Jede Zeile muss ein separates, eigenständiges gültiges JSON-Objekt enthalten. Als Konsequenz wird eine reguläre mehrzeilige JSON-Datei meistens fehlschlagen.

Es ist nicht praktisch, JSON in einem solchen Format zu speichern. Gibt es einen Workaround, um die Multi-Liner-Struktur von JSON loszuwerden oder in oneliner zu konvertieren?

Antwort

14

Spark> = 2.2

Spark-2.2 eingeführt wholeFilemultiline Option, die verwendet werden können, JSON laden (nicht JSONL) Dateien:

spark.read 
    .option("multiline", true).option("mode", "PERMISSIVE") 
    .json("/path/to/user.json") 

See:

  • SPARK-18352 - Parsen normaler, mehrzeiliger JSON fi les (nicht nur JSON Linien).
  • SPARK-20980 - Benennen Sie die Option wholeFile in multiLine für JSON und CSV um.

Funken < 2.2

Nun, die Verwendung von JSONL formatierten Daten kann unbequem sein, aber es wird argumentieren, dass nicht das Problem mit der API, sondern das Format selbst ist. JSON ist einfach nicht dafür ausgelegt, in verteilten Systemen parallel verarbeitet zu werden.

Es bietet kein Schema und ohne einige sehr spezifische Annahmen über seine Formatierung und Form ist es fast unmöglich, Top-Level-Dokumente korrekt zu identifizieren. Wahrscheinlich ist dies das denkbar schlechteste Format, um es in Systemen wie Apache Spark zu verwenden. Es ist auch ziemlich schwierig und in der Regel nicht praktikabel, gültige JSON in verteilten Systemen zu schreiben.

aber sagen, dass, wenn einzelne Dateien gültig JSON Dokumente (entweder einzelne Dokument oder eine Reihe von Dokumenten) sind, können Sie immer versuchen, wholeTextFiles:

spark.read.json(sc.wholeTextFiles("/path/to/user.json").values()) 
2

Nur um zero323 Antwort hinzuzufügen auf, die Möglichkeit in Funken 2.2+ zum Lesen von mehrzeiligen JSON wurde in multiLine umbenannt (siehe Spark-Dokumentation here).

Daher ist die korrekte Syntax ist jetzt:

spark.read 
    .option("multiLine", true).option("mode", "PERMISSIVE") 
    .json("/path/to/user.json") 

Das in https://issues.apache.org/jira/browse/SPARK-20980 passiert ist.

+0

"Multiline" -Option funktionierte für mich. Danke Dan! – Omkar