Discovering frequent boilerplate and duplicate fragments in large-scale text datasets
C++
1
34 commits
updated Oct 12, 2026
This repository contains the source code and benchmark framework accompanying the paper:
BloomSpan: Memory-Efficient Maximal Frequent Substring Mining for Large-Scale Text Rauf Aliev, Joeran Beel — University of Siegen, Germany
The full paper is available in paper/bloomspan.pdf.
BloomSpan is an algorithm for mining Maximal Contiguous Frequent Phrases (MCFPs) from large text corpora. MCFPs are strictly contiguous token sequences whose document-support meets a minimum threshold — unlike general Sequential Pattern Mining, no gaps are permitted.
BloomSpan combines a Counting Bloom Filter for probabilistic frequency estimation with prioritized seed generation and depth-first expansion directly on the corpus, avoiding recursive projected databases. Key properties:
BloomSpan operates in four phases:
bloomspan/
├── corpus-miner-java/ # Java benchmark framework (primary, used in paper evaluation)
│ ├── src/ # Source code for all algorithms
│ ├── build.sh # Build script
│ └── test_docs/ # Small test corpus (3 documents)
├── corpus-miner/ # C++ implementation (prototype)
│ ├── _ours/ # BloomSpan C++ implementation
│ ├── bide/ # BIDE+ implementation
│ ├── Makefile # Build with `make`
│ └── process_results_csv.py # Post-processing & visualization
├── spmf-jar/ # SPMF library dependency
├── tests/ # Test corpora and benchmark scripts
│ ├── test1/ # 10-document test set
│ ├── test-gen/ # Synthetic dataset generator
│ └── run-benchmark-*.py # Benchmark runner scripts
└── paper/ # Paper source and compiled PDF
├── main.tex # LaTeX source
├── main.pdf # Compiled paper
├── literature.bib # Bibliography
└── *.png # Figures
The Java implementation is the one used for all experiments reported in the paper. Tested with JDK 21.
Build:
cd corpus-miner-java
./build.sh
Run:
java -cp "../spmf-jar/spmf.jar:extensions.jar" com.bloomspan.benchmarks.BenchmarkRunner \
<algorithm> <input_folder> <min_support> <min_length> <output_csv> [max_docs]
Example (included test corpus):
java -cp "../spmf-jar/spmf.jar:extensions.jar" com.bloomspan.benchmarks.BenchmarkRunner \
bloomspan test_docs 2 3 out.csv
Parameters:
| Parameter | Description |
|---|---|
algorithm | Algorithm to run (see below) |
input_folder | Directory containing .txt files (one document per file) |
min_support | Minimum number of documents a phrase must appear in (absolute) |
min_length | Minimum phrase length in tokens |
output_csv | Path for the output CSV file |
max_docs | (Optional) Limit the number of documents to process |
Available algorithms:
| Algorithm | Description |
|---|---|
bloomspan | BloomSpan — proposed algorithm |
fhk | Fischer-Heun-Kramer (SA-IS + Kasai LCP, bottom-up traversal) |
dfi | Deferred Frequency Index (top-down DFS with RMQ sparse table) |
gst | Generalized Suffix Tree via suffix array + LCP |
vmsp | VMSP maximal sequential pattern miner (SPMF) |
bidecontiguous | BIDE+ restricted to contiguous extensions (SPMF) |
bidecontiguousmaximal | BIDE+ contiguous, maximal only (SPMF) |
Output format (output_csv):
phrase,freq,length,example_files
"another unique phrase for testing",5,5,"file1.txt|file2.txt"
The C++ version is an earlier prototype with additional algorithms (BIDE, CloSpan, VMSP). It requires a C++20 compiler, OpenMP, and TBB.
Build:
cd corpus-miner
make
Run:
./corpus_miner <input_dir_or_csv> [options]
Options:
| Flag | Description | Default |
|---|---|---|
--n | Minimum support (number of documents) | 10 |
--ngrams | Seed n-gram size | 4 |
--min_l | Minimum phrase length | — |
--algo | Algorithm: bloomspan, bide, clospan, vmsp | bloomspan |
--threads | Number of OpenMP threads (0 = all) | 0 |
--mem | Memory limit in MB for n-gram builder (0 = unlimited) | 0 |
Example:
./corpus_miner ../tests/test1 --ngrams 3 --n 3 --algo bloomspan
Post-processing and visualization:
python3 process_results_csv.py --input results_max.csv --min_l 3
open visualization.html
All experiments in the paper use the Java implementation with the following setup:
-Xmx40g| Dataset | Source | Parameters |
|---|---|---|
| Synthetic 1 (Sparse) | Generated via tests/generate_test_dataset.py | sigma=3, min length 3 |
| Synthetic 2 (Dense Overlaps) | 300 overlapping injections, N=15,000 | — |
| Gutenberg-8k | Fhrozen/gutenberg8k | sigma=10, min length 5 |
| Gutenberg-BookCorpus-Cleaned | laihuiyuan/gutenberg-bookcorpus-cleaned | sigma=20, min length 10 |
cd tests
python3 generate_test_dataset.py
This creates 100,000 documents with embedded "golden" phrases defined in generate_test_dataset.csv, enabling precision/recall validation.
Results on Gutenberg-BookCorpus-Cleaned (sigma=20, min phrase length 10). Wall-clock time in seconds; peak heap memory in MB. Medians over five measured runs. OOM = Out of Memory (40 GB heap).
| N | BloomSpan | FHK | DFI | Speedup | MCFPs | |||
|---|---|---|---|---|---|---|---|---|
| Time (s) | Mem (MB) | Time (s) | Mem (MB) | Time (s) | Mem (MB) | (FHK/BS) | ||
| 1,000 | 1.73 | 5,095 | 19.08 | 6,591 | 20.17 | 9,138 | 11.0x | 31 |
| 3,000 | 4.16 | 7,836 | 60.34 | 7,856 | 67.25 | 29,393 | 14.5x | 120 |
| 5,000 | 6.64 | 6,977 | 101.33 | 11,238 | OOM | OOM | 15.3x | 217 |
| 8,000 | 10.41 | 8,853 | 160.37 | 16,708 | OOM | OOM | 15.4x | 375 |
| 10,000 | 13.59 | 12,044 | 199.34 | 20,764 | OOM | OOM | 14.7x | 516 |
| 15,000 | 20.80 | 14,979 | 308.67 | 31,549 | OOM | OOM | 14.8x | 1,034 |
| 20,000 | 27.67 | 20,839 | — | — | OOM | OOM | — | 1,964 |
| 30,000 | 44.61 | 29,385 | 662.24 | 38,461 | OOM | OOM | 14.8x | 3,673 |
| 50,000 | 383.27 | 38,873 | OOM | OOM | OOM | OOM | — | — |
Notes:
If you use BloomSpan in your research, please cite:
@inproceedings{aliev2026bloomspan,
title = {BloomSpan: Memory-Efficient Maximal Frequent Substring Mining for Large-Scale Text},
author = {Aliev, Rauf and Beel, Joeran},
year = {2026},
institution = {University of Siegen}
}
This repository is provided for research purposes. The SPMF library (spmf-jar/spmf.jar) is subject to its own license terms.
Discovering frequent boilerplate and duplicate fragments in large-scale text datasets
C++
1
34 commits
updated Oct 12, 2026
This repository contains the source code and benchmark framework accompanying the paper:
BloomSpan: Memory-Efficient Maximal Frequent Substring Mining for Large-Scale Text Rauf Aliev, Joeran Beel — University of Siegen, Germany
The full paper is available in paper/bloomspan.pdf.
BloomSpan is an algorithm for mining Maximal Contiguous Frequent Phrases (MCFPs) from large text corpora. MCFPs are strictly contiguous token sequences whose document-support meets a minimum threshold — unlike general Sequential Pattern Mining, no gaps are permitted.
BloomSpan combines a Counting Bloom Filter for probabilistic frequency estimation with prioritized seed generation and depth-first expansion directly on the corpus, avoiding recursive projected databases. Key properties:
BloomSpan operates in four phases:
bloomspan/
├── corpus-miner-java/ # Java benchmark framework (primary, used in paper evaluation)
│ ├── src/ # Source code for all algorithms
│ ├── build.sh # Build script
│ └── test_docs/ # Small test corpus (3 documents)
├── corpus-miner/ # C++ implementation (prototype)
│ ├── _ours/ # BloomSpan C++ implementation
│ ├── bide/ # BIDE+ implementation
│ ├── Makefile # Build with `make`
│ └── process_results_csv.py # Post-processing & visualization
├── spmf-jar/ # SPMF library dependency
├── tests/ # Test corpora and benchmark scripts
│ ├── test1/ # 10-document test set
│ ├── test-gen/ # Synthetic dataset generator
│ └── run-benchmark-*.py # Benchmark runner scripts
└── paper/ # Paper source and compiled PDF
├── main.tex # LaTeX source
├── main.pdf # Compiled paper
├── literature.bib # Bibliography
└── *.png # Figures
The Java implementation is the one used for all experiments reported in the paper. Tested with JDK 21.
Build:
cd corpus-miner-java
./build.sh
Run:
java -cp "../spmf-jar/spmf.jar:extensions.jar" com.bloomspan.benchmarks.BenchmarkRunner \
<algorithm> <input_folder> <min_support> <min_length> <output_csv> [max_docs]
Example (included test corpus):
java -cp "../spmf-jar/spmf.jar:extensions.jar" com.bloomspan.benchmarks.BenchmarkRunner \
bloomspan test_docs 2 3 out.csv
Parameters:
| Parameter | Description |
|---|---|
algorithm | Algorithm to run (see below) |
input_folder | Directory containing .txt files (one document per file) |
min_support | Minimum number of documents a phrase must appear in (absolute) |
min_length | Minimum phrase length in tokens |
output_csv | Path for the output CSV file |
max_docs | (Optional) Limit the number of documents to process |
Available algorithms:
| Algorithm | Description |
|---|---|
bloomspan | BloomSpan — proposed algorithm |
fhk | Fischer-Heun-Kramer (SA-IS + Kasai LCP, bottom-up traversal) |
dfi | Deferred Frequency Index (top-down DFS with RMQ sparse table) |
gst | Generalized Suffix Tree via suffix array + LCP |
vmsp | VMSP maximal sequential pattern miner (SPMF) |
bidecontiguous | BIDE+ restricted to contiguous extensions (SPMF) |
bidecontiguousmaximal | BIDE+ contiguous, maximal only (SPMF) |
Output format (output_csv):
phrase,freq,length,example_files
"another unique phrase for testing",5,5,"file1.txt|file2.txt"
The C++ version is an earlier prototype with additional algorithms (BIDE, CloSpan, VMSP). It requires a C++20 compiler, OpenMP, and TBB.
Build:
cd corpus-miner
make
Run:
./corpus_miner <input_dir_or_csv> [options]
Options:
| Flag | Description | Default |
|---|---|---|
--n | Minimum support (number of documents) | 10 |
--ngrams | Seed n-gram size | 4 |
--min_l | Minimum phrase length | — |
--algo | Algorithm: bloomspan, bide, clospan, vmsp | bloomspan |
--threads | Number of OpenMP threads (0 = all) | 0 |
--mem | Memory limit in MB for n-gram builder (0 = unlimited) | 0 |
Example:
./corpus_miner ../tests/test1 --ngrams 3 --n 3 --algo bloomspan
Post-processing and visualization:
python3 process_results_csv.py --input results_max.csv --min_l 3
open visualization.html
All experiments in the paper use the Java implementation with the following setup:
-Xmx40g| Dataset | Source | Parameters |
|---|---|---|
| Synthetic 1 (Sparse) | Generated via tests/generate_test_dataset.py | sigma=3, min length 3 |
| Synthetic 2 (Dense Overlaps) | 300 overlapping injections, N=15,000 | — |
| Gutenberg-8k | Fhrozen/gutenberg8k | sigma=10, min length 5 |
| Gutenberg-BookCorpus-Cleaned | laihuiyuan/gutenberg-bookcorpus-cleaned | sigma=20, min length 10 |
cd tests
python3 generate_test_dataset.py
This creates 100,000 documents with embedded "golden" phrases defined in generate_test_dataset.csv, enabling precision/recall validation.
Results on Gutenberg-BookCorpus-Cleaned (sigma=20, min phrase length 10). Wall-clock time in seconds; peak heap memory in MB. Medians over five measured runs. OOM = Out of Memory (40 GB heap).
| N | BloomSpan | FHK | DFI | Speedup | MCFPs | |||
|---|---|---|---|---|---|---|---|---|
| Time (s) | Mem (MB) | Time (s) | Mem (MB) | Time (s) | Mem (MB) | (FHK/BS) | ||
| 1,000 | 1.73 | 5,095 | 19.08 | 6,591 | 20.17 | 9,138 | 11.0x | 31 |
| 3,000 | 4.16 | 7,836 | 60.34 | 7,856 | 67.25 | 29,393 | 14.5x | 120 |
| 5,000 | 6.64 | 6,977 | 101.33 | 11,238 | OOM | OOM | 15.3x | 217 |
| 8,000 | 10.41 | 8,853 | 160.37 | 16,708 | OOM | OOM | 15.4x | 375 |
| 10,000 | 13.59 | 12,044 | 199.34 | 20,764 | OOM | OOM | 14.7x | 516 |
| 15,000 | 20.80 | 14,979 | 308.67 | 31,549 | OOM | OOM | 14.8x | 1,034 |
| 20,000 | 27.67 | 20,839 | — | — | OOM | OOM | — | 1,964 |
| 30,000 | 44.61 | 29,385 | 662.24 | 38,461 | OOM | OOM | 14.8x | 3,673 |
| 50,000 | 383.27 | 38,873 | OOM | OOM | OOM | OOM | — | — |
Notes:
If you use BloomSpan in your research, please cite:
@inproceedings{aliev2026bloomspan,
title = {BloomSpan: Memory-Efficient Maximal Frequent Substring Mining for Large-Scale Text},
author = {Aliev, Rauf and Beel, Joeran},
year = {2026},
institution = {University of Siegen}
}
This repository is provided for research purposes. The SPMF library (spmf-jar/spmf.jar) is subject to its own license terms.