2016-09-16 9 views
0

Ich habe einen JSON-String, die wie folgt aussieht:Wie teilt man den String effizienter auf?

{"Detail": [ 
    {"PrimaryKey":111,"Date":"2016-09-01","Version":"7","Count":2,"Name":"Windows","LastAccessTime":"2016-05-25T21:49:52.36Z"}, 
    {"PrimaryKey":222,"Date":"2016-09-02","Version":"8","Count":2,"Name":"Windows","LastAccessTime":"2016-07-25T21:49:52.36Z"}, 
    {"PrimaryKey":333,"Date":"2016-09-03","Version":"9","Count":3,"Name":"iOS","LastAccessTime":"2016-08-22T21:49:52.36Z"}, 
    .....(*many values) 
]} 

Das Array Detail viele PrimaryKey s hat. Manchmal ist es etwa 500K PrimaryKey s. Das System, das wir verwenden, kann nur JSON-Zeichenfolgen mit einer bestimmten Länge, d. H. 128 KB, verarbeiten. Also muss ich diese JSON-Zeichenfolge in Segmente aufteilen (jede ist 128 KB oder weniger Zeichen lang).

Regex reg = new Regex(@"\{"".{0," + (128*1024).ToString() + @"}""\}"); 
MatchCollection mc = reg.Matches(myListString); 

Derzeit verwende ich regulären Ausdruck, um dies zu tun. Es funktioniert gut. Es verwendet jedoch zu viel Arbeitsspeicher. Gibt es einen besseren Weg dies zu tun (unnötig um regulärer Ausdruck zu sein)?

*** Weitere Informationen hinzugefügt.

Das 'System', das ich oben erwähnte, ist Azure DocumentDB. Standardmäßig kann das Dokument nur 512 KB groß sein (wie jetzt). Obwohl wir MS diese erhöhen können, aber die JSON-Datei haben wir immer viel viel mehr als 512KB. Deshalb müssen wir einen Weg finden, dies zu tun.

Wenn möglich, möchten wir weiterhin documentDB verwenden, aber wir sind offen für andere Vorschläge.

*** Einige Informationen, um die Dinge zu verdeutlichen: 1) Die Werte im Array sind unterschiedlich. Nicht dupliziert. 2) Ja, ich benutze StringBuilder wann immer ich kann. 3) Ja, ich habe versucht, IndexOf & Substring, aber basierend auf Tests, die Leistung ist nicht besser als regulärer Ausdruck in diesem Fall (obwohl es könnte die Art, wie ich es implementieren).

* ** Das Json-Objekt ist komplex, aber alles was mich interessiert, ist dieses "Detail", das ein Array ist. Wir können davon ausgehen, dass die Zeichenfolge genau wie das Beispiel ist, nur "Detail" hat. Wir müssen diese json-Array-Zeichenfolge in eine Größe von weniger als 512 KB aufteilen. Grundsätzlich können wir dies als eine einfache Zeichenfolge, nicht Json denken. Aber es ist ein JSON-Format, also können vielleicht einige Bibliotheken das besser machen.

+6

Welches System? (Das System, das wir verwenden, kann nur die JSON-Zeichenfolge mit bestimmter Länge verarbeiten, dh 128 KB) –

+2

Sie müssen Ihren JSON im Wesentlichen neu schreiben, um gültig zu sein JSON von geringerer Länge, oder ist das "System" Sie sprechen über Homebrew und doesn ' t interessiert es wirklich, ob es gültiger json ist oder nicht? Werfen Sie einen Blick auf json.net oder etwas, das diese Art von Einschränkung nicht hat? –

+0

Wenn Sie das genaue Format Ihrer Daten kennen und nicht daran interessiert sind, den Parsing-Code zu brechen, wenn sich das Format ändert, würde ich ein paar "IndexOf" und "Substring" anwenden. –

Antwort

3

Werfen Sie einen Blick auf Json.NET (verfügbar über NuGet).

Es verfügt über eine JsonReader Klasse, mit der Sie ein erforderliches Objekt durch Lesen von JSON durch Token example of json reading with JsonReader erstellen können. Nicht, wenn Sie eine ungültige JSON-Zeichenfolge (z. B. ohne "end array" -Zeichen oder ohne "end object" -Zeichen) an JsonReader übergeben - es wird nur eine Ausnahme ausgelöst, wenn es ein ungültiges Element erreicht, so dass Sie verschiedene Teilzeichenfolgen an es übergeben können.

Auch denke ich, dass Ihr System etwas ähnlich zu JsonReader hat, so dass Sie es verwenden können.

Das Lesen einer string mit StringReader sollte nicht zu viel Anwendungsspeicher erfordern und es sollte schneller sein, als durch Übereinstimmungen mit regulären Ausdrücken zu iterieren.

+0

Nun, es war früh am Morgen und ich habe mich hier vermischt ... –

+0

