Exact similarity search over large collections of data series is a fundamental operation in modern applications, yet existing solutions are often fragmented, specialized, or tailored to specific execution environments. We present DaiSy (Data series similarity Search library), a unified library for exact data series and vector similarity search that integrates multiple state-of-the-art algorithms within a single, coherent framework. DaiSy is the first library to support exact similarity search across diverse execution environments, including implementations for disk-based, in-memory, GPU-accelerated, and distributed scalable similarity search. The library supports interfaces in both C++ and Python, enabling researchers and practitioners to easily integrate its functionality in a variety of tasks.
ALPHA VERSION: Currently, DaiSy is experimental. The library is still under active development. We welcome suggestions and bug reports.
DaiSy has been accepted for publication at SIGMOD Record! When using DaiSy, please cite the following artifacts:
@article{daisy2026preprint,
title={DaiSy: A Library for Scalable Data Series Similarity Search},
author={Del Gaudio, Francesca and Chatzakis, Manos and Ravendirane, Gayathiri and Peng, Botao and Palpanas, Themis},
journal={arXiv preprint arXiv:2603.27719},
year={2026}
}
@misc{daisy2026github,
title = {{The DaiSy Library for Fast and Exact, Data Series and Vector Similarity Search}},
author ={Francesca Del Gaudio, Manos Chatzakis, Gayathiri Ravendirane, Botao Peng, Panagiota Fatourou, Themis Palpanas},
year = {2026},
howpublished = {\url{https://github.com/mchatzakis/daisy}}
}We currently support several algorithms for exact similarity search, each optimized for specific use cases and environments. The following table summarizes the key features of each algorithm:
| Algorithm | Description |
|---|---|
| Bruteforce | Naive parallel similarity search implementation with incremental streaming inserts |
| Lower Bound Bruteforce | Optimized bruteforce with lower bounding and incremental streaming inserts |
| MESSI | In-memory parallel similarity search with incremental iSAX-tree inserts |
| PARIS | Disk-based parallel similarity search |
| SING | GPU-accelerated in-memory parallel similarity search |
| Odyssey | Distributed and parallel in-memory similarity search |
| SOFA | In-memory similarity search using Symbolic Fourier Approximation (SFA) |
| Hercules | In-memory hierarchical similarity search using EAPCA and SAX-based pruning |
| DumpyOS | In-memory scalable data series similarity search using an adaptive multi-ary iSAX index |
| FreSH | In-memory lock-free parallel similarity search using an iSAX index (SRDS 2023) |
| COCONUT | Paper-based materialized Coconut-LSM-Full: bottom-up disk index, streaming inserts, resident-summary SIMS and recent-window top-k |
BruteForceSearch, LbBruteforce, Messi, and Coconut implement the common
streaming API. Build the initial index once, then append one series or a contiguous batch without
rebuilding:
daisy::Messi search(daisy::DistanceType::L2_SQUARED);
search.buildIndex(initial_data, initial_size, dim);
search.insert(one_series);
search.insertBatch(batch_data, batch_size);Inserted series receive consecutive IDs beginning at the size of the initial database and are
immediately visible to supported top-k and range searches. LbBruteforce and Messi compute a
SAX summary for each insert using the breakpoints established during the initial build. MESSI
routes each new summary into the live iSAX tree and splits full leaves without rebuilding the
index. Its first insert copies a borrowed initial in-memory database into owned growable storage.
SAX encoding uses the ordered breakpoints for both tail intervals, including shifted and repeated
adaptive cuts. setNormalized(false) selects adaptive breakpoints without changing input values.
Python MESSI queries accept strided NumPy arrays (including .fvecs views); the binding copies
queries to contiguous float32 storage when needed and checks the index dimension before searching.
MESSI range refinement evaluates the full distance when a partial sum equals the inclusive radius.
Streaming updates are not concurrent with queries. Inserts can reallocate the owned database,
so callers should not retain a pointer returned by getDatabase() across them.
Coconut now uses bounded disk streaming: a RAM memtable of at most
getBufferCapacity() records (default 1,000,000) flushes to sorted disk runs.
Binary LSM compaction merges adjacent temporal runs in the background, including
the raw vectors. Include waitForMerges() after insertBatch() when measuring
completed insertion time (sorting, writes, fsync and compaction). Initial build
uses external sorting; SIMS keeps packed SAX summaries resident and parallelizes
bounds over resident summaries before ordered raw refinement. Up to 32 independent
queries share bounded candidate reads; each retains its own exact heap and bound.
Sparse reads coalesce short gaps, while dense reads share blocks of at most 8 MiB.
Ordered approximate seeding precedes exact SAX-bound refinement across every run
and any partially full memtable. Candidate raw vectors are read in leaf blocks.
Top-k and inclusive range search support squared L2 with Gaussian SAX breakpoints;
vectors are never normalized internally. Configure layout before building:
index = daisy.Coconut(daisy.DistanceType.L2_SQUARED)
index.setBufferCapacity(1_000_000) # records, not the external insertion batch size
index.setIndexDirectory("/path/to/storage") # unique temporary child directory
index.buildIndex(initial_vectors)
index.insertBatch(new_vectors) # full tables persist and schedule compaction
index.waitForMerges() # include this barrier in completed-insert timing
index.setQueryBatchSize(32) # share candidate reads across independent queries
ids, distances = index.searchIndexRecent(queries, 1, 50_000_000) # latest records
print(index.getDiskRecords(), index.getBufferedRecords(), index.getMergeCount())This implements the paper's materialized Coconut-LSM-Full algorithms, with explicit implementation choices and tests; it is not the authors' binary or an upstream performance reproduction. POSIX disk storage is required. The OS may cache disk pages, so measure cgroup memory as well as the bounded explicit buffers. Indexes are temporary and removed on destruction; crash recovery, reopening, deletion and concurrent caller writes/reads are unsupported. Recent-window queries use insertion counts, not arbitrary user timestamps. Resident SAX uses O(N) RAM; bound/read scratch is bounded independently of N; the raw vectors and bounded insertion buffer have separate budgets. See the implementation notes. Earlier results from the unmerged RAM insertion buffer do not evaluate disk-based streaming.
Algorithms that implement range search answer range queries through
SearchConfig. Instead of a fixed k, each query returns however many series fall within the
radius, so the results come back as one vector per query:
daisy::SearchConfig config;
config.type = daisy::QueryType::RANGE;
config.r = radius; // squared L2 distance
std::vector<std::vector<daisy::idx_t>> I;
std::vector<std::vector<float>> D;
search.searchIndex(query, n_query, config, I, D);demos/demo_<Algorithm>_Range.cpp shows this for each algorithm and cross-checks the returned
sets against brute force.
- Operating System: Linux, macOS, or Windows
- C++ Compiler: C++14 or higher (GCC 6+, Clang 3.4+, MSVC 2015+)
- CMake: Version 3.15 or higher
Optionally,
- Python: 3.10-3.12
- MPI: Required for Odyssey distributed computing algorithm
- CUDA: Required for SING GPU acceleration algorithm
To download DaiSy, use:
git clone https://github.com/MChatzakis/daisy.git
cd daisy
git submodule update --init --recursiveBased on the available hardware, you can specify the below arguments to enable/disable features.
| Flag | Description | Default | Dependencies |
|---|---|---|---|
BUILD_PYTHON |
Enable Python bindings | OFF |
Python 3.10+ |
BUILD_BENCHMARK |
Build benchmarking tools | OFF |
GoogleBenchmark |
BUILD_TESTS |
Build test suite | OFF |
GoogleTest |
BUILD_DEMO |
Build demonstration applications | ON |
Core library |
BUILD_ODYSSEY |
Enable MPI for distributed computing | OFF |
OpenMPI/MPICH |
BUILD_SING |
Enable CUDA for GPU acceleration | OFF |
CUDA Toolkit |
BUILD_COCONUT |
Enable the COCONUT sortable-SAX algorithm | ON |
Core library |
DEBUG_MSG |
Enable debug output | OFF |
None |
BUILD_SOFA |
Enable SOFA with SFA-Based indexing | OFF |
FFTW3 |
To compile:
mkdir build && cd build
cmake ..
makeIf you intent to use only the Python interface, you can install the library directly from PyPI using pip:
pip install daisy-exact-searchIf you want to use Odyssey, you will need to install mpi:
pip install daisy-exact-search[mpi]Kindly note that we are aware for compatibility issues related to ARM processors (e.g., Apple MX processors). Due to pthread-barriers and SIMD being unavailable on ARM, we currently noticing compilations failling on ARM machines. We are currently working on possible solutions, however we recommend using DaiSy on non-ARM machines for the time being.
We provide several usage examples in both C++ and Python under demos/, demonstrating how to utilize the library for various similarity search tasks.
We provide several troubleshooting guides and extra resources in the docs/ directory.
In this directory, we also provide useful information about how to contribute to the project, and how to implement new algorithms.
Work supported by EU Horizon projects ARMADA (101168951), TwinODIS (101160009), DataGEMS (101188416), and YΠAIΘA & NextGenerationEU project HARSH (YΠ3TA − 0560901) that is carried out within the framework of the National Recovery and Resilience Plan “Greece 2.0” with funding from the European Union – NextGenerationEU. Manos Chatzakis is supported with a PhD Scholarship from the Onassis Foundation. The logo of DaiSy was designed by Eva Chamilaki.
