# Große JSON-Dateien schnell und effizient verarbeiten



## Kenta1561 (1. Mai 2017)

Hallo,

eigentlich versuche ich gerade eine Android-App zu machen, da es aber eher um allgemein Java und Performance geht, dachte ich, ich könnte auch mal hier fragen.

Es geht um folgendes: Ich benutzte eine offizielle API vom Frankfurter Flughafen, um Flüge von und nach Frankfurt zu bekommen. Das Problem bei der API ist jedoch, dass es nicht wie bei manchen anderen APIs die Möglichkeit gibt, die Zahl der Ergebnisse zu limitieren. Deshalb muss muss jedes Mal wenn die Anwendung gestartet wird insgesamt um die täglich 1300 Flüge gelesen werden, obwohl ich nur eigentlich um die 100-150 Flüge (also ungefähr im 2-stündigem Rahmen) brauche. Ich habe es hinbekommen, nur 100-150 Flüge *anzuzeigen*, jedoch ändert es nichts daran, dass trotzdem diese Massen an Flügen erstmal gelesen werden müssen. Wie kann ich das Ganze so optimieren, dass es schneller läuft? Oder geht es nicht?

Kenta1561


----------



## mrBrown (1. Mai 2017)

Naja, wenn die API nicht zulässt, dass weniger geladen werden, können nicht weniger geladen werden 

Wenn du in der Anwendung weniger brauchst, kann man die natürlich direkt im Service/Repo/'wie auch immer du das nennst' filtern, dann bekommt die restliche Application davon nichts mit


----------



## Thallius (1. Mai 2017)

Also 1300 kommt mir jetzt nicht so wahnsinnig viel vor. Das sollte man doch in weniger als 1s geparsed  haben.

Aber davon mal ab würde ich das Konzept eh ändern. Du hältst die Daten einfach lokal auf dem device und machst bei jedem Start der App einen Request im Hintergrund der die Flugdaten aktualisiert. Damit hat der User (ausser beim allerersten Start der App) überhaupt keine Wartezeit und kann sogar offline arbeiten wenn es nötig ist.

Gruß

Claus


----------



## Kenta1561 (1. Mai 2017)

@Thallius Stimmt, danke für die Idee  Ich denke auch dass nicht das Parsen viel Zeit kostet, sondern das eigentliche herunterladen. (Wenn man im Playground von der API rumprobiert dauert das Laden sehr lange (es wird nicht geparsed sondern einfach als Text angezeigt))


----------



## Thallius (1. Mai 2017)

Wie lange der Download dauert siehst du doch wenn du den Link einfach mal in einen Browser eingibst.


----------



## Kenta1561 (1. Mai 2017)

@Thallius Ich verstehe nicht ganz wie ich
"curl -X GET --header "Authorization: Bearer (access token)" "https://developer.fraport.de/api/flights/1.0/flight/FRA/departure" in einen Link verwandeln soll.


----------



## Thallius (1. Mai 2017)

Ok ich wusste nicht das die eine auth Verlagen


----------



## mrBrown (1. Mai 2017)

Du kannst dir mit time in der Konsole ausgeben lassen, wie lange curl braucht, nen Browser dafür nutzen ist doch Unsinn...


----------



## Kenta1561 (1. Mai 2017)

Hallo,

