All Products
Search
Document Center

Tair (Redis® OSS-Compatible):Use Bloom filters to manage game event push notifications

Last Updated:Mar 28, 2026

Game events—pop-up windows, in-game messages, non-player character (NPC) tasks—need to reach each player exactly once. With millions of concurrent players, the core question a Bloom filter answers is: Has this player already received this notification?

This guide shows how to connect to a Tair (Enterprise Edition) instance and use Bloom filters with Jedis to prevent duplicate push notifications.

How it works

A Bloom filter is a probabilistic data structure that answers membership queries with minimal memory. It returns one of two results:

  • Definitely not in the set — the player has not received the notification; send it.

  • Possibly in the set — the player may have received the notification; skip it.

The trade-off: false positives are possible, meaning a small number of players might miss a notification. For most game event scenarios, this is an acceptable trade-off for the memory and performance gains.

Why Bloom filters for this use case:

AdvantageDetail
Memory efficiencyBloom filters use bit arrays instead of storing full player IDs, using significantly less space than traditional data structures, especially when storing the push status of millions of players.
ScalabilityBloom filters work natively in Redis clusters and scale with your player base.

Prerequisites

Before you begin, ensure that you have:

  • A Tair (Enterprise Edition) instance with the endpoint and port number

  • The instance password

  • Java 8 or later

  • Maven

Set up the Jedis dependency

Add Jedis 5.1.0 to your pom.xml:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>5.1.0</version>
</dependency>

Manage notifications with a Bloom filter

The following example uses three operations to control notification delivery:

OperationDescription
bfReserveCreates the Bloom filter with a target capacity and false positive rate
bfExistsChecks whether a player ID is already in the filter
bfAddRecords that a player has received the notification
import redis.clients.jedis.*;
import redis.clients.jedis.UnifiedJedis;

public class TairBloomFilterDemo {
    // Replace with your instance endpoint, port number, and password.
    static HostAndPort hostAndPort = new HostAndPort("r-bp1y****svonly41srpd.redis.rds.aliyuncs.com", 6379);
    static JedisClientConfig config = DefaultJedisClientConfig.builder().password("tw:Da***3").build();
    static UnifiedJedis unifiedJedis = new UnifiedJedis(hostAndPort, config);

    private static final String BLOOM_KEY = "activity_popup";

    /**
     * Creates the Bloom filter with a 1% false positive rate and capacity for 50,000 player IDs.
     */
    public static void createBloom() {
        try {
            unifiedJedis.bfReserve(BLOOM_KEY, 0.01, 50000);
        } catch (Exception e) {
            e.printStackTrace(); // Handle connection timeouts and other errors.
        }
    }

    /**
     * Returns true if the player has not yet received the notification.
     */
    public static boolean shouldShowPopup(String playerId) {
        try {
            return !unifiedJedis.bfExists(BLOOM_KEY, playerId);
        } catch (Exception e) {
            e.printStackTrace(); // Handle connection timeouts and other errors.
            return true;
        }
    }

    /**
     * Records that the player has received the notification.
     */
    public static void updatePopupState(String playerId) {
        try {
            unifiedJedis.bfAdd(BLOOM_KEY, playerId);
        } catch (Exception e) {
            e.printStackTrace(); // Handle connection timeouts and other errors.
        }
    }

    /**
     * Sends a notification to the player if they haven't received one yet.
     */
    public static void handlePopup(String playerId) {
        if (shouldShowPopup(playerId)) {
            System.out.println("Push a notification to the player: " + playerId);
            updatePopupState(playerId);
        } else {
            System.out.println("Player " + playerId + " has already been notified.");
        }
    }

    public static void main(String[] args) {
        createBloom();
        String playerId = "player123";

        handlePopup(playerId); // Sends the notification on first login.
        handlePopup(playerId); // Skips the notification on subsequent logins.
    }
}

Expected output:

Push a notification to the player: player123
Player player123 has already been notified.

Choose a false positive rate

The error_rate parameter in bfReserve controls the trade-off between accuracy and memory. A lower rate improves accuracy but increases memory consumption.

RateUse when
1% (0.01) or higherAccuracy is not critical — for example, cache prefetching or recommendation systems. Uses less memory but has a higher false positive rate.
0.1% to 1% (0.001–0.01)Most scenarios — a reasonable balance between memory efficiency and accuracy.
0.01% (0.0001) or lowerA low false positive rate is highly critical — for example, security systems or financial applications. Uses more memory.

In the example, the Bloom filter is created with a 1% false positive rate and a capacity for 50,000 player IDs. Adjust these values based on your expected player base and accuracy requirements.

False positives and notification delivery

A false positive means the filter incorrectly reports that a player has already received a notification when they have not. The affected player misses one notification. For most game event scenarios, this is acceptable. If missing a notification is not acceptable—for example, for time-sensitive rewards—consider supplementing the Bloom filter with a secondary confirmation step.

Tair (Enterprise Edition) compatibility

The Bloom filter provided by Tair (Enterprise Edition) is compatible with the Redis Bloom filter and uses the same commands. See TairBloom commands for the full command reference.