Zstd can use dictionaries to improve compression ratio of small data. Traditionally small files don't compress well because there is very little repetition in a single sample, since it is small. But, if you are compressing many similar files, like a bunch of JSON records that share the same structure, you can train a dictionary on ahead of time on some samples of these files. Then, zstd can use the dictionary to find repetitions that are present across samples. This can vastly improve compression ratio.
Dictionaries are useful when compressing many small files that are similar. The larger a file is, the less benefit a dictionary will have. Generally, we don't expect dictionary compression to be effective past 100KB. And the smaller a file is, the more we would expect the dictionary to help.
Simply pass the dictionary to the zstd compressor with CCtx_loadDictionary. The same dictionary must then be passed to the decompressor, using
DCtx_loadDictionary. There are other more advanced functions that allow selecting some options, see zstd.h for complete documentation.
A zstd dictionary has two pieces: Its header, and its content. The header contains a magic number, the dictionary ID, and entropy tables. These entropy tables allow zstd to save on header costs in the compressed file, which really matters for small data. The content is just bytes, which are repeated content that is common across many samples.
A raw content dictionary is just bytes. It doesn't have a zstd dictionary header, a dictionary ID, or entropy tables. Any buffer is a valid raw content dictionary.
Gather samples from your use case. These samples should be similar to each other. If you have several use cases, you could try to train one dictionary per use case.
Pass those samples to trainFromBuffer and that will train your dictionary. There are a few advanced versions of this function, but this is a great
starting point. If you want to further tune your dictionary you could try optimizeTrainFromBuffer_cover. If that is too slow you can try
optimizeTrainFromBuffer_fastCover.
If the dictionary training function fails, that is likely because you either passed too few samples, or a dictionary would not be effective for your data. Look at the messages that the dictionary trainer printed, if it doesn't say too few samples, then a dictionary would not be effective.
A reasonable dictionary size, the dictBufferCapacity, is about 100KB. The zstd CLI defaults to a 110KB dictionary. You likely don't need a
dictionary larger than that. But, most use cases can get away with a smaller dictionary. The advanced dictionary builders can automatically shrink the
dictionary for you, and select a the smallest size that doesn't hurt compression ratio too much. See the shrinkDict parameter. A smaller
dictionary can save memory, and potentially speed up compression.
We generally recommend passing ~100x the size of the dictionary in samples. A few thousand should suffice. Having too few samples can hurt the dictionaries effectiveness. Having more samples will only improve the dictionaries effectiveness. But having too many samples can slow down the dictionary builder.
Simply train a dictionary and try it out. You can use zstd's built in benchmarking tool to test the dictionary effectiveness.
# Benchmark levels 1-3 without a dictionary
zstd -b1e3 -r /path/to/my/files
# Benchmark levels 1-3 with a dictionary
zstd -b1e3 -r /path/to/my/files -D /path/to/my/dictionary
You should retrain a dictionary when its effectiveness drops. Dictionary effectiveness drops as the data you are compressing changes. Generally, we do expect dictionaries to "decay" over time, as your data changes, but the rate at which they decay depends on your use case. Internally, we regularly retrain dictionaries, and if the new dictionary performs significantly better than the old dictionary, we will ship the new dictionary.
If you have a raw content dictionary, e.g. by manually constructing it, or using a third-party dictionary builder, you can turn it into a zstd
dictionary by using finalizeDictionary. You'll also have to provide some samples of the data. It will add the zstd header to the raw content, which
contains a dictionary ID and entropy tables, which will improve compression ratio, and allow zstd to write the dictionary ID into the frame, if you so
choose.
No! You can construct dictionary content however you please, it is just bytes. It will always be valid as a raw content dictionary. If you want a zstd
dictionary, which can improve compression ratio, use finalizeDictionary.
Zstd is heavily fuzz tested, including loading fuzzed dictionaries, so zstd should never crash, or access out-of-bounds memory no matter what the dictionary is. However, if an attacker can control the dictionary during decompression, they can cause zstd to generate arbitrary bytes, just like if they controlled the compressed data.
| Modifier and Type | Field and Description |
|---|---|
| public static final int | |
| public static final int |
| Access | Constructor and Description |
|---|---|
| protected |
| Modifier and Type | Method and Description |
|---|---|
| private static long | |
| public static native long | nZDICT_finalizeDictionary(long dictBuffer, long dictBufferCapacity, long dictContent, long dictContentSize, long samplesBuffer, long samplesSizes, int nbSamples, long parameters)
Unsafe version of: |
| public static native int | |
| public static native long | |
| public static native int | |
| public static native long | nZDICT_optimizeTrainFromBuffer_cover(long dictBuffer, long dictBufferCapacity, long samplesBuffer, long samplesSizes, int nbSamples, long parameters)
Unsafe version of: |
| public static native long | nZDICT_optimizeTrainFromBuffer_fastCover(long dictBuffer, long dictBufferCapacity, long samplesBuffer, long samplesSizes, int nbSamples, long parameters)
Unsafe version of: |
| public static native long | nZDICT_trainFromBuffer(long dictBuffer, long dictBufferCapacity, long samplesBuffer, long samplesSizes, int nbSamples)
Unsafe version of: |
| public static native long | nZDICT_trainFromBuffer_cover(long dictBuffer, long dictBufferCapacity, long samplesBuffer, long samplesSizes, int nbSamples, long parameters)
Unsafe version of: |
| public static native long | nZDICT_trainFromBuffer_fastCover(long dictBuffer, long dictBufferCapacity, long samplesBuffer, long samplesSizes, int nbSamples, long parameters)
Unsafe version of: |
| public static long | Returns: size of dictionary stored intodictBuffer (≤ dictBufferCapacity) or an error code, which can be tested with isError.Given a custom content as a basis for dictionary, and a set of samples, finalize dictionary by adding headers and statistics. |
| public static int | Returns: zero if error (not a valid dictionary)Extracts |
| public static String | |
| public static boolean | |
| public static long | Returns: size of dictionary stored intodictBuffer (≤ dictBufferCapacity) or an error code, which can be tested with isError. On success
*parameters contains the parameters selected.The same requirements as |
| public static long | Returns: size of dictionary stored intodictBuffer (≤ dictBufferCapacity) or an error code, which can be tested with isError. On success
*parameters contains the parameters selected.The same requirements as |
| public static long | Returns: size of dictionary stored intodictBuffer (≤ dictBufferCapacity) or an error code, which can be tested with isError.Train a dictionary from an array of samples. |
| public static long | Returns: size of dictionary stored intodictBuffer (≤ dictBufferCapacity) or an error code, which can be tested with isError.Train a dictionary from an array of samples using the COVER algorithm. |
| public static long | Returns: size of dictionary stored intodictBuffer (≤ dictBufferCapacity) or an error code, which can be tested with isError.Train a dictionary from an array of samples using a modified version of COVER algorithm. |
| ZDICT_CONTENTSIZE_MIN | back to summary |
|---|---|
| public static final int ZDICT_CONTENTSIZE_MIN | |
| ZDICT_DICTSIZE_MIN | back to summary |
|---|---|
| public static final int ZDICT_DICTSIZE_MIN | |
| Zdict | back to summary |
|---|---|
| protected Zdict() | |
| getSamplesBufferSize | back to summary |
|---|---|
| private static long getSamplesBufferSize(PointerBuffer samplesSizes) | |
| nZDICT_finalizeDictionary | back to summary |
|---|---|
| public static native long nZDICT_finalizeDictionary(long dictBuffer, long dictBufferCapacity, long dictContent, long dictContentSize, long samplesBuffer, long samplesSizes, int nbSamples, long parameters) Unsafe version of: | |
| nZDICT_getDictID | back to summary |
|---|---|
| public static native int nZDICT_getDictID(long dictBuffer, long dictSize) Unsafe version of: | |
| nZDICT_getErrorName | back to summary |
|---|---|
| public static native long nZDICT_getErrorName(long errorCode) | |
| nZDICT_isError | back to summary |
|---|---|
| public static native int nZDICT_isError(long errorCode) | |
| nZDICT_optimizeTrainFromBuffer_cover | back to summary |
|---|---|
| public static native long nZDICT_optimizeTrainFromBuffer_cover(long dictBuffer, long dictBufferCapacity, long samplesBuffer, long samplesSizes, int nbSamples, long parameters) Unsafe version of: | |
| nZDICT_optimizeTrainFromBuffer_fastCover | back to summary |
|---|---|
| public static native long nZDICT_optimizeTrainFromBuffer_fastCover(long dictBuffer, long dictBufferCapacity, long samplesBuffer, long samplesSizes, int nbSamples, long parameters) Unsafe version of: | |
| nZDICT_trainFromBuffer | back to summary |
|---|---|
| public static native long nZDICT_trainFromBuffer(long dictBuffer, long dictBufferCapacity, long samplesBuffer, long samplesSizes, int nbSamples) Unsafe version of: | |
| nZDICT_trainFromBuffer_cover | back to summary |
|---|---|
| public static native long nZDICT_trainFromBuffer_cover(long dictBuffer, long dictBufferCapacity, long samplesBuffer, long samplesSizes, int nbSamples, long parameters) Unsafe version of: | |
| nZDICT_trainFromBuffer_fastCover | back to summary |
|---|---|
| public static native long nZDICT_trainFromBuffer_fastCover(long dictBuffer, long dictBufferCapacity, long samplesBuffer, long samplesSizes, int nbSamples, long parameters) Unsafe version of: | |
| ZDICT_finalizeDictionary | back to summary |
|---|---|
| public static long ZDICT_finalizeDictionary(ByteBuffer dictBuffer, ByteBuffer dictContent, ByteBuffer samplesBuffer, PointerBuffer samplesSizes, ZDICTParams parameters) Given a custom content as a basis for dictionary, and a set of samples, finalize dictionary by adding headers and statistics. Samples must be stored concatenated in a flat buffer Notes:
| |
| ZDICT_getDictID | back to summary |
|---|---|
| public static int ZDICT_getDictID(ByteBuffer dictBuffer) Extracts
| |
| ZDICT_getErrorName | back to summary |
|---|---|
public static String ZDICT_getErrorName(long errorCode)
| |
| ZDICT_isError | back to summary |
|---|---|
public static boolean ZDICT_isError(long errorCode)
| |
| ZDICT_optimizeTrainFromBuffer_cover | back to summary |
|---|---|
| public static long ZDICT_optimizeTrainFromBuffer_cover(ByteBuffer dictBuffer, ByteBuffer samplesBuffer, PointerBuffer samplesSizes, ZDICTCoverParams parameters) The same requirements as This function tries many parameter combinations and picks the best parameters.
Note
| |
| ZDICT_optimizeTrainFromBuffer_fastCover | back to summary |
|---|---|
| public static long ZDICT_optimizeTrainFromBuffer_fastCover(ByteBuffer dictBuffer, ByteBuffer samplesBuffer, PointerBuffer samplesSizes, ZDICTFastCoverParams parameters) The same requirements as This function tries many parameter combinations (specifically,
Note
| |
| ZDICT_trainFromBuffer | back to summary |
|---|---|
| public static long ZDICT_trainFromBuffer(ByteBuffer dictBuffer, ByteBuffer samplesBuffer, PointerBuffer samplesSizes) Train a dictionary from an array of samples. Redirect towards Samples must be stored concatenated in a single flat buffer The resulting dictionary will be saved into Note
Tips:
| |
| ZDICT_trainFromBuffer_cover | back to summary |
|---|---|
| public static long ZDICT_trainFromBuffer_cover(ByteBuffer dictBuffer, ByteBuffer samplesBuffer, PointerBuffer samplesSizes, ZDICTCoverParams parameters) Train a dictionary from an array of samples using the COVER algorithm. Samples must be stored concatenated in a single flat buffer The resulting dictionary will be saved into Note
Tips:
| |
| ZDICT_trainFromBuffer_fastCover | back to summary |
|---|---|
| public static long ZDICT_trainFromBuffer_fastCover(ByteBuffer dictBuffer, ByteBuffer samplesBuffer, PointerBuffer samplesSizes, ZDICTFastCoverParams parameters) Train a dictionary from an array of samples using a modified version of COVER algorithm. Samples must be stored concatenated in a single flat buffer Note
Tips: In general, a reasonable dictionary has a size of
| |