すべてのプロダクト
Search
ドキュメントセンター

Tair (Redis® OSS-Compatible):Bloomフィルターを使用したゲームイベントプッシュ通知の管理

最終更新日:Dec 13, 2024

このトピックでは、Bloomフィルターを使用してゲーム操作でイベントプッシュ通知を管理し、プレイヤーへの繰り返し通知を防ぐ方法について説明します。 このトピックでは、Jedisを使用してTair (Enterprise Edition) インスタンスに接続し、Bloomフィルターで操作を実行する方法についても説明します。

背景情報

現代のゲーム運用では、ゲーム開発者や運用チームは、ユーザーの人気、エンゲージメント、支払い率を高めるためにさまざまなイベントを開始することがよくあります。 ほとんどの場合、イベントは、ポップアップウィンドウ、ゲーム内メッセージ、および非プレイヤーキャラクター (NPC) タスクによってプレイヤーにプッシュされます。 複雑なゲーム環境では、開発者は、繰り返し通知によるユーザーエクスペリエンスの低下を防ぐために、イベント通知をプッシュする頻度を制御しながら、システム効率を確保する必要があります。

このシナリオでは、ブルームフィルタデータ構造は、繰り返しポップアップ通知を制御するための効率的なソリューションを提供します。 ブルームフィルタは、要素がセットのメンバーであるかどうかを判断するために使用される確率的データ構造です。 ブルームフィルタは、要素が集合内にある可能性があるか、または集合内に全くないかを迅速に判定し、返す。 Bloomフィルターは、スペースの複雑さが低く、クエリが高速で、大規模なデータセットに適しています。 しかしながら、偽陽性が生じることもある。 その結果、ユーザは通知を見逃す可能性がある。

このシナリオでは、次の点でBloomフィルターが他のデータ構造よりも優れています。

  • 高効率: ブルームフィルタはビット配列を使用して大量のユーザーデータを保存します。

  • 低メモリ使用量: 従来のデータ構造と比較して、Bloomフィルターは、特に数百万人のプレーヤーのプッシュステータスを保存する場合、使用するスペースが大幅に少なくなります。

  • スケーラビリティ: Bloomフィルターはスケーラブルで、Redisクラスターなどの大規模な分散環境に適しています。

Tair (Enterprise Edition) が提供するBloomフィルターは、Redis Bloomフィルターと互換性があり、同じ方法で使用されます。

概要

次のセクションでは、Bloomフィルターを使用してゲームイベントプッシュ通知を管理する方法のサンプルコードを示します。

  1. Tair (Enterprise Edition) インスタンスに接続します。

  2. サンプルコードのcreateBloom関数を使用して、activity_popupという名前のBloomフィルターを作成します。

    この例では、ブルームフィルタは、50,000の要素を格納することが期待され、1% の偽陽性率を有する。

    偽陽性率に関する提案

    偽陽性率は、ブルームフィルタの重要なパラメータである。 セットにない要素が存在すると誤って識別された場合に、偽陽性が発生します。 より低い偽陽性率は、ブルームフィルタのより高い精度を示す。 しかし、より大きなメモリ空間が使用される。 したがって、偽陽性率の設定は、メモリ効率と精度との間のトレードオフを伴う。 ビジネス要件に基づいて偽陽性率を設定することを推奨します。

    • 低誤検出率 (0.01% 以下): セキュリティシステムや金融アプリケーションなど、低誤検出率が非常に重要なビジネスシナリオでは、誤検出率を0.01% 以下に設定できます。 しかし、これは、より高いメモリ使用量を犠牲にする。

    • 中程度の偽陽性率 (0.1% 〜1%): この偽陽性率は、ほとんどのシナリオにとって合理的な妥協である。 この偽陽性率は、高いメモリ効率と低い偽陽性率との間の良好なバランスを提供する。

    • 高い偽陽性率 (1% 以上): キャッシュプリフェッチやレコメンデーションシステムなど、精度が重要でないビジネスシナリオでは、偽陽性率を1% 以上に設定できます。 この場合、より少ないメモリ空間が使用されるが、偽陽性率は高い。

  3. プレイヤーがログインすると、サンプルコードのhandlePopup関数を使用してプレイヤーに通知をプッシュできます。

    その前に、サンプルコードのshouldShowPopup関数を使用してプッシュが必要かどうかを確認する必要があります。

    • プレイヤーIDがブルームフィルタに見つからない場合、通知はプレイヤーにプッシュされていません。 この場合、プレーヤーに通知をプッシュし、updatePopupState関数を使用してプレーヤーのプッシュステータスを更新する必要があります。

    • プレイヤーIDがすでにブルームフィルタに存在する場合、プレイヤーは通知を受信している可能性があります。 この場合、通知を再度プッシュしないでください。

サンプルコード

次の情報は、Jedisの依存関係を示しています。

pom.xmlファイルのMaven依存関係

この例では、Jedis 5.1.0がMavenの依存関係としてpom.xmlファイルに追加されます。

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

サンプルコード:

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);
    }
}

サンプル成功出力:

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