danke für die ganzen Antworten. Ich habe gerade herausgefunden, dass die Verzögerung nicht am Herunterladen der Daten oder an der Visualisierung der Daten liegt, sondern am Lesen der JSON-Datei.
Ob ich erst mit OkHttp die Response mit body().string() in ein String umwandle oder erst im JsonReader mit new JsonReader(new InputStreamReader(body().byteStream()) ist egal, es dauert fast genau so lange.
Es wäre halt echt am besten wenn ich die Zahl der Flüge begrenzen könnte, leider geht das nicht. Weil es ja wie schon erwähnt bereits am Lesen liegt, bringt es auch nichts, beim durchgehen des Flüge-Arrays bzw. Entry-Sets zum Beispiel mit einem Integer-Counter bei 100 Flügen mit return abzubrechen. Die Idee mit den lokalen Daten ist eigentlich ganz gut, aber gibt es auch eine alternative, schnelle Möglichkeit wenn ich immer die Daten auf dem Bildschirm aktuell halten möchte?

*PS:*
Ich habe das sogenannte Streaming bei Gson gefunden, was angeblich nicht die komplette Datei erstmal lädt, sondern erst bei Bedarf. Ich bin mir ziemlich sicher dass dadurch die App schneller starten kann, jedoch
sind die Json-Antworten von der API so komisch gebaut (Manchmal nehmen sie wenn sie keine richtigen Werte als Antwort haben null als Value, manchmal lassen die die Tags auch komplett raus), dass es fast unmöglich scheint, durch next(), begin() und end() blind die ganze Json-Datei zu durchforsten.

Kenta1561


----------



## mrBrown (1. Mai 2017)

Kenta1561 hat gesagt.:


> danke für die ganzen Antworten. Ich habe gerade herausgefunden, dass die Verzögerung nicht am Herunterladen der Daten oder an der Visualisierung der Daten liegt, sondern am Lesen der JSON-Datei.
> Ob ich erst mit OkHttp die Response mit body().string() in ein String umwandle oder erst im JsonReader mit new JsonReader(new InputStreamReader(body().byteStream()) ist egal, es dauert fast genau so lange.


Wie lange dauert es denn überhaupt?



Kenta1561 hat gesagt.:


> Ich habe das sogenannte Streaming bei Gson gefunden, was angeblich nicht die komplette Datei erstmal lädt, sondern erst bei Bedarf. Ich bin mir ziemlich sicher dass dadurch die App schneller starten kann, jedoch
> sind die Json-Antworten von der API so komisch gebaut (Manchmal nehmen sie wenn sie keine richtigen Werte als Antwort haben null als Value, manchmal lassen die die Tags auch komplett raus), dass es fast unmöglich scheint, durch next(), begin() und end() blind die ganze Json-Datei zu durchforsten.


Ob die Tags vorhanden sind oder nicht oder null sind ist eigentlich egal, solange GSON das parsen kann, kann er es parsen - du nutzt doch jetzt schon GSON?


----------



## Kenta1561 (2. Mai 2017)

@mrBrown Eigentlich wollte ich mit gson.fromJson die Json-Datei parsen, jedoch wusste ich nicht wie ich zum Beispiel folgendes parsen sollte:

"codeShares": [
  {
    "codeShare": {
      ...
    }
  }, (usw.)

codeShare ist hierbei irgendwie doppelt? geschachtelt und ich weiß nicht wie ich das mit gson.fromJson() parsen kann. Deshalb habe ich immer nur mit
getAsJsonObject(), get(), getAsJsonArray() usw. die Json-Datei geparsed.

Kenta1561


----------



## mrBrown (2. Mai 2017)

Ne, da ist nichts doppelt, das heißt anders.

Generell nutzt man GSON, in dem man Klassen mit gleicher Struktur wie das JSON hat, in welches dann die Daten überführt werden.
In dem Fall halt ein Array von Objekte, aber der Ausschnitt ist etwa knapp und unvollständig, um da was zu sagen...


----------



## Kenta1561 (2. Mai 2017)

@mrBrown Hier ist die Dokumentation von der API: https://developer.fraport.de/store/documentation Beim Arrival bzw. Departure Abschnitt sieht man z.B. bei codeShares ein Array von codeShare-Objekten.
Kann ich hierbei einfach eine CodeShare Klasse machen, die dann einfach von Json als List<CodeShare> erkannt wird?

Kenta1561


----------



## mrBrown (2. Mai 2017)

Das sollte klappen, uU muss da noch die passende GSON-Annotation dran, probiers einfach mal


----------



## Kenta1561 (2. Mai 2017)

@mrBrown Ok danke, ich werde es später ausprobieren. Mit Annotationen meinst du z.B. @SerializedName(), oder?

Kenta1561


----------



## mrBrown (2. Mai 2017)

Ja


----------



## Kenta1561 (2. Mai 2017)

@mrBrown 
Also, ich bin jetzt bis hierhin gekommen:

Die Variablen sind:
private OperatingAirline operatingAirline;
private AircraftType aircraftType;
private FlightNumber flightNumber;
private List<FlightNumber> codeShares;

"codeShares": [
  {
    "codeShare": {
      "airlineCode": "LH",
      "trackNumber": "9695",
      "suffix": ""
    }
  },
  {
    "codeShare": {
      "airlineCode": "NH",
      "trackNumber": "5350",
      "suffix": ""
    }
  },
  {
    "codeShare": {
      "airlineCode": "TP",
      "trackNumber": "8988",
      "suffix": ""
    }
  },
  {
    "codeShare": {
      "airlineCode": "UA",
      "trackNumber": "7212",
      "suffix": ""
    }
  }
]

Die Liste mit FlightNumber an sich wird normal gelesen, wenn ich die Größe von der Liste mir ausgeben lasse wird auch die richtige Größe genannt (4). Jedoch sind die Variablen der FlightNumber-Klasse alle null,
was darauf deutet, dass die Werte nicht richtig gelesen wurden. Ich verstehe jetzt aber nicht, wie, wo und welche Annotation ich hinzufügen muss.

Kenta1561


----------

