TL;DR
This paper presents BBhash, a parallel minimal perfect hash function implementation that is highly efficient in construction time and memory usage, capable of handling extremely large key sets up to 10^12 elements.
Contribution
It revisits a simple algorithm and demonstrates its competitiveness, providing the first implementation tested on 10^12 elements with practical performance.
Findings
Constructs a minimal perfect hash for 10^10 elements in under 7 minutes
Uses only 3.7 bits per element in the resulting hash
Successfully tested on input sizes up to 10^12 elements
Abstract
Minimal perfect hash functions provide space-efficient and collision-free hashing on static sets. Existing algorithms and implementations that build such functions have practical limitations on the number of input elements they can process, due to high construction time, RAM or external memory usage. We revisit a simple algorithm and show that it is highly competitive with the state of the art, especially in terms of construction time and memory usage. We provide a parallel C++ implementation called BBhash. It is capable of creating a minimal perfect hash function of elements in less than 7 minutes using 8 threads and 5 GB of memory, and the resulting function uses 3.7 bits/element. To the best of our knowledge, this is also the first implementation that has been successfully tested on an input of cardinality . Source code: https://github.com/rizkg/BBHash
| Method |
|
|
|
|
|
||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| BBhash | 271 | 3.1 | 60 (393) | 3.2 (376) | 8.23 | ||||||||||||
| BBhash minirank | 279 | 2.9 | 61(401) | 3.2 (376) | 8.23 | ||||||||||||
| BBhash | 216 | 3.7 | 35 (229) | 4.3 (516) | 4.45 | ||||||||||||
| BBhash nodisk | 216 | 3.7 | 80 (549) | 6.2 (743) | 0 | ||||||||||||
| BBhash | 179 | 6.9 | 25 (162) | 10.7 (1,276) | 1.52 | ||||||||||||
| EMPHF | 246 | 2.9 | 2,642 | 247.1 (29,461) | 20.8 | ||||||||||||
| EMPHF HEM | 581 | 3.5 | 489 | 258.4 (30,798) | 22.5 | ||||||||||||
| CHD | 1037 | 2.6 | 1,146 | 176.0 (20,982) | 0 | ||||||||||||
| Sux4J | 252 | 3.3 | 1,418 | 18.10 (2,158) | 40.1 |
| Dataset |
|
|
|
|||||
|---|---|---|---|---|---|---|---|---|
| Random strings | 325 | 3.7 | 35 | |||||
| Ngrams | 296 | 3.7 | 37 |
Peer Reviews
No public reviews on file for this paper yet. If you reviewed it on a platform where reviews are public (OpenReview, ICLR, NeurIPS, ICML), you can paste yours below so the community can read it here.
Code & Models
Videos
No videos yet. Explain this paper in a talk, walkthrough, or lecture? Add one.
\Copyright
Antoine Limasset, Guillaume Rizk, Rayan Chikhi and Pierre Peterlongo
Fast and scalable minimal perfect hashing for massive key sets
Antoine Limasset
IRISA Inria Rennes Bretagne Atlantique, GenScale team, Campus de Beaulieu 35042 Rennes, France
Guillaume Rizk
IRISA Inria Rennes Bretagne Atlantique, GenScale team, Campus de Beaulieu 35042 Rennes, France
Rayan Chikhi
CNRS, CRIStAL, Université de Lille, Inria Lille - Nord Europe, France
Pierre Peterlongo
IRISA Inria Rennes Bretagne Atlantique, GenScale team, Campus de Beaulieu 35042 Rennes, France
Abstract.
Minimal perfect hash functions provide space-efficient and collision-free hashing on static sets. Existing algorithms and implementations that build such functions have practical limitations on the number of input elements they can process, due to high construction time, RAM or external memory usage. We revisit a simple algorithm and show that it is highly competitive with the state of the art, especially in terms of construction time and memory usage. We provide a parallel C++ implementation called BBhash. It is capable of creating a minimal perfect hash function of elements in less than 7 minutes using 8 threads and 5 GB of memory, and the resulting function uses 3.7 bits/element. To the best of our knowledge, this is also the first implementation that has been successfully tested on an input of cardinality . Source code: https://github.com/rizkg/BBHash
Key words and phrases:
Minimal Perfect Hash Functions, Algorithms, Data Structures, Big Data
1991 Mathematics Subject Classification:
H.3.1 E.2
1. Introduction
Given a set of elements (keys), a minimal perfect hash function (MPHF) is an injective function that maps each key of to an integer in the interval . In other words, an MPHF labels each key of with integers in a collision-free manner, using the smallest possible integer range. A remarkable property is the small space in which these functions can be stored: only a couple of bits per key, independently of the size of the keys. Furthermore, an MPHF query is done in constant time. While an MPHF could be easily obtained using a key-value store (e.g. a hash table), such a representation would occupy an unreasonable amount of space, with both the keys and the integer labels stored explicitly.
The theoretical minimum amount of space needed to represent an MPHF is known to be bits [10, 14]. In practice, for large key sets (billions of keys), many implementations achieve less than bits per key, independently of the number of keys [2, 9]. However no implementation comes asymptotically close to the lower bound for large key sets. Given that MPHFs are typically used to index huge sets of strings, e.g. in bioinformatics [6, 7, 8], in network applications [12], or in databases [5], lowering the representation space is of interest. We observe that in many of these applications, MPHFs are actually used to construct static dictionaries, i.e. key-value stores where the set of keys is fixed and never updated [6, 8]. Assuming that the user only queries the MPHF to get values corresponding to keys that are guaranteed to be in the static set, the keys themselves do not necessarily need to be stored in memory. However the associated values in the dictionary typically do need to be stored, and they often dwarf the size of the MPHF. The representation of such dictionaries then consists of two components: a space-efficient MPHF, and a relatively more space-expensive set of values. In such applications, whether the MPHF occupies 1.44 bits or 3 bits per key is thus arguably not a critical aspect.
In practice, a significant bottleneck for large-scale applications is the construction step of MPHFs, both in terms of memory usage and computation time. Constructing MPHFs efficiently is an active area of research. Many recent MPHF construction algorithms are based on efficient peeling of hypergraphs [1, 3, 4, 11]. However, they require an order of magnitude more space during construction than for the resulting data structure. For billions of keys, while the MPHF itself can easily fit in main memory of a commodity computer, its construction algorithm requires large-memory servers. To address this, Botelho and colleagues [4] propose to divide the problem by building many smaller MPHFs, while Belazzougui et al. [1] propose an external-memory algorithm for hypergraph peeling. Very recently, Genuzio et al. [11] demonstrated practical improvements to the Gaussian elimination technique, that make it competitive with [1] in terms of construction time, lookup time and space of the final structure. These techniques are, to the best of our knowledge, the most scalable solutions available. However, when evaluating existing implementations, the construction of MPHFs for sets that significantly exceed a billion of keys remains prohibitive in terms of time and space usage.
A simple idea has been explored by previous works [6, 12, 16] for constructing MPHFs using arrays of bits, or fingerprints. However, it has received relatively less attention compared to other hypergraph-based methods, and no implementation is publicly available in a stand-alone MPHF library. In this article we revisit this idea, and introduce novel contributions: a careful analysis of space usage during construction, and an efficient, parallel implementation along with an extensive evaluation with respect to the state of the art. We show that it is possible to construct an MPHF using nearly as much memory as the space required by the final structure, without partitioning the input. We propose a novel implementation called BBhash (“Basic Binary representAtion of Successive Hashing”) with the following features:
- •
construction space overhead is small compared to the space occupied by the MPHF,
- •
multi-threaded,
- •
scales up to to very large key sets (tested with up to 1 trillion keys).
To the best of our knowledge, there does not exist another usable implementation that satisfies any two of the features above. Furthermore, the algorithm enables a time/memory trade-off: faster construction and faster query times can be obtained at the expense of a few more bits per element in the final structure and during construction. We created an MPHF for ten billion keys in 6 minutes 47 seconds and less than 5 GB of working memory, and an MPHF for a trillion keys in less than 36 hours and 637 GB memory. Overall, with respect to others available MPHF construction approaches, our implementation is at least two orders of magnitudes more space-efficient when considering internal and external memory usage during construction, and at least one order of magnitude faster. The resulting MPHF has slightly higher space usage and faster or comparable query times than other methods.
2. Efficient construction of minimal perfect hash function
2.1. Method overview
Our MPHF construction procedure revisits previously published techniques [6, 12]. Given a set of keys, a classical hash function maps keys to an integer in . A bit array of size is created such that there is a 1 at position if and only if exactly one element of has a hash value of . We say that there is a collision whenever two keys in have the same hash value. Keys from that were involved in a collision are inserted into a new set . The process repeats with and a new hash function . A new bit array of size is created using the same procedure as for (except that is used instead of , and instead of ). The process is repeated with until one of these sets, , is empty.
We obtain an MPHF by concatenating the bit arrays into an array . To perform a query, a key is hashed successively with hash functions as long as the value in () at the position given by the hash function is 0. Eventually, by construction, we reach a 1 at some position of for some . We say that the level of the key is . The index returned by the MPHF is the rank of this one in . See Figure 1 for an example.
2.2. Algorithm details
2.2.1. Collision detection
During construction at each level , collisions are detected using a temporary bit array of size . Initially all bits are set to ’0’. A bit of is set to ’1’ if two or more keys from have the same value given by hash function . Finally, if , then . Formally:
[TABLE]
2.2.2. Queries
A query of a key is performed by finding the smallest such that . The (non minimal) hash value of is then .
2.2.3. Minimality
To ensure that the image range of the function is , we compute the cumulative rank of each ’1’ in the bit arrays . Suppose, that is the smallest value such that . The minimal perfect hash value is given by , where is the number of bits set to ’1’ in the array, and is the number of bits set to 1 in within the interval , thus . This is a classic method also used in other MPHFs [3].
2.2.4. Faster query and construction times (parameter )
The running time of the construction depends on the number of collisions on the arrays, at each level . One way to reduce the number of collisions, hence to place more keys at each level, is to use bit arrays ( and ) larger than . We introduce a parameter , , such that . With , the size of is minimal. With , the number of collisions is significantly decreased and thus construction and query times are reduced, at the cost of a larger MPHF structure size. The influence of is discussed in more details in the following analyses and results.
2.3. Analysis
Proofs of the following observations and lemma are given in the Appendix.
2.3.1. Size of the MPHF
The expected size of the structure can be determined using a simple argument, previously made in [6]. When , the expected number of keys which do not collide at level is , thus . In total, the expected number of bits required by the hashing scheme is , with being the total number of input keys (). Note that consequently the image of the hash function is also in , before minimization using the rank technique. When , the expected proportion of keys without collisions each level is . Since each no longer uses one bit per key but bits per key, the expected total number of bits required by the MPHF is .
2.3.2. Space usage during construction
We analyze the disk space during construction. Recall that during construction of level , a bit array of size is used to record collisions. Note that the array is only needed during the -th level. It is deleted before level . The total memory required during level is .
Lemma 1**.**
For , the space of our MPHF is bits. The maximal space during construction is when , and bits otherwise.
A full proof of the Lemma is provided in the Appendix.
3. Implementation
We present BBhash, a C++ implementation available at http://github.com/rizkg/BBHash. We describe in this section some design key choices and optimizations.
3.1. Rank structure
We use a classical technique to implement the rank operation: the ranks of a fraction of the ’1’s present in are recorded, and the ranks in-between are computed dynamically using the recorded ranks as checkpoints.
In practice 64 bits integers are used for counters, which is enough for realistic use of an MPHF, and placed every 512 positions by default. These values were chosen as they offer a good speed/memory trade-off, increasing the size of the MPHF by a factor 1.125 while achieving good query performance. The total size of the MPHF is thus
3.2. Parallelization
Parallelization is achieved by partitioning keys over several threads. The algorithm presented in Section 2 is executed on multiple threads concurrently, over the same memory space. Built-in compiler functions (e.g. sync_fetch_and_or) are used for concurrent access in the arrays. The efficiency of this parallelization scheme is shown in the Results section, but note that it is fundamentally limited by random memory accesses to the arrays which incur cache misses.
3.3. Hash functions
The MPHF construction requires classical hash functions. Other authors have observed that common hash functions behave practically as well as fully random hash functions [2]. We therefore choose to use xor-shift based hash functions [13] for their efficiency both in terms of computation speed and distribution uniformity [15].
3.4. Disk usage
In the applications we consider, key sets are typically too big to fit in RAM. Thus we propose to read them on the fly from disk. There are mainly two distinct strategies regarding the disk usage during construction: 1/ during each level , keys that are to be inserted in the set are written directly to disk. The set is then read during level and erased before level ; or 2/ at each level all keys from the original input key file are read and queried in order to determine which keys were already assigned to a level , and which would belong to .
The first strategy obviously provides faster construction at the cost of temporary disk usage. At each level , two temporary key files are stored on disk: and . The highest disk usage is thus achieved during level , i.e. by storing elements. With , this represents elements, thus the construction overhead on disk is approximately the size of the input key file. Note that with (resp. ), this overhead diminishes and becomes a ratio of (resp. ) the size of the input key file.
The first strategy is the default strategy proposed in our implementation. The second one has also been implemented and can be optionally switched on.
3.5. Termination
The expected number of unplaced keys decreases exponentially with the number of levels but is not theoretically guaranteed to reach zero in a finite number of steps. To ensure termination of the construction algorithm, in our implementation a maximal number of levels is fixed. Then, the remaining keys are inserted into a regular hash table. Value is a parameter, its default value is for which the expected number of keys stored in this hash table is for and becomes in practice negligible for , allowing the size overhead of the final hash table to be negligible regarding the final MPHF size.
4. Results
We evaluated the performance BBhash for the construction of large MPHFs. We generated files containing various number of keys (from 1 million to 1 trillion keys). In our tests, a key is a binary representation of a pseudo-random positive integer in . Within each file, each key is unique. We also performed a test where input keys are strings (n-grams) to ensure that using integers as keys does not bias results. Tests were performed on a cluster node with a Xeon E5 2.8 GHz 24-core CPU, 256 GB of memory, and a mechanical hard drive. Except for the experiment with keys, running times include the time needed to read input keys from disk. Note that files containing key sets may be cached in memory by the operating system, and all evaluated methods benefit from this effect during MPHF construction. We refer to the Appendix for the specific commands and parameters used in these experiments.
We first analyzed the influence of the value (the main parameter of BBhash), then the effect of using multiple threads depending on the parallelization strategy. Second, we compared BBhash with other state-of-the-art methods. Finally, we performed an MPHF construction on elements.
4.1. Influence of the parameter
We report in Figure 2 (left) the construction times and the mean query times, as well as the size of the produced MPHF, with respect to several values. The main observation is that drastically accelerates construction and query times. This is expected since large values allow more elements to be placed in the first levels of the MPHF; thus limiting the number of times each key is hashed to compute its level. In particular, for keys placed in the very first level, the query time is limited to a single hashing and a memory access. The average level of all keys is , we therefore expect construction and query times to decrease when increases. However, larger values also incur larger MPHF sizes. One observes that values seem to bring very little advantage at the price of higher space requirements. A related work used in order to minimize the MPHF size [6]. Here, we argue that using values larger than has significant practical merits. In our tests, we often used as it yields an attractive time/space trade-off during construction and queries.
4.2. Parallelization performance
We evaluated the capability of our implementation to make use of multiple CPU cores. In Figure 2 (right), we report the construction times with respect to the number of threads. We observe a near-ideal speed-up with respect to the number of threads with diminishing returns when using more than 10 threads, which is likely due to cache misses that induce a memory access bottleneck.
In addition to these results, we applied BBhash on a key set of 10 billion keys and on a key set of 100 billion keys, again using default parameters and 8 threads. The memory usage was respectively 4.96GB and 49.49GB, and the construction time was respectively 462 seconds and 8913 seconds, showing the scalability of BBhash.
4.3. Comparisons with state of the art methods
We compared BBhash with state-of-the-art MPHF methods. CHD (http://cmph.sourceforge.net/) is an implementations of the compressed hash-and-displace algorithm [2]. EMPHF [1] is based on random hypergraph peeling, and the HEM [4] implementation in EMPHF is based on partitioning the input data; both methods use external memory during construction. We did not perform comparisons with similar techniques as ours [6, 12, 16], given that stand-alone implementations were not available. Our benchmark code is available at https://github.com/rchikhi/benchmphf.
Figure 3 shows that all evaluated methods are able to construct MPHFs that contain a billion of elements, while only BBhash scales up to datasets that contain elements and more. Overall, BBhash shows consistently better time and memory usage during construction.
We additionally compared the resulting MPHF size, i.e. the space of the data structure returned by the construction algorithm, and the mean query time across all libraries on a dataset consisting of a billion keys (Table 1). MPHFs produced by BBhash range from 2.89 bits/key (when and ranks are sampled every 1024 positions) to 6.9 bits/key (when and a rank sampling of 512). The 0-0.8 bits/key size difference between our implementation and the theoretical space of BBhash structure size is due to additional space used by the rank structure. We believe that a reasonable compromise in terms of query time and structure size is 3.7 bits/key with and a rank sampling of 512, which is marginally larger than the MPHF sizes of other libraries (ranging from 2.6 to 3.5 bits/key). As we argued in the Introduction that using 1 more bit per key is an acceptable trade-off for performance.
Construction times vary by one or two orders of magnitude across methods, BBhash being the fastest. With default parameters (, rank sampling of 512), BBhash has a construction memory footprint 40 to 60 smaller than other libraries except for Sux4j, for which BBhash remains 4 smaller. Query times are roughly within an order of magnitude of each other across methods, with a slight advantage for BBhash when . Sux4j achieves an attractive balance with low construction memory and query times, but high disk usage. In our tests, the high disk usage of Sux4j was a limiting factor for the construction of very large MPHFs.
Note that EMPHF, EMPHF HEM and Sux4j implement a disk partitioning strategy, that could in principle also be applied to others methods, including ours. Instead of creating a single large MPHF, they partition the set of input keys on disk and construct many small MPHFs independently. In theory this technique allows to engineer the MPHF construction algorithm to use parallelism and lower memory, at the expense of higher disk usage. In practice we observe that the existing implementations that use this technique are not parallelized. While EMPHF en EMPHF HEM used relatively high memory in our tests (around 30 GB for 1 billion elements) due to memory-mapped files, they also completed the construction successfully on another machine that had 16 GB of available memory. However, we observed what appears to be limitations in the scalability of the scheme: we were unable to run EMPHF and EMPHF HEM on an input of 100 billion elements. Regardless, we view this partitioning technique as promising but orthogonal to the design of efficient "monolithic" MPHFs constructions such as BBhash.
4.4. Performance on an actual dataset
In order to ensure that using pseudo-random integers as keys does not bias results, we ran BBhash using string as keys. We used n-grams extracted from the Google Books Ngram dataset111http://storage.googleapis.com/books/ngrams/books/datasetsv2.html, version 20120701. In average the n-gram size is 18. We also generated random words of size 18. As reported in Table 2, we obtained highly similar results than those obtained with random integer keys.
4.5. Indexing a trillion keys
We performed a very large-scale test by creating an MPHF for keys. For this experiment, we used a machine with 750 GB of RAM. Since storing that many keys would require 8 TB of disk space, we instead used a procedure that generates deterministically a stream of pseudo-random integers in . We considered the streamed values as input keys without writing them to disk. Thus, the reported computation time should not be compared to previously presented results as this experiment has no disk accesses. The test was performed using , 24 threads, and keys were loaded in memory when of total keys (i.e. when remaining number of keys to index was lower than 20 billion).
Creating the MPHF took hours and required GB RAM. This memory footprint is roughly separated between the bit arrays ( GB) and the memory required for loading 20 billion keys in memory ( GB). The final MPHF occupied bits per key.
5. Conclusion
We propose a resource-efficient and highly scalable algorithm for constructing and querying MPHFs. Our algorithmic choices were motivated by simplicity: the method only relies on bit arrays and classical hash functions. While the idea of recording collisions in bit arrays to create MPHFs is not novel [6, 12], to the best of our knowledge BBhash is the first implementation that is competitive with the state of the art. The construction is particularly time-efficient as it is parallelized and mainly consists in hashing keys and performing memory accesses. Moreover, the additional data structures used during construction are provably small enough to ensure a low memory overhead during construction. In other words, creating the MPHF does not require much more space than the resulting MPHF itself. This aspect is important when constructing MPHFs on large key sets in practice.
Experimental results show that BBhash generates MPHFs that are slightly larger than those produced by other methods. However BBhash is by far the most efficient in terms of construction time, query time, memory and disk footprint for indexing large key sets (of cardinality above keys). The scalability of our approach was confirmed by constructing MPHFs for sets as large as keys. To the best of our knowledge, no other MPHF implementation has been tested on that many keys.
A time/space trade-off is achieved through the parameter. The value yields MPHFs that occupy roughly bits of space and have little memory overhead during construction. Higher values use more space for the construction and the final structure size, but they achieve faster construction and query times. Our results suggest that is a good time-versus-space compromise, using 3.7 bits per key. With respect to hypergraph-based methods [1, 3, 4, 11], BBhash offers significantly better construction performance, but the resulting MPHF size is up to 1 bit/key larger. We however argue that the MPHF size, as long as it is limited to a few bits per key, is generally not a bottleneck as many applications use MPHFs to associate much larger values to keys. Thus, we believe that this work will unlock many HPC applications where the possibility to index billions keys and more is a huge step forward.
An interesting future work is to obtain more space-efficient MPHFs using our method. We believe that a way to achieve this goal is to slightly change the hashing scheme. We would like to explore an idea inspired by the CHD algorithm for testing several hash functions at each level and selecting (then storing) one that minimizes the number of collisions. At the price of longer construction times, we anticipate that this approach could significantly decrease the final structure size.
Acknowledgments
This work was funded by French ANR-12-BS02-0008 Colib’read project. We thank the GenOuest BioInformatics Platform that provided the computing resources necessary for benchmarking. We thank Djamal Belazzougui for helpful discussions and pointers.
Appendix
Proofs of MPHF size and memory required for construction
MPHF size with .
[TABLE]
∎
MPHF size using any .
[TABLE]
Moreover, as , on has:
[TABLE]
∎
Note that this proof stands for any value , but that with the theoretical and practical MPHF sizes increase exponentially as get close to zero.
Lemma 1.
Let be memory required during level and let be the ratio between the maximal memory needed during the MPHF construction and the MPHF total size denoted by . Formally,
[TABLE]
First we prove that .
[TABLE]
Since for , , then . Thus .
Before going further, we need to compute :
[TABLE]
We now prove when and also, when .
- •
Case 1:
We have .
Moreover, as and as, with : , and then , thus, is an increasing function.
To sum up, with , we have 1/ that , 2/ that , and 3/ that is increasing, then .
- •
Case 2: We have . With , . Moreover, is negative as: and for . Thus is a decreasing function with .
With , we have 1/ that , /2 that and /3 that is decreasing. Thus .
∎
Algorithms pseudo-codes
Commands
In this section we describe used commands for each presented result. Time and memory usages where computed using “/usr/bin/time –verbatim” unix command. The disk usage was computed thanks to a home made script measuring each 1/10 second the size of the directory using the “du -sk” unix command, and recording the highest value. The BBhash library and its Bootest tool are available from https://github.com/rizkg/BBHash.
Commands used for Section 4.1:
for ((gamma=1;gamma<11;gamma++)); do Ψ./Bootest 1000000000 1 ${gamma} -bench done
Note that 1000000000 is the number of keys tested and 1 is the number of used cores.
Additional tests, with larger key set and 8 threads:
for ((gamma=1;gamma<11;gamma++)); do Ψ./Bootest 1000000000 1 ${gamma} -bench done
Commands used for Section 4.2:
for keys in 10000000000 100000000000; do Ψ./Bootest ${keys} 8 2 -bench done
Commands used for Section 4.3:
We remind that our benchmark code, testing EMPHF, EMPHF MEM, CHD, and Sux4J is available at https://github.com/rchikhi/benchmphf.
- •
BBhash commands:
for keys in 1000000 10000000 100000000 10000000000
10000000000 100000000000; do
Ψ./Bootest ${keys} 1 2 -bench
done
- •
BBhash command with nodisk (Table 1) was
./Bootest 1000000000 1 2 -bench -nodisk
and
./Bootest 1000000000 8 2 -bench -nodisk
respectively for one and height threads. Other commands from Table 1 were deduced from previously presented BBhash computations.
- •
Commands EMPHF & EMPHF HEM:
for keys in 1000000 10000000 100000000 10000000000
10000000000 100000000000; do
Ψ./benchmphf ${keys} -emphf
done
EMPHF (resp. EMPHF HEM) is tested by using the #define EMPHF_SCAN macro (resp. #define EMPHF_HEM). In order to assess the disk size footprint, the line “unlink(tmpl);” from file “emphf/mmap_memory_model.hpp” was commented.
- •
Commands CHD:
for keys in 1000000 10000000 100000000 10000000000
10000000000 100000000000; do
Ψ./benchmphf ${keys} -chd
done
- •
Commands Sux4J:
for each size, the “Sux4J/slow/it/unimi/dsi/sux4j/mph/LargeLongCollection.java” was modified indicating the used size.
./run-sux4j-mphf.sh
Commands used for Section 4.4:
As explained Section 4.4, the keyString.txt file is composed of n-grams extracted from the Google Books Ngram dataset222http://storage.googleapis.com/books/ngrams/books/datasetsv2.html, version 20120701.
./BootestFile keyStrings.txt 10 2
Commands used for Section 4.5:
BBhash command for indexing a trillion keys, with keys generated on the fly.
./Bootest 1000000000000 24 2 -onthefly
The reference list from the paper itself. Each links out to its DOI / PubMed record.
- 1[1] Djamal Belazzougui, Paolo Boldi, Giuseppe Ottaviano, Rossano Venturini, and Sebastiano Vigna. Cache-oblivious peeling of random hypergraphs. In Data Compression Conference (DCC), 2014 , pages 352–361. IEEE, 2014.
- 2[2] Djamal Belazzougui, Fabiano C Botelho, and Martin Dietzfelbinger. Hash, displace, and compress. In European Symposium on Algorithms , pages 682–693. Springer, 2009.
- 3[3] Fabiano C Botelho, Rasmus Pagh, and Nivio Ziviani. Simple and space-efficient minimal perfect hash functions. In Algorithms and Data Structures , pages 139–150. Springer, 2007.
- 4[4] Fabiano C Botelho, Rasmus Pagh, and Nivio Ziviani. Practical perfect hashing in nearly optimal space. Information Systems , 38(1):108–131, 2013.
- 5[5] Chin-Chen Chang and Chih-Yang Lin. Perfect hashing schemes for mining association rules. The Computer Journal , 48(2):168–179, 2005. doi:10.1093/comjnl/bxh 074 . · doi ↗
- 6[6] Jarrod A Chapman, Isaac Ho, Sirisha Sunkara, Shujun Luo, Gary P Schroth, and Daniel S Rokhsar. Meraculous: de novo genome assembly with short paired-end reads. Plo S one , 6(8):e 23501, 2011.
- 7[7] Yupeng Chen, Bertil Schmidt, and Douglas L Maskell. A hybrid short read mapping accelerator. BMC Bioinformatics , 14(1):67, 2013. doi:10.1186/1471-2105-14-67 . · doi ↗
- 8[8] Rayan Chikhi, Antoine Limasset, and Paul Medvedev. Compacting de bruijn graphs from sequencing data quickly and in low memory. Bioinformatics , 32(12):i 201–i 208, 2016.
