In [194]:
import pandas as pd
import matplotlib.pyplot as plt

Preconditions

In this analysis we use report by the python script serde.py (which is located in the repository) executed with such parameters:

python ./serde.py -n=1000 -r=10 --input_path=./data/data_1.json --output_path=./reports/report.csv

Incoming dataset: data_1.json - randomly generated JSON file with demographic data.

Number of executions: 1000 - more on that here

Number of repeats: 10 - more on that here

In [195]:
dt = pd.read_csv("./reports/report.csv")
In [196]:
dt['compression rate'] = 100.0 - dt['size']/dt['size'].max() * 100
dt['serialization_perf_rate'] = dt['serialize']/dt['serialize'].max() * 100
dt['deserialization_perf_rate'] = dt['deserialize']/dt['deserialize'].max() * 100
dt
Out[196]:
protocol compression size serialize deserialize compression rate serialization_perf_rate deserialization_perf_rate
0 json none 1847 0.007438 0.012850 0.000000 2.397034 24.238534
1 json bz2 443 0.223569 0.046816 76.015160 72.047666 88.308188
2 json zlib 423 0.035219 0.018151 77.097997 11.349695 34.236843
3 json snappy 708 0.010927 0.014115 61.667569 3.521453 26.624665
4 msgpack none 1648 0.006349 0.006947 10.774228 2.046000 13.103128
5 msgpack bz2 552 0.304665 0.048315 70.113698 98.181509 91.134417
6 msgpack zlib 473 0.045302 0.012471 74.390904 14.598987 23.524499
7 msgpack snappy 590 0.009955 0.008410 68.056308 3.208049 15.863047
8 cbor none 1694 0.006143 0.009993 8.283703 1.979558 18.850118
9 cbor bz2 537 0.310308 0.053015 70.925826 100.000000 100.000000
10 cbor zlib 482 0.043570 0.015548 73.903628 14.040746 29.327289
11 cbor snappy 607 0.008844 0.011480 67.135896 2.850100 21.654341
12 proto none 234 0.008248 0.003437 87.330807 2.658142 6.484056
13 proto bz2 337 0.095620 0.021414 81.754196 30.814634 40.392823
14 proto zlib 245 0.026605 0.004238 86.735246 8.573606 7.994201
15 proto snappy 238 0.008849 0.004099 87.114239 2.851664 7.732734

Size and serialization time

In [197]:
ax = dt.plot(x='size', y='serialize', kind='scatter', grid=True, figsize=(15,10))
for line in range(0, dt.shape[0]):
    ax.annotate(dt.loc[line]['protocol'] + "+" + dt.loc[line]['compression'],(dt.loc[line]['size'], dt.loc[line]['serialize']))
plt.show()

The left down corner is an ideal combination. The protobuf without serialization is on the same level as protobuf + snappy compression.

Size and deserialization time

In [198]:
ax = dt.plot(x='size', y='deserialize', kind='scatter', grid=True, figsize=(15,10))
for line in range(0, dt.shape[0]):
    ax.annotate(dt.loc[line]['protocol'] + "+" + dt.loc[line]['compression'],(dt.loc[line]['size'], dt.loc[line]['deserialize']))
plt.show()

Again, protobuf without compression works best for our data record.

Results

For our data struct, which is a map of counters, protobuf without additional compression is a winner.

Protobuf effectively reduces messages which contain only integer values, but when values are strings it doesn't do anything with them. In this case combination of protobuf/msgpack with zlib/snappy may be a solution.