Author: Mikhail Khoroshavin aka "XopMC"
Build compact XOR filters from massive hex datasets
From raw text dumps to clean release-ready filter files, with flexible size profiles for real batch workloads.
XorFilter is a command-line tool that builds binary XOR filter files from text inputs where each line contains a hex-encoded value.
It is built for people who work with big lists, long-running batch jobs, and data pipelines where you want the final result to stay compact, fast to query, and easy to regenerate.
Instead of forcing one rigid output profile, XorFilter lets you choose how aggressively you want to shrink the result. You can start with a straightforward default build, switch to tighter compression when file size matters, verify the result after generation, and package the same workflow for both Windows and Linux.
The current implementation focuses on:
- deterministic filter generation;
- lower peak memory usage during in-memory construction;
- several output density profiles;
- simple CLI flow for one file or many shards;
- practical release packaging for Windows and Linux.
- Uses a low-memory 4-wise XOR binary fuse filter implementation.
- Accepts one or more input files with one hex value per line.
- Supports standard, compressed, ultra-compressed, and hyper-compressed output modes.
- Can verify the finished filter after build with
-check. - Can split the source text stream into numbered chunk files with
-txt. - Fits both quick local runs and larger automated build pipelines.
The builder accepts several practical line formats out of the box:
- plain 40-character hex lines;
0x-prefixed hex lines;- lines that start with
02,03, or04, which are normalized automatically before the filter key is derived.
Example input:
00112233445566778899aabbccddeeff00112233
0x89abcdef0123456789abcdef0123456789abcdef
02fedcba9876543210fedcba9876543210fedcba98
| Mode | Flag | Extension | Notes |
|---|---|---|---|
| Uncompressed | default | .xor_u |
Stores the default 32-bit fingerprint format |
| Compressed | -compress |
.xor_c |
Lower output size, very low false-positive rate |
| Ultra compressed | -ultra |
.xor_uc |
Smaller output, higher false-positive rate than -compress |
| Hyper compressed | -hyper |
.xor_hc |
Smallest output, highest false-positive rate among supported modes |
Approximate false-positive rates used in the CLI help:
-compress:0.0000001%-ultra:0.001444%-hyper:0.3556%
Recommended environment:
- Visual Studio 2022
- MSBuild
- Clang/LLVM toolset configured in the solution
Build command:
msbuild hex_to_xor.sln /p:Configuration=Release /p:Platform=x64Output:
x64\Release\hex_to_xor.exe
Expected toolchain:
clang++make- OpenMP runtime
- Intel TBB development package
Example dependency install on Ubuntu:
sudo apt update
sudo apt install -y clang make libomp-dev libtbb-devBuild command:
makeOutput:
./build/hex_to_xor
| Argument | Description | Details |
|---|---|---|
-i <file> |
Adds an input file | Can be specified multiple times |
-o <folder> |
Writes output files to a custom directory | If omitted, output is written next to the current working directory |
-check |
Verifies the populated filter | Re-checks that inserted keys are found |
-compress |
Builds compressed filters | Produces .xor_c files |
-ultra |
Builds ultra-compressed filters | Produces .xor_uc files |
-hyper |
Builds hyper-compressed filters | Produces .xor_hc files |
-mini |
Uses the smaller large-filter preset | About 2,147,483,644 entries per filter file; useful when you want to keep peak RAM lower |
-max |
Uses the large-filter preset | About 8,589,934,584 entries per filter file; can require very large amounts of RAM |
-max2 |
Uses the largest preset | About 17,179,869,168 entries per filter file; intended only for machines with extreme RAM capacity |
-txt |
Saves numbered split text chunks while processing | Useful when the source stream is large |
-force |
Uses the conservative duplicate-removal path | Higher CPU cost, avoids the fast path |
-mini, -max, and -max2 are not just "make the filter bigger" switches.
They define the maximum batch size that is accumulated before the current filter file is built and flushed. In practice, that means they affect two things at the same time:
- how large one output filter file can become;
- how much RAM the tool may need while it is collecting, sorting, deduplicating, and building that batch.
This is the practical way to think about them:
-miniis the safer choice when you want to limit peak RAM. The tool will flush smaller batches, which usually means more numbered output files, but each batch is easier to build. Typical output size is about9 GBin the default mode and about4.5 GBin ultra mode.-maxlets one filter file grow much larger. This can reduce the number of output files, but it may require more than256 GB RAMon very large runs. Typical output size is about36 GBin the default mode and about18 GBin ultra mode.-max2is the extreme preset. It targets the largest per-file batch size and may require more than512 GB RAMon very large runs. Typical output size is about72 GBin the default mode and about36 GBin ultra mode.
If your goal is to keep memory under control, start with -mini. If your goal is to produce fewer, larger filter files and your machine has enough RAM, move up to -max or -max2.
| If your machine looks like this | Main goal | Recommended flag | Why |
|---|---|---|---|
32-64 GB RAM |
Stay on the safe side | -mini |
Keeps the in-memory batch smaller and reduces the risk of running out of memory |
128-256 GB RAM |
Build larger files without going extreme | -max |
Good when you want fewer output files and the machine can handle a much bigger batch |
512+ GB RAM |
Push one filter file as large as possible | -max2 |
Best suited for very large runs on machines built for huge memory workloads |
| Not sure about available headroom | Start conservatively | -mini |
It is the safest first pass before moving up to more aggressive presets |
Rule of thumb: Start with
-mini. Move to-maxonly after you confirm that the machine has real RAM headroom. Use-max2only on dedicated high-memory systems where huge in-memory batches are expected.
The tool derives the file name from the first input file and appends a sequence number plus the mode extension.
Examples:
keys.txt->keys_0.xor_ukeys.txt+-compress->keys_0.xor_ckeys.txt+-ultra->keys_0.xor_uckeys.txt+-hyper->keys_0.xor_hc
If -txt is enabled, split text files are created with names similar to:
keys_split_0.txtkeys_split_1.txt
x64\Release\hex_to_xor.exe -i .\data\hashes.txtLinux:
./build/hex_to_xor -i ./data/hashes.txtx64\Release\hex_to_xor.exe -i .\data\hashes.txt -compressx64\Release\hex_to_xor.exe -i .\data\hashes.txt -ultrax64\Release\hex_to_xor.exe -i .\data\hashes.txt -hyperx64\Release\hex_to_xor.exe -i .\data\hashes.txt -compress -checkx64\Release\hex_to_xor.exe -i .\data\hashes.txt -compress -o .\outLinux:
./build/hex_to_xor -i ./data/hashes.txt -compress -o ./outx64\Release\hex_to_xor.exe -i .\data\part1.txt -i .\data\part2.txt -i .\data\part3.txtx64\Release\hex_to_xor.exe -i .\data\hashes.txt -txt -o .\outx64\Release\hex_to_xor.exe -i .\data\hashes.txt -compress -mini
x64\Release\hex_to_xor.exe -i .\data\hashes.txt -compress -max-mini is the better starting point when RAM matters. -max is for machines that can afford much larger in-memory batches.
x64\Release\hex_to_xor.exe -i .\data\hashes.txt -forceThe repository includes a smoke script and validation checks so you can quickly confirm that a build still behaves as expected.
Run the smoke script after building:
powershell -ExecutionPolicy Bypass -File tests\run_smoke.ps1What it does:
- builds filters in all supported modes from a small fixture;
- compares generated files against checked-in golden files;
- compiles and runs
tests/filter_compat_tests.cppwhenclang-clis available.
The repository is prepared for two primary release packages:
| Artifact | Platform | Typical contents |
|---|---|---|
XorFilter-windows-x64.zip |
Windows | hex_to_xor.exe, README, LICENSE |
XorFilter-linux-x64.tar.gz |
Linux | hex_to_xor, README, LICENSE |
- Works well for large text-based datasets without turning the CLI flow into a maze.
- Gives you several size/accuracy trade-offs instead of a single one-size-fits-all mode.
- Lets you validate the finished result immediately with
-check. - Ships with release packaging for Windows and Linux so the same workflow can move from local experiments to distribution.
| Path | Purpose |
|---|---|
Source.cpp |
CLI, file ingestion, sorting, and filter generation flow |
xor_filter.h |
Low-memory 4-wise XOR binary fuse filter implementation |
hex_key_utils.h |
Shared helpers for input decoding and hashing |
tests/ |
Smoke tests, fixtures, and validation checks |
.github/workflows/ |
Automated CI and release workflows |
MIT License. See LICENSE.txt.
Mikhail Khoroshavin aka "XopMC"
XorFilter — это консольный инструмент для построения бинарных XOR-фильтров из текстовых входных файлов, где каждая строка содержит одно hex-значение.
Он рассчитан на людей, которые работают с большими списками, тяжёлыми batch-задачами и data pipeline’ами, где на выходе хочется получить компактный, быстрый и удобный для повторной сборки результат.
XorFilter не загоняет пользователя в один жёсткий сценарий. Можно собрать фильтр в базовом режиме, выбрать более плотный профиль, если важен размер файла, тут же проверить результат через -check, а потом использовать тот же workflow и на Windows, и на Linux.
Текущая реализация делает упор на:
- детерминированную сборку фильтров;
- уменьшенное пиковое потребление памяти во время in-memory построения;
- несколько профилей плотности и размера результата;
- простой CLI-проход для одного файла и для набора шардов;
- удобную подготовку релизов под Windows и Linux.
- Использует low-memory реализацию 4-wise XOR binary fuse filter.
- Принимает один или несколько входных файлов с одной hex-строкой на запись.
- Поддерживает стандартный, compressed, ultra-compressed и hyper-compressed режимы.
- Может проверять готовый фильтр после построения через
-check. - Может сохранять исходный поток в разбитые текстовые чанки через
-txt. - Подходит и для локальных прогонов, и для более серьёзных автоматизированных пайплайнов.
Инструмент умеет принимать несколько удобных форматов строк без лишней подготовки:
- обычные 40-символьные hex-строки;
- строки с префиксом
0x; - строки, начинающиеся с
02,03или04, которые автоматически нормализуются перед извлечением ключа.
Пример входного файла:
00112233445566778899aabbccddeeff00112233
0x89abcdef0123456789abcdef0123456789abcdef
02fedcba9876543210fedcba9876543210fedcba98
| Режим | Флаг | Расширение | Описание |
|---|---|---|---|
| Обычный | по умолчанию | .xor_u |
Базовый формат с 32-битным fingerprint |
| Сжатый | -compress |
.xor_c |
Меньше размер файла, очень низкий false-positive rate |
| Ультра-сжатый | -ultra |
.xor_uc |
Ещё меньше размер, но выше вероятность false-positive |
| Гипер-сжатый | -hyper |
.xor_hc |
Самый компактный режим, но с самой высокой вероятностью false-positive |
Ориентировочные значения false-positive rate из CLI:
-compress:0.0000001%-ultra:0.001444%-hyper:0.3556%
Рекомендуемое окружение:
- Visual Studio 2022
- MSBuild
- Clang/LLVM toolset, подключённый в solution
Команда сборки:
msbuild hex_to_xor.sln /p:Configuration=Release /p:Platform=x64Результат:
x64\Release\hex_to_xor.exe
Ожидаемый toolchain:
clang++make- OpenMP runtime
- development-пакет Intel TBB
Пример установки зависимостей на Ubuntu:
sudo apt update
sudo apt install -y clang make libomp-dev libtbb-devКоманда сборки:
makeРезультат:
./build/hex_to_xor
| Аргумент | Назначение | Подробности |
|---|---|---|
-i <file> |
Добавляет входной файл | Можно указывать несколько раз |
-o <folder> |
Сохраняет результат в выбранную папку | Если не указан, используется текущая рабочая директория |
-check |
Проверяет фильтр после построения | Повторно проверяет, что все добавленные ключи находятся |
-compress |
Строит сжатый фильтр | Создаёт .xor_c |
-ultra |
Строит ultra-compressed фильтр | Создаёт .xor_uc |
-hyper |
Строит hyper-compressed фильтр | Создаёт .xor_hc |
-mini |
Использует уменьшенный большой preset | Около 2 147 483 644 записей на один файл фильтра; полезно, если нужно держать RAM ниже |
-max |
Использует большой preset | Около 8 589 934 584 записей на один файл фильтра; может требовать очень большого объёма RAM |
-max2 |
Использует самый большой preset | Около 17 179 869 168 записей на один файл фильтра; режим для машин с экстремальным объёмом RAM |
-txt |
Сохраняет разбитые текстовые чанки во время обработки | Полезно для очень больших входов |
-force |
Включает более консервативный путь удаления дублей | Дороже по CPU, но без fast path |
-mini, -max и -max2 — это не просто переключатели вида "сделать фильтр побольше".
Они задают максимальный размер батча, который инструмент накапливает перед тем, как построить очередной файл фильтра и сбросить текущий набор. На практике эти флаги одновременно влияют на две вещи:
- насколько большим может стать один выходной файл фильтра;
- сколько ОЗУ может понадобиться инструменту во время накопления, сортировки, дедупликации и построения этого батча.
Проще всего понимать их так:
-mini— более безопасный вариант, если нужно ограничить пиковое потребление ОЗУ. Батчи будут меньше, поэтому инструмент чаще будет создавать несколько нумерованных файлов, но каждый из них легче собрать. Типичный размер результата — около9 GBв обычном режиме и около4.5 GBв ultra-режиме.-maxпозволяет сделать один файл фильтра заметно крупнее. Это уменьшает количество выходных файлов, но на очень больших прогонах может потребовать более256 GB RAM. Типичный размер результата — около36 GBв обычном режиме и около18 GBв ultra-режиме.-max2— экстремальный preset для самого большого размера батча на один файл. На очень больших прогонах может потребовать более512 GB RAM. Типичный размер результата — около72 GBв обычном режиме и около36 GBв ultra-режиме.
Если главная цель — удержать потребление памяти в разумных пределах, лучше начинать с -mini. Если цель — получить меньше, но более крупных файлов фильтра, и у машины достаточно памяти, тогда уже имеет смысл переходить к -max или -max2.
| Если машина выглядит примерно так | Главная цель | Что выбрать | Почему |
|---|---|---|---|
32-64 GB RAM |
Играть безопасно по памяти | -mini |
Уменьшает размер in-memory батча и заметно снижает риск упереться в нехватку ОЗУ |
128-256 GB RAM |
Делать более крупные файлы без экстремума | -max |
Подходит, когда хочется меньше выходных файлов и машина уже тянет гораздо более крупный батч |
512+ GB RAM |
Выжать максимально большой один файл фильтра | -max2 |
Имеет смысл для очень больших прогонов на машинах с действительно огромным объёмом памяти |
| Если не уверен в запасе памяти | Начать аккуратно | -mini |
Это самый безопасный стартовый вариант перед переходом к более агрессивным preset'ам |
Простое правило: Начинай с
-mini. Переходить на-maxстоит только после подтверждения, что у машины действительно есть запас по ОЗУ.-max2имеет смысл только на выделенных high-memory системах, где заранее ожидаются огромные in-memory батчи.
Имя берётся из первого входного файла, после чего добавляются номер и расширение режима.
Примеры:
keys.txt->keys_0.xor_ukeys.txt+-compress->keys_0.xor_ckeys.txt+-ultra->keys_0.xor_uckeys.txt+-hyper->keys_0.xor_hc
Если включён -txt, параллельно создаются файлы вида:
keys_split_0.txtkeys_split_1.txt
x64\Release\hex_to_xor.exe -i .\data\hashes.txtLinux:
./build/hex_to_xor -i ./data/hashes.txtx64\Release\hex_to_xor.exe -i .\data\hashes.txt -compressx64\Release\hex_to_xor.exe -i .\data\hashes.txt -ultrax64\Release\hex_to_xor.exe -i .\data\hashes.txt -hyperx64\Release\hex_to_xor.exe -i .\data\hashes.txt -compress -checkx64\Release\hex_to_xor.exe -i .\data\hashes.txt -compress -o .\outLinux:
./build/hex_to_xor -i ./data/hashes.txt -compress -o ./outx64\Release\hex_to_xor.exe -i .\data\part1.txt -i .\data\part2.txt -i .\data\part3.txtx64\Release\hex_to_xor.exe -i .\data\hashes.txt -txt -o .\outx64\Release\hex_to_xor.exe -i .\data\hashes.txt -compress -mini
x64\Release\hex_to_xor.exe -i .\data\hashes.txt -compress -maxЕсли RAM ограничена, лучше начинать с -mini. -max имеет смысл только на машинах, где действительно можно позволить себе очень большой in-memory батч.
x64\Release\hex_to_xor.exe -i .\data\hashes.txt -forceВ репозитории есть smoke-скрипт и проверочный набор, чтобы быстро убедиться, что сборка ведёт себя ожидаемо.
После сборки можно запустить:
powershell -ExecutionPolicy Bypass -File tests\run_smoke.ps1Что делает скрипт:
- строит фильтры во всех поддерживаемых режимах на маленькой фикстуре;
- сравнивает результаты с golden-файлами в репозитории;
- компилирует и запускает
tests/filter_compat_tests.cpp, если доступенclang-cl.
Репозиторий подготовлен под два основных релизных пакета:
| Артефакт | Платформа | Содержимое |
|---|---|---|
XorFilter-windows-x64.zip |
Windows | hex_to_xor.exe, README, LICENSE |
XorFilter-linux-x64.tar.gz |
Linux | hex_to_xor, README, LICENSE |
- Инструмент хорошо чувствует себя на больших текстовых наборах и не превращает CLI в перегруженный конструктор.
- Даёт несколько вариантов баланса между размером и точностью, а не один жёсткий режим.
- Позволяет сразу перепроверить результат через
-check. - Уже подготовлен к релизной упаковке под Windows и Linux, так что один и тот же workflow легко переносится из локальной работы в дистрибуцию.
| Путь | Назначение |
|---|---|
Source.cpp |
CLI, чтение файлов, сортировка и основной flow построения |
xor_filter.h |
Реализация low-memory 4-wise XOR binary fuse filter |
hex_key_utils.h |
Общие helper’ы для декодирования входа и hashing |
tests/ |
Smoke-тесты, фикстуры и проверочный набор |
.github/workflows/ |
Автоматические CI и release workflows |
MIT License. См. LICENSE.txt.
Mikhail Khoroshavin aka "XopMC"