JsonReader wird in diesem Fall nicht besser funktionieren. Da die JSON-Zeichenfolge für das Array sehr lang ist, möchten wir sie jetzt in mehrere Strings aufteilen, die jeweils weniger als 512 KB groß sind. Dies bedeutet, dass wir die Objekte durchlaufen müssen, die Länge des Elements ermitteln, sie addieren müssen, bis die Zeichenfolge 512 KB erreicht hat, die Zeichenfolge ausgeben und dann das nächste Objekt verarbeiten. Dies ist offensichtlich langsamer als die direkte Verarbeitung der Zeichenfolge durch IndexOf, da das Objekt nicht analysiert werden muss. Und IndexOf ist in diesem Fall basierend auf Tests langsamer als Regex. Vielen Dank. – urlreader

1

Hier ist eine hacky Lösung unter der Annahme data enthält Ihre JSON-Daten:

var details = data 
    .Split('[')[1] 
    .Split(']')[0] 
    .Split(new[] { "}," }, StringSplitOptions.None) 
    .Select(d => d.Trim()) 
    .Select(d => d.EndsWith("}") ? d : d + "}");; 

foreach (var detail in details) 
{ 
    // Now process "detail" with your JSON library. 
} 

Arbeitsbeispiel: https://dotnetfiddle.net/sBQjyi

Offensichtlich sollten Sie dies nur tun, wenn Sie wirklich keine normale JSON-Bibliothek verwenden können. Informationen zu Bibliotheksvorschlägen finden Sie unter Mikhail Neofitov's answer.

Wenn Sie die JSON-Daten aus Datei oder Netzwerk lesen, sollten Sie eine Stream-ähnliche Verarbeitung implementieren, bei der Sie eine Detailzeile lesen, sie mit Ihrer JSON-Bibliothek deserialisieren und sie dem Aufrufer übergeben. Wenn der Aufrufer das nächste Detailobjekt anfordert, lesen Sie die nächste Zeile, deserialisieren Sie es und so weiter. Auf diese Weise können Sie den Speicherbedarf Ihres Deserialisers minimieren.

0

Sie sollten in Erwägung ziehen, jedes Detail in einem separaten Dokument zu speichern. Es bedeutet zwei Rundreisen, um sowohl den Header als auch alle Detaildokumente zu erhalten, aber es bedeutet, dass Sie nie mit einem wirklich großen JSON-Dokument zu tun haben. Wenn Detail inkrementell hinzugefügt wird, ist es außerdem viel effizienter für Schreibvorgänge, da es keine Möglichkeit gibt, einfach eine weitere Zeile hinzuzufügen. Sie müssen das gesamte Dokument neu schreiben. Ihr Lese-/Schreibverhältnis bestimmt den Break-even-Punkt in der Gesamteffizienz.

Ein weiteres Argument dafür ist, dass die Komplexität der Regex-Analyse, Feeding es durch Ihre JSON-Parser, und dann wieder zusammenbauen geht weg. Sie wissen nie, ob Ihr Regex-Parser alle Fälle behandelt (Kommas in Anführungszeichen, internationale Zeichen usw.). Ich habe viele Leute glauben gemacht, dass sie eine gute Regex haben, nur um in der Produktion seltsame Fälle zu finden.

Wenn Ihr Detail-Array unbegrenzt (oder sogar mit einer großen Grenze) wachsen kann, sollten Sie diese Änderung unabhängig von Ihren JSON-Parser-Beschränkungen oder dem Lese-/Schreibverhältnis vornehmen, da Sie das Limit schließlich überschreiten.

+0

Danke larry Sie sind zu 100% korrekt. Die Regex wird nicht mit allen Möglichkeiten umgehen können. Aber das ist noch nicht meine Sache. Was das Speichern eines Details als Dokument betrifft, ist das das nächste Problem, das ich lösen muss.Wir möchten im Laufe der Zeit mehr zum Detail-Array hinzufügen, aber da wir so viele Daten haben, hat es möglicherweise mehr Dokumente als eine Sammlung erlaubt. Also haben wir uns entschieden, im Detail auf No-Add zu verzichten. Wenn wir nun jedes Element im Detail als Dokument speichern, tritt ein Performance-Problem auf, da wir Hunderte von Dokumenten benötigen, wenn wir das Detail verwenden müssen. – urlreader

+0

Ich empfehle dringend, jetzt partitionierte Sammlungen zu verwenden, damit Sie sich keine Sorgen darüber machen müssen, dass es sich um eine einzelne Sammlung handelt. Ich würde nicht annehmen, dass es langsamer wäre, die Details zu sammeln, wenn sie alle in ihrem eigenen Dokument sind. Sicher, es dauert eine Hin- und Rückfahrt für den Header und ein anderes für die Details, aber das gesamte Lesen ist vielleicht nicht so groß wie Sie denken. Außerdem werden die Schreibvorgänge auf diese Weise viel schneller, besonders wenn Sie später Details hinzufügen. –