News Froggy
newsfroggy
HomeTechReviewProgrammingGamesHow ToAboutContacts
newsfroggy

Your daily source for the latest technology news, startup insights, and innovation trends.

More

  • About Us
  • Contact
  • Privacy Policy
  • Terms of Service

Categories

  • Tech
  • Review
  • Programming
  • Games
  • How To

© 2026 News Froggy. All rights reserved.

TwitterFacebook
Programming

Build a Bloom Filter from Scratch in Python for Efficient Checks

Bloom filters are probabilistic data structures that efficiently determine if an item is "definitely not" or "possibly" in a set, using minimal memory. They are ideal for scenarios requiring fast membership checks on vast datasets where a small rate of false positives is acceptable. This article details how to build one from scratch in Python, covering its core components, hash function design, and how to size it for a target error rate.

PublishedJune 29, 2026
Reading Time8 min
Build a Bloom Filter from Scratch in Python for Efficient Checks

As software developers, we often encounter scenarios where we need to check for an item's existence within a vast dataset. Traditional data structures like hash sets excel at this, but their memory footprint can become prohibitive when dealing with millions or billions of items, especially if those items are large strings or complex objects. This is where a Bloom filter shines, offering a clever space-time tradeoff for membership queries.

A Bloom filter is a probabilistic data structure designed to tell you one of two things about an item: "definitely not in the set" or "possibly in the set." The former is always correct, while the latter might occasionally be a "false positive." The magic? It achieves this with a fixed, small memory footprint, independent of the size of the items themselves, and lightning-fast lookup times.

Why Use a Bloom Filter?

Imagine a scenario where you need to quickly determine if a URL has been seen before without storing the full URL for every single entry. A standard Python set or hash table would consume memory proportional to both the number of items and their individual sizes. For a million URLs, each averaging fifty bytes, a regular set could easily consume tens of megabytes.

A Bloom filter, however, offers a solution that's vastly more memory-efficient. For the same million items and a one percent error rate, it might only require about 1.2 megabytes – a fixed size regardless of URL length. This makes Bloom filters indispensable in contexts like:

  • Databases and Storage Engines: Systems like Cassandra and HBase use them to avoid expensive disk reads by quickly checking if a key might be present in a specific data file.
  • Web Browsers and Safe Browsing: Google Chrome once used Bloom filters to locally check URLs against a list of known malicious sites, avoiding network calls for safe links.
  • Caches and CDNs: They can track frequently requested items, ensuring an item is only cached after a second request, thus filtering out one-off requests.

The core pattern is always the same: a Bloom filter acts as a fast, memory-efficient gate in front of a more expensive operation, reliably telling you when that operation can be skipped.

The Core Components: Bit Array and Hashes

At its heart, a Bloom filter relies on two simple pieces:

  1. A Bit Array: A long sequence of bits, all initialized to 0.
  2. Multiple Hash Functions: Several independent hash functions that convert an item into multiple distinct positions within that bit array.

To add an item, you feed it to each hash function. Each hash function produces an index, and you set the bit at each of these calculated indices to 1. To check for an item's presence, you run it through the same hash functions, generating the same set of indices. If all the bits at these positions are 1, the item is considered "possibly present." If even one bit is 0, the item is "definitely absent."

Let's start building our Bloom filter in Python:

python import hashlib

class BloomFilter: def init(self, size, num_hashes): self.size = size # number of bits in the array (m) self.num_hashes = num_hashes # number of hash functions (k) self.bits = [0] * size # every bit starts at 0

Generating Hash Positions with Double Hashing

We need num_hashes distinct and well-distributed positions for each item. A common and elegant method for this is double hashing. We compute two initial, independent hashes, then combine them iteratively to generate the required number of unique positions.

python def _positions(self, item): data = item.encode("utf-8") h1 = int.from_bytes(hashlib.sha256(data).digest()[:8], "big") h2 = int.from_bytes(hashlib.md5(data).digest()[:8], "big") for i in range(self.num_hashes): yield (h1 + i * h2) % self.size

In this _positions method:

  • We convert the input item to bytes for hashing.
  • sha256 and md5 provide two strong, independent hash values (h1 and h2). We take the first 8 bytes and convert them to an integer to ensure they're large and random-looking.
  • The formula (h1 + i * h2) % self.size generates num_hashes distinct indices. The % self.size operation ensures these indices fit within our bit array.

Adding and Checking for Membership

With our _positions generator, the add and __contains__ methods become straightforward:

python def add(self, item): for idx in self._positions(item): self.bits[idx] = 1

def contains(self, item): return all(self.bits[idx] for idx in self._positions(item))

By implementing __contains__, our BloomFilter class can be used with Python's natural in operator, making checks intuitive:

python bf = BloomFilter(size=1000, num_hashes=4) bf.add("alice") bf.add("bob") print("alice" in bf) # True print("bob" in bf) # True print("carol" in bf) # almost always False

Understanding and Managing False Positives

The "almost always False" for "carol" highlights the Bloom filter's probabilistic nature. Because bits are shared among multiple items, it's possible for all the hash positions corresponding to an un-added item (like "carol") to have been set to 1 by other items. When this happens, the filter reports a "yes" for an item that isn't present – this is a false positive.

Crucially, a Bloom filter never produces a false negative. If an item was added, all its corresponding bits were set to 1 and remain 1, so it will always be reported as "possibly present." This asymmetry is a key feature:

  • Definitely not in the set: This is always accurate (no false negatives).
  • Possibly in the set: This might be incorrect (false positives are possible).

The rate of false positives is controllable and depends on three factors: the bit array size (m), the expected num_items (n), and the num_hashes (k). You can observe false positives directly by overfilling a small filter:

python bf = BloomFilter(size=200, num_hashes=4) for i in range(100): bf.add(f"user-{i}")

