Lambdaカクテル

京都在住Webエンジニアの日記です

JSONをMessagePackにしてから圧縮するとどのくらい短くできるか(1/3になった)

こういう記事を読んだ。

blog.utgw.net

URLにデータを載っける発想は面白い。せっかくなのでMessagePackにしたついでにzstdとかで圧縮してからBase64エンコードしたほうが小さくなるのではないかと思った。

また、最初からJSONを圧縮したほうが小さくなる可能性もあるので、つまり以下のパターンを考えられる。

  • JSONをBase64エンコードする
  • JSONをMessagePackに変換してからBase64エンコードする
  • JSONをzstdなどで圧縮してからBase64エンコードする
  • JSONをMessagePackに変換してからzstdなどで圧縮してからBase64エンコードする

せっかくなのでマトリックステストしよう。

元データ

元記事からデータを拝借する。実験するときには忘れてたけど、実際はコンパクトな形式で運用する。またtrailing commaは実際は取り除く。

[
  {"price":100,"label":"","createdAt":1681602213424},
  {"price":100,"label":"","createdAt":1681602213424},
  {"price":100,"label":"","createdAt":1681602213424},
]
echo "$JSON" | wc -c
166
echo "$JSON" | jq -c | wc -c
155

テストする

JSONからMessagePackに変換する便利ツールとしてmsgpack-toolsというコマンドラインツールがあるのでこれを使う。

github.com

先に結果のプロットだけ示すとこうなった。

考察

MessagePackを経由しなくてもJSONを圧縮するだけで十分な効果が得られるが、MessagePackを通すと確実にさらに小さくできることがわかった。

ブラウザ上実行が可能な圧縮方法については詳しくないが、まあだいたいのアルゴリズムはやろうと思えばブラウザ上で動作させられるし、なんならRustからWASMを経由して高速圧縮といった芸当も可能だと思う。

元記事のデータの性質上、繰り返し構造がよく出現するので圧縮アルゴリズムの得意分野にヒットしたのかもしれない。

走らせたコード

以下のテストコードを走らせてサイズがどうなるか確認した。

#!/bin/sh

JSON='[
  {"price":100,"label":"","createdAt":1681602213424},
  {"price":100,"label":"","createdAt":1681602213424},
  {"price":100,"label":"","createdAt":1681602213424}
]
'

echo "# raw"
echo "$JSON" | jq -c
echo "$JSON" | jq -c | wc -c

echo "# base64"
# -w 0を使い、改行を阻止する
echo "$JSON" | base64 -w 0
echo
echo "$JSON" | base64 -w 0 | wc -c

echo "# mp + b64"
echo "$JSON" | json2msgpack | base64 -w 0
echo
echo "$JSON" | json2msgpack | base64 -w 0 | wc -c

echo "# zstd + b64"
echo "$JSON" | zstd | base64 -w 0
echo
echo "$JSON" | zstd | base64 -w 0 | wc -c

echo "# gz + b64"
echo "$JSON" | gzip | base64 -w 0
echo
echo "$JSON" | gzip | base64 -w 0 | wc -c

echo "# deflate + b64"
echo "$JSON" | openssl zlib | base64 -w 0
echo
echo "$JSON" | openssl zlib | base64 -w 0 | wc -c

echo "# brotli + b64"
echo "$JSON" | brotli | base64 -w 0
echo
echo "$JSON" | brotli | base64 -w 0 | wc -c

echo "# mp + zstd + b64"
echo "$JSON" | json2msgpack | zstd | base64 -w 0
echo
echo "$JSON" | json2msgpack | zstd | base64 -w 0 | wc -c

echo "# mp + gz + b64"
echo "$JSON" | json2msgpack | gzip | base64 -w 0
echo
echo "$JSON" | json2msgpack | gzip | base64 -w 0 | wc -c

echo "# mp + deflate + b64"
echo "$JSON" | json2msgpack | openssl zlib | base64 -w 0
echo
echo "$JSON" | json2msgpack | openssl zlib | base64 -w 0 | wc -c

echo "# mp + brotli + b64"
echo "$JSON" | json2msgpack | brotli | base64 -w 0
echo
echo "$JSON" | json2msgpack | brotli | base64 -w 0 | wc -c

以下のような結果になった。

# raw
[{"price":100,"label":"","createdAt":1681602213424},{"price":100,"label":"","createdAt":1681602213424},{"price":100,"label":"","createdAt":1681602213424}]
155
# base64
WwogIHsicHJpY2UiOjEwMCwibGFiZWwiOiIiLCJjcmVhdGVkQXQiOjE2ODE2MDIyMTM0MjR9LAogIHsicHJpY2UiOjEwMCwibGFiZWwiOiIiLCJjcmVhdGVkQXQiOjE2ODE2MDIyMTM0MjR9LAogIHsicHJpY2UiOjEwMCwibGFiZWwiOiIiLCJjcmVhdGVkQXQiOjE2ODE2MDIyMTM0MjR9Cl0KCg==
224
# mp + b64
k4OlcHJpY2VkpWxhYmVsoKljcmVhdGVkQXTPAAABh4dNdjCDpXByaWNlZKVsYWJlbKCpY3JlYXRlZEF0zwAAAYeHTXYwg6VwcmljZWSlbGFiZWygqWNyZWF0ZWRBdM8AAAGHh012MA==
140
# zstd + b64
KLUv/QRYHQIAtANbCiAgeyJwcmljZSI6MTAwLCJsYWJlbCI6IiIsImNyZWF0ZWRBdCI6MTY4MTYwMjIxMzQyNH0sCl0KCgEAh3KqoDXhgVw=
108
# gz + b64
H4sIAAAAAAAAA4vmUlCoViooykxOVbIyNDDQUcpJTErNUbJSUtJRSi5KTSxJTXEsAUqZWRiaGRgZGRqbGJnU6tBRF1csFxcAUxgViKYAAAA=
108
# deflate + b64
eJyL5lJQqFYqKMpMTlWyMjQw0FHKSUxKzVGyUlLSUUouSk0sSU1xLAFKmVkYmhkYGRkamxiZ1OrQURdXLBcXAH1mK5I=
92
# brotli + b64
H6UAwI3UYs0Z7qRz6y+JPRM4Mma1ZGdpNmfotCiz1BKhIpm0YfYYmIpwviHpFKesS/VUR6ZGZX234AA=
80
# mp + zstd + b64
KLUv/QRYXQEANAKTg6VwcmljZWSlbGFiZWygqWNyZWF0ZWRBdM8AAAGHh012MAEAi4KqJ4ccduU=
76
# mp + gz + b64
H4sIAAAAAAAAA5vcvLSgKDM5NWVpTmJSas6ClclFqYklqSmOJecZGBjb233LDKihAgC9FD/9ZwAAAA==
80
# mp + deflate + b64
eJyb3Ly0oCgzOTVlaU5iUmrOgpXJRamJJakpjiXnGRgY29t9ywyooQIA3fkqVQ==
64
# mp + brotli + b64
H2YAaEYn99ACbZ5YgC2QoHkgSZBRPUklmxylPqM6N2G7nYNz8QeoSoMF
56
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?