sql >> データベース >  >> NoSQL >> Redis

RedisのZRANKで同じスコアに対して同じランクを取得するにはどうすればよいですか?

    実際のソリューションは、元の質問にはない要件に適合する必要があります。私の最初の答えは小さなデータセットを想定していましたが、少なくともO(N)で密なランキングが行われるため(たとえば、Luaを介して)、このアプローチは拡張できません。

    したがって、スコアを持つユーザーが多数いると仮定すると、for_stackが提案した方向は、複数のデータ構造が組み合わされた方が適切です。これが彼の最後の発言の要点だと思います。

    ユーザーのスコアを保存するには、ハッシュを使用できます。概念的には、単一のキーを使用してすべてのユーザースコアのハッシュを保存できますが、実際には、スケーリングするようにハッシュをハッシュする必要があります。この例を簡単にするために、ハッシュスケーリングは無視します。

    これは、Luaでユーザーのスコアを追加(更新)する方法です:

    local hscores_key = KEYS[1]
    local user = ARGV[1]
    local increment = ARGV[2]
    local new_score = redis.call('HINCRBY', hscores_key, user, increment)
    

    次に、個別のスコア値ごとの現在のユーザー数を追跡して、そのための別のハッシュを保持します。

    local old_score = new_score - increment
    local hcounts_key = KEYS[2]
    local old_count = redis.call('HINCRBY', hcounts_key, old_score, -1)
    local new_count = redis.call('HINCRBY', hcounts_key, new_score, 1)
    

    さて、私たちが維持する必要がある最後のことは、ソートされたセットを使用したスコアごとのランクです。新しいスコアはすべてzsetのメンバーとして追加され、ユーザーがいないスコアは削除されます:

    local zdranks_key = KEYS[3]
    if new_count == 1 then
      redis.call('ZADD', zdranks_key, new_score, new_score)
    end
    if old_count == 0 then
      redis.call('ZREM', zdranks_key, old_score)
    end
    

    ソートされたセットを使用するため、この3ピーススクリプトの複雑さはO(logN)ですが、Nはシステム内のユーザーではなく、個別のスコア値の数であることに注意してください。ユーザーの密なランキングを取得するには、別の短くて単純なスクリプトを使用します。

    local hscores_key = KEYS[1]
    local zdranks_key = KEYS[2]
    local user = ARGV[1]
    
    local score = redis.call('HGET', hscores_key, user)
    return redis.call('ZRANK', zdranks_key, score)
    


    1. 2016年の流星生産データベースへのアクセス

    2. MongoDBで最大のドキュメントサイズを見つける

    3. MongoDBでドキュメントを管理する方法

    4. Redis —大きな地図を保存するための最良の方法(辞書)