Подтвердить что ты не робот

Как сделать мой JSON менее подробным?

В настоящее время я разрабатываю веб-приложение и использую JSON для запросов и ответов ajax. У меня есть область, где я возвращаю очень большой набор данных клиенту в виде массива из более чем 10000 объектов. Здесь часть примера (его было несколько упрощено):

"schedules": [
        {
            "codePractice": 35,
            "codeScheduleObject": 576,
            "codeScheduleObjectType": "",
            "defaultCodeScheduleObject": 12,
            "name": "Dr. 1"
        },
        {
            "codePractice": 35,
            "codeScheduleObject": 169,
            "codeScheduleObjectType": "",
            "defaultCodeScheduleObject": 43,
            "name": "Dr. 2"
        },
        {
            "codePractice": 35,
            "codeScheduleObject": 959,
            "codeScheduleObjectType": "",
            "defaultCodeScheduleObject": 76,
            "name": "Dr. 3"
        }
    ]

Как вы можете себе представить, с очень большим количеством объектов в этом массиве размер ответа JSON может быть довольно большим.

Мой вопрос в том, есть ли синтаксис/парсер JSON, который преобразует массив "schedules", чтобы выглядеть примерно так, как строка JSON:

"schedules": [
    ["codePractice", "codeScheduleObject", "codeLogin", "codeScheduleObjectType", "defaultCodeScheduleObject","name"],
    [35, 576, "", 12, "Dr. 1"],
    [35, 169, "", 43, "Dr. 2"],
    [35, 959, "", 76, "Dr. 3"],
]

т.е. что в начале массива "schedules" будет массив, в котором хранятся ключи объектов этого массива, и все остальные массивы контейнеров будут удерживать значения.

Я мог бы, если бы захотел, сделать преобразование на сервере и проанализировать его на клиенте, но мне интересно, есть ли стандартная библиотека для синтаксического анализа/стробирования большого JSON?

Я мог бы также запустить его через minifier, но я бы хотел сохранить ключи, которые у меня есть, поскольку они дают некоторый контекст в приложении.

Я также надеюсь, что вы можете критиковать мой подход здесь или предложить альтернативы?

4b9b3361

Ответ 1

HTTP-сжатие (т.е. gzip или deflate) уже делает именно это. Повторяющиеся шаблоны, такие как ваши JSON-ключи, заменяются токенами, так что подробный шаблон должен появляться только один раз для каждой передачи.

Ответ 2

Вот статья, в которой вы многое делаете:

http://stevehanov.ca/blog/index.php?id=104

На первый взгляд, похоже, что ваш пример будет сжиматься до следующего после первого шага алгоритма, который на самом деле будет работать над ним на последующих шагах):

{
    "templates": [ 
        ["codePractice", "codeScheduleObject", "codeScheduleObjectType", "defaultCodeScheduleObject", "name"] 
    ],
    "values": [ 
        { "type": 1, "values": [ 35, 576, "", 12, "Dr. 1" ] },
        { "type": 1, "values": [ 35, 169, "", 43, "Dr. 2" ] },
        { "type": 1, "values": [ 35, 959, "", 76, "Dr. 3" ] }
    ]
}

Вы уже можете увидеть преимущество алгоритма. Здесь конечный выход после запуска через компрессор:

{
    "f" : "cjson",
    "t" : [
              [0,"schedules"],
              [0,"codePractice","codeScheduleObject","codeScheduleObjectType","defaultCodeScheduleObject","name"]
          ],
    "v" : {
        "" : [ 1, [
                { "" : [2, 35, 576, "", 12, "Dr. 1"] },
                { "" : [2, 35, 169, "", 43, "Dr. 2"] },
                { "" : [2, 35, 959, "", 76, "Dr. 3"] }
            ]
        ]
    }
}

Очевидно, можно увидеть улучшение, если у вас несколько тысяч записей. Выход по-прежнему доступен для чтения, но я думаю, что другие ребята тоже правы: хороший алгоритм сжатия будет удалять блоки текста, которые повторяются в любом случае...

