All Products
Search
Document Center

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

Last Updated:Dec 06, 2024

This topic describes how to manage event push notifications in game operations by using Bloom filters to prevent repetitive notifications to players. This topic also describes how to connect to a Tair (Enterprise Edition) instance and perform operations on Bloom filters by using Jedis.

Background information

In modern game operations, game developers and operations teams often launch various events to boost user popularity, engagement, or payment rates. In most cases, events are pushed to players by means of pop-up windows, in-game messages, and non-player character (NPC) tasks. In a complex game environment, developers need to ensure system efficiency while controlling the frequency of pushing event notifications to prevent the user experience from being degraded due to repetitive notifications.

In this scenario, the Bloom filter data structure provides an efficient solution to control repetitive pop-up notifications. A Bloom filter is a probabilistic data structure that is used to determine whether an element is a member of a set. A Bloom filter quickly determines and returns whether an element is possibly in a set or definitely not in a set. The Bloom filter offers low space complexity and fast query, which is suitable for large datasets. However, false positives may also be produced. As a result, a user could miss a notification.

In this scenario, Bloom filters outperform other data structures in the following aspects:

  • High efficiency: Bloom filters use bit arrays to store large amounts of user data.

  • Low memory usage: Compared with traditional data structures, Bloom filters use significantly less space, especially when storing the push status of millions of players.

  • Scalability: Bloom filters are scalable and well-suited for large-scale distributed environments, such as Redis clusters.

The Bloom filter provided by Tair (Enterprise Edition) is compatible with the Redis Bloom filter and is used in the same manner.

Overview

The following section provides sample code on how to use a Bloom filter to manage game event push notifications.

  1. Connect to a Tair (Enterprise Edition) instance.

  2. Create a Bloom filter named activity_popup by using the createBloom function in the sample code.

    In this example, the Bloom filter is expected to store 50,000 elements and has a false positive rate of 1%.

    Suggestions on the false positive rate

    The false positive rate is a key parameter for the Bloom filter. A false positive occurs when an element that is not in a set is incorrectly identified as being present. A lower false positive rate indicates a higher accuracy of the Bloom filter. However, a larger memory space is used. Therefore, setting the false positive rate involves a trade-off between memory efficiency and accuracy. We recommend that you set the false positive rate based on your business requirements:

    • Low false positive rate (0.01% or lower): In business scenarios in which a low false positive rate is highly critical, such as security systems or financial applications, you can set the false positive rate to 0.01% or lower. However, this comes at the cost of higher memory usage.

    • Medium false positive rate (0.1% to 1%): This false positive rate is a reasonable compromise for most scenarios. This false positive rate provides a good balance between high memory efficiency and low false positive rate.

    • High false positive rate (1% or higher): In business scenarios in which accuracy is not critical, such as cache prefetching or recommendation systems, you can set the false positive rate to 1% or even higher. In this case, less memory space is used, but the false positive rate is high.

  3. When a player logs in, you can push a notification to the player by using the handlePopup function in the sample code.

    Before you do so, you must check whether a push is required by using the shouldShowPopup function in the sample code.

    • If the player ID is not found in the Bloom filter, no notification has been pushed to the player. In this case, you must push a notification to the player and update the push status of the player by using the updatePopupState function.

    • If the player ID already exists in the Bloom filter, the player may have received a notification. In this case, do not push the notification again.

Sample code

The following information describes the Jedis dependency:

Maven dependency in the pom.xml file

In this example, Jedis 5.1.0 is added as a Maven dependency in the pom.xml file:

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

Sample code:

import redis.clients.jedis.*;
import redis.clients.jedis.UnifiedJedis;


public class TairBloomFilterDemo {
    static HostAndPort hostAndPort=new HostAndPort("r-bp1y****svonly41srpd.redis.rds.aliyuncs.com", 6379); // You can obtain the endpoint and port number of the instance in the console. 
    static JedisClientConfig config=DefaultJedisClientConfig.builder().password ("tw:Da***3").build(); // The account password of the instance. 
    static UnifiedJedis unifiedJedis = new UnifiedJedis(hostAndPort, config);
    private static final String BLOOM_KEY = "activity_popup";

    /**
    * Create a Bloom filter key. 
    */
    public static void createBloom() {
        try {
            unifiedJedis.bfReserve(BLOOM_KEY, 0.01, 50000);
        } catch (Exception e) {
            e.printStackTrace(); // Handle exceptions such as connection timeouts.
        }
    }

    /**
    * Check whether a specific player ID already exists in the Bloom filter. 
    */
    public static boolean shouldShowPopup(String playerId) {
        try {
            return !unifiedJedis.bfExists(BLOOM_KEY, playerId);
        } catch (Exception e) {
            e.printStackTrace(); // Handle exceptions such as connection timeouts.
            return true;
        }
    }

    /**
    * Add the player ID to the bloom filter key. 
    */
    public static void updatePopupState(String playerId) {
        try {
            unifiedJedis.bfAdd(BLOOM_KEY, playerId);
        } catch (Exception e) {
            e.printStackTrace(); // Handle exceptions such as connection timeouts. 
        }
    }

    /**
    * Push a notification to the specified player ID. 
    */
    public static void handlePopup(String playerId) {
        if (shouldShowPopup(playerId)) {
            // Push a notification. 
            System.out.println("Push a notification to the player: " + playerId);
            // Update the push status. 
            updatePopupState(playerId);
        } else {
            System.out.println("Player" + playerId + "Pushed");
        }
    }

    public static void main(String[] args) {
        createBloom();
        // Assume that the player ID is player123. 
        String playerId = "player123";

        // Push a notification in the first call. 
        handlePopup(playerId);

        // Do not push a notification in the second call. 
        handlePopup(playerId);
    }
}

Sample success output:

Push a notification to player123.
A notification has been pushed to player123.