false_hits = sum(f"ghost-{i}" in bf for i in range(1000)) print(false_hits) # Expect a non-zero number, demonstrating the false positive rate.

Sizing for Optimal Performance and Error Rate

To achieve a desired false positive rate (p) for a given number of items (n), you can calculate the optimal size (m) and num_hashes (k) using these formulas:

python import math

def optimal_params(n, p): m = math.ceil(-n * math.log(p) / (math.log(2) ** 2)) # bits needed k = max(1, round((m / n) * math.log(2))) # hashes to use return m, k

print(optimal_params(1_000_000, 0.01)) # Example: About (9,585,059 bits, 7 hashes) for 1M items, 1% error

This calculation shows that for 1 million items and a 1% false positive rate, you'd need roughly 9.6 million bits (about 1.2 MB) and 7 hash functions. This demonstrates the significant memory savings compared to storing the actual items.

A Note on Deletion

One significant limitation of a standard Bloom filter is the inability to reliably delete items. Clearing an item's bits might inadvertently clear bits that other items rely on, leading to false negatives (where an item is present but reported as absent), which violates the core guarantee. If deletion is a requirement, a counting Bloom filter (where each slot holds a counter instead of a single bit) is a common alternative, though it consumes more memory.

Practical Takeaways

OperationCost
addO(k)
in (check)O(k)
space~m bits for n items, independent of item size

Bloom filters are invaluable when:

  • Memory is a critical constraint.
  • Fast membership checks are needed.
  • A small, controllable rate of false positives is acceptable (or can be mitigated by a secondary, more accurate check).
  • Deletion of items is not a primary requirement.

By understanding their mechanics and limitations, you can leverage Bloom filters to build highly efficient systems that confidently filter out non-members and defer expensive checks only for possible members.

FAQ

Q: Can a Bloom filter ever produce a false negative? A: No, a standard Bloom filter cannot produce a false negative. Once an item is added, all its corresponding bits are set to 1 and remain so. Therefore, if an item truly exists in the set, a check will always return "possibly in the set."

Q: How does the number of hash functions (k) impact the Bloom filter's performance and accuracy? A: The number of hash functions (k) is crucial. Too few hashes, and many items will map to the same few bits, leading to a high false positive rate. Too many hashes, and the add and check operations become slower (O(k)), and the bit array fills up faster, also increasing false positives. The optimal k is calculated to minimize the false positive rate for a given m and n.

Q: Is there a way to clear a Bloom filter to reuse it? A: Yes, you can clear a Bloom filter by simply re-initializing its bit array to all zeros. However, you cannot selectively remove individual items from a populated filter without risking false negatives, as explained above. Re-initializing clears all stored "fingerprints" at once.

#Python#Data Structures#Algorithms#System Design#Performance

Related articles

Google Play's New Stance on 501(c)(6) Donations: AnkiDroid's Challenge
Programming
Hacker NewsSep 1

Google Play's New Stance on 501(c)(6) Donations: AnkiDroid's Challenge

For developers deeply embedded in the open-source ecosystem, the challenge of sustainable funding is ever-present. Many projects rely on community donations, often facilitated by fiscal hosts that simplify legal and

Cold Cases & Data Integrity: Lessons from a Decades-Old Verdict
Programming
Hacker NewsSep 1

Cold Cases & Data Integrity: Lessons from a Decades-Old Verdict

As software developers, we often deal with complex systems, legacy codebases, and the relentless pursuit of bugs that have evaded detection for years. The recent conviction in the 1996 murder of rapper Tupac Shakur

ai: Musk’s faster path to more gas turbines comes with pollution
Tech
TechCrunch AIAug 30

ai: Musk’s faster path to more gas turbines comes with pollution

Elon Musk's SpaceX is building a secret Texas foundry to produce gas turbine blades, aiming to accelerate AI data center power by 18 months. This addresses a critical energy bottleneck, but faces environmental backlash over pollution and health risks from gas turbines.

Reimagining Classic IM: Exploring Open OSCAR Server in Go
Programming
Hacker NewsAug 30

Reimagining Classic IM: Exploring Open OSCAR Server in Go

Open OSCAR Server is an open-source, Go-based instant messaging server compatible with classic AIM and ICQ clients. It enables developers and enthusiasts to self-host a private IM server, reviving the functionality of these legacy platforms. The project boasts broad client compatibility, detailed protocol implementations, and a management API for administration.

Nvidia's AI Dominance Shifts Beyond GPUs to Data Orchestration
Tech
TechCrunch AIAug 30

Nvidia's AI Dominance Shifts Beyond GPUs to Data Orchestration

Nvidia is extending its AI dominance beyond GPUs, focusing on system-level data orchestration within massive data centers. Post-earnings, the company's Vera Rubin architecture, including the Vera CPU, is proving crucial for efficient data management, optimizing performance and energy use. This shift towards smarter data traffic control marks a new competitive front in AI infrastructure, where Nvidia currently holds a commanding lead.

Startup Spotlight: Skyfarer Connects Pilots with Aviation Services
Tech
GeekWireAug 28

Startup Spotlight: Skyfarer Connects Pilots with Aviation Services

Skyfarer, a startup founded by Nick Tsang in Camas, Wash., is building an "Airbnb for aviation," a unified online marketplace connecting pilots with flight training, instructors, mechanics, and aircraft. Addressing a fragmented multi-billion dollar general aviation market, Skyfarer has rapidly grown to nearly 14,000 users and 8,500 listings by offering essential services and leveraging AI for swift development. The company's vision is to support pilots throughout their entire aviation journey, aiming to reduce dropout rates and foster a thriving flying community.

Back to Newsroom

Stay ahead of the curve

Get the latest technology insights delivered to your inbox every morning.