Ответ 3

Не ответ, но дать приблизительную оценку "сбережений" на основе 10 тыс. записей и некоторых фиктивных данных:-) Это в ответ на комментарий, который я разместил. Будет ли добавленная сложность сделать подход, основанный на схеме?

"Это зависит".

Этот С# является LINQPad и готов к тестированию/модификации:

string LongTemplate (int n1, int n2, int n3, string name) {
    return string.Format(@"
            {{
                ""codePractice"": {0},
                ""codeScheduleObject"": {1},
                ""codeScheduleObjectType"": """",
                ""defaultCodeScheduleObject"": {2},
                ""name"": ""Dr. {3}""
            }}," + "\n", n1, n2, n3, name);
}

string ShortTemplate (int n1, int n2, int n3, string name) {
    return string.Format("[{0}, {1}, \"\", {2}, \"Dr. {3}\"],\n",
        n1, n2, n3, name);
}

string MinTemplate (int n1, int n2, int n3, string name) {
    return string.Format("[{0},{1},\"\",{2},\"Dr. {3}\"],",
        n1, n2, n3, name);
}

long GZippedSize (string s) {
    var ms = new MemoryStream();
    using (var gzip = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress, true))
    using (var sw = new StreamWriter(gzip)) {
        sw.Write(s);
    }
    return ms.Position;
}

void Main()
{
    var r = new Random();
    var l = new StringBuilder();
    var s = new StringBuilder();
    var m = new StringBuilder();
    for (int i = 0; i < 10000; i++) {
        var n1 = r.Next(10000);
        var n2 = r.Next(10000);
        var n3 = r.Next(10000);

        var name = "bogus" + r.Next(50);
        l.Append(LongTemplate(n1, n2, n3, name));
        s.Append(ShortTemplate(n1, n2, n3, name));
        m.Append(MinTemplate(n1, n2, n3, name));
    }

    var lc = GZippedSize(l.ToString());
    var sc = GZippedSize(s.ToString());
    var mc = GZippedSize(s.ToString());
    Console.WriteLine(string.Format("Long:\tNormal={0}\tGZip={1}\tCompressed={2:P}", l.Length, lc, (float)lc / l.Length));
    Console.WriteLine(string.Format("Short:\tNormal={0}\tGZip={1}\tCompressed={2:P}", s.Length, sc, (float)sc / s.Length));
    Console.WriteLine(string.Format("Min:\tNormal={0}\tGZip={1}\tCompressed={2:P}", m.Length, mc, (float)mc / m.Length));
    Console.WriteLine(string.Format("Short/Long\tRegular={0:P}\tGZip={1:P}",
        (float)s.Length / l.Length, (float)sc / lc));
    Console.WriteLine(string.Format("Min/Long\tRegular={0:P}\tGZip={1:P}",
        (float)m.Length / l.Length, (float)mc / lc));
}

Мои результаты:

Long:  Normal=1754614  GZip=197053  Compressed=11.23 %
Short:  Normal=384614  GZip=128252  Compressed=33.35 %
Min:  Normal=334614  GZip=128252  Compressed=38.33 %
Short/Long  Regular=21.92 %  GZip=65.09 %
Min/Long  Regular=19.07 %  GZip=65.09 %

Вывод:

  • Самая большая экономия - использовать GZIP (лучше, чем просто использовать schema'ize).
  • GZIP + schema'ized будет наименьшим в целом.
  • С GZIP нет смысла использовать обычный мини-ридер JavaScript (в этом случае).
  • Используйте GZIP (например, DEFLATE); он очень хорошо работает на повторяющемся структурированном тексте (900% сжатие на нормальном!).

Счастливое кодирование.

Ответ 5

Для записи, я делаю именно это в php. Его список объектов из базы данных.

$comp=base64_encode(gzcompress(json_encode($json)));

json: строка (длина 22501)

gz Сжатый = строка (711), но его двоичный формат.

gz сжатый + base64 = строка (948) его текстовый формат.

Таким образом, его значительно меньше, используя долю секунды.