Redis(Remote Dictionary Server)は、非常に人気のあるメモリ内のKey-Valueストアであり、オプションの耐久性、パーティショニング、レプリケーション、およびその他の多くの機能も提供します。これは現在最も人気のあるKey-Valueデータベースであり、そのシンプルさ、メモリフットプリントの低さ、学習曲線の低さで知られています。 Redisはデータ構造サーバーとも呼ばれ、ハッシュ、リスト、セット、並べ替えられたセット、ビットマップ、ハイパーログなどのデータ構造に対するアトミック操作をサポートしています。この投稿では、Redisが提供するセットのデータ型と、その使用法および実際の使用例を見ていきます。
Redisセット
Redisセットは、文字列の順序付けられていないコレクションです(文字列は、ほとんどすべてを含むことができる基本的なRedis値です)。これにより、一定の時間の追加、削除、およびメンバーシップのチェックが行われます。 Redisは、セット間の適度に高速な和集合、共通部分、および減算演算もサポートします。予想どおり、値を繰り返すことはできません。
これは、 redis-cliからのRedisセットの動作例です。 。以下の例の主要な表現の概要は次のとおりです。
- users:all Webサイトに登録されているすべてのユーザーのセットを表します。
- users:actv アクティブユーザーを表します。
- users:inactv 非アクティブなユーザー(しばらくサイトにアクセスしていないユーザー)を表します。
# sadd key member [member ...] : add members to a set 127.0.0.1:6379> sadd users:all 11 12 13 14 15 Rocket Pocket Socket (integer) 8 127.0.0.1:6379> type users:all set # smembers key: get all members of a set 127.0.0.1:6379> smembers users:all 1) "Pocket" 2) "11" 3) "Socket" 4) "13" 5) "14" 6) "Rocket" 7) "12" 8) "15" # sismember key member: is the given value a member of the set? 127.0.0.1:6379> sismember users:all 00 (integer) 0 127.0.0.1:6379> sismember users:all 11 (integer) 1 127.0.0.1:6379> sismember users:all Socket (integer) 1 127.0.0.1:6379> sadd users:inactv 11 12 13 (integer) 3 # sinter key [key ...]: Intersection of multiple sets # Similar: sinterstore stores the result of intersection of sets to a new set 127.0.0.1:6379> sinter users:all users:inactv 1) "11" 2) "12" 3) "13" # scard key: cardinality of the set i.e. number of members present in the set 127.0.0.1:6379> scard users:all (integer) 8 # sdiff key [key ...] : Subtract multiple sets # Similar: sdiffstore: subtract and store result in a new destination set 127.0.0.1:6379> sdiff users:all 1) "Pocket" 2) "11" 3) "Socket" 4) "13" 5) "14" 6) "12" 7) "Rocket" 8) "15" 127.0.0.1:6379> sdiff users:all users:inactv 1) "14" 2) "Pocket" 3) "Rocket" 4) "Socket" 5) "15" # sdiffstore destination key [key ...] 127.0.0.1:6379> sdiffstore users:actv users:all users:inactv (integer) 5 127.0.0.1:6379> smembers users:actv 1) "14" 2) "Pocket" 3) "Rocket" 4) "Socket" 5) "15" 127.0.0.1:6379> sdiff users:all users:actv users:inactv (empty list or set) # smove source destination member: move a member from source set to destination. 127.0.0.1:6379> smove users:inactv users:actv 11 (integer) 1 127.0.0.1:6379> smembers users:actv 1) "Pocket" 2) "11" 3) "Socket" 4) "14" 5) "Rocket" 6) "15"
その他の重要な設定コマンドには次のものがあります:
- SUNION –和集合を設定
- SPOP –要素をランダムに削除します
- SREM –1つ以上の要素を削除します
セットに関連するRedisコマンドの完全なリストはここにあります。
Redisの内部
Redisはセットを辞書として内部的に保存します。 Redisのディクショナリは、ハッシュ関数MurmurHash2を使用するハッシュテーブルとして実装され、増分サイズ変更によって拡張されます。ハッシュの衝突は連鎖によって処理されます。セットのすべてのメンバーがIntSetsと呼ばれる64ビット符号付き整数の範囲#の基数10にある場合、セットには小さなセット用の特別なエンコードがあります。これは基本的に、ソートされた整数の配列です。配列内の検索は、バイナリ検索によって実行されます。明らかに、この実装は非常に小さなセットに対して効率的です。このエンコーディングが使用されるサイズは、 set-max-intset-entriesによって管理されます。 構成パラメーター。デフォルト値は512です。Redisで使用される内部データ構造の適切な説明はここにあります。
Redisアプリケーション
これは、可能なRedisSetアプリケーションのいくつかの小さなリストです:
- セットとして、一意のアイテムを追跡するために使用できます:
- サイトにアクセスするすべての一意のIPアドレス。
- 現在特定の状態にあるすべての一意のジョブインスタンスなど。
- 繰り返しになりますが、セットとして、「に属する」または同様の関係を示すために使用できます。
- 特定のカテゴリに属するすべてのSKU。
- 特定のタグなどを持つすべてのオブジェクト
- セットは、関係を組み合わせるためにのみ使用できます。つまり、セットの和集合/共通部分/減算:
- Tシャツのカテゴリに属するが、ポロネックのサブカテゴリには属さないすべてのSKU。
実際の例を取り上げて、セットに関連するユースケースをさらに詳しく見ていきましょう。
電子書籍ストア用のビジュアルプロファイラー
あなたが何百万ものタイトルを掲載している非常に大規模なオンライン書店のオーナーだとしましょう。プライマリデータベースはMongoDBであり、インデックス作成やシャーディングなどを正しく使用することで、ほとんどのユースケースでかなり良好に機能します。本の部分的なDBドキュメントスキーマを次に示します。 コレクション:
... sku: SKU, pid: Product ID, title: String, auth: String, pub: String, isbn: ISBN, edition: Int, price: Float, rating: Float, cats: [String, String ...], tags: [String, String ...], ...
また、 txnsというコレクションにトランザクションを記録します 次のようになります:
txnid: TxnID, cid: CustomerID, amnt: Float, curr: Currency, sku: [sku1, sku2, ...], time: TimeStamp, ...
そして、 views:と呼ばれるビューのコレクション
time: TimeStamp, # daily aggregated cid: CustomerID, sku: [sku1, sku2, ...], ...
明らかに、これは非常に単純化された例であり、幅広い前提があります。私たちの目的は、(ほぼ)実際のシナリオでRedisセットの例を示すことです。
わかりました。ストアマネージャーとして、さまざまなカテゴリの関係と顧客の行動を分析するためのビジュアルプロファイラーツールが必要です。例:
- 最も人気のあるカテゴリは何ですか?
- サイエンスフィクションを見ている、または購入している人はノンフィクションも見ていますか?
これをリアルタイムで実行できるようにする必要があります。つまり、プロファイラーのUIがボックス、パラメーターを変更できるボタンにチェックマークを付け、結果を(ほぼ)すぐに表示します。
MongoDBでこのような操作を行うには、さまざまなカテゴリ、タグ、その他の気になるデータを結合するために、かなり複雑なクエリを実行する必要があります。メモリ内に収まらないワーキングセットでは、これらは最速の操作ではありません。例:
- 本日販売されたフィクションであり、サイエンスフィクションではないすべての本を見つけるには、 txnにクエリを実行する必要があります。 今日のトランザクションのコレクション。次に、SKUを繰り返し処理してカテゴリを収集し、$ in /$nin操作を実行します。
Redisをミックスに取り入れることで、これがどのように処理されるかを見てみましょう。毎日の終わりに、毎日スケジュールされたジョブをこれらのMongoDBコレクションに対して実行して、Redisセットを作成できます。作成するセットの種類は、フロントエンドでサポートするフィルターの種類によって異なります。たとえば、カテゴリ関連のクエリをサポートしたい場合は、次のようなセットを作成します。
cat:type:catID cat:sku:fiction cat:sku:nonfiction cat:sku:scfiction cat:sku:history cat:sku:milhistory cat:sku:military ... cat:cid:fiction cat:cid:nonfiction cat:cid:scfiction cat:cid:history cat:cid:milhistory cat:cid:military ...
cat:sku:*セットには、そのカテゴリで本日販売/閲覧された書籍のSKUが含まれます。同様に、cat:cid:*には、そのカテゴリの本を購入/販売した顧客のCIDが含まれます。これらのセットで回答できるクエリのサンプルは次のとおりです。
- 今日フィクション(単一カテゴリ)の本を閲覧/購入した顧客(または顧客数):メンバーcat:cid:fiction
- 今日、軍事史ではなく歴史を閲覧/購入したお客様: sdiff cat:cid:history cat:cid:milhistory
- (数)今日販売されたサイエンスフィクションとミリタリーの本、つまりミリタリーサイエンスフィクション: inter cat:sku:scfiction cat:sku:military
- 必要な和集合、共通部分、差分演算の数。
これ自体が非常に強力なクエリ機能を提供します。セットを追加しましょう!たとえば、書評に基づいて追加のセットを作成します。例:
rat:sku:5str: Set of books with ratings > 4.5 rat:sku:4str: Set of books with ratings > 3.5 && <= 4.5 rat:sku:3str: ... rat:sku:2str: ... ... rat:cid:5str: Set of customer who bought books with ratings as mentioned above. rat:cid:4str: ... ..
これらのセットを装備すると、次のようなものをすばやく見つけることができるようになります:
- 本日購入した4つ星以上の評価のフィクション本: sunionstore rat:sku:4strabv rat:sku:5str rat:sku:5str / synter rat:sku:4strabv cat :sku:fiction
- 歴史上3つ星以上の本を購入したお客様: sunionstore rat:cid:5strabv rat:cid:3str rat:cid:5str rat:cid:5str / synter cat:cid:history rat:cid:5strabv
ここで、今日占星術の本を2以下の評価で購入したすべての顧客に割引クーポンを送信したいとします(悪い経験に対するお詫びとして)その本を読まなければならないことの!)。 CustomerIDのリストをエクスポートできます sを送信し、電子メールアプリケーションに送信します。同様に、タグや価格帯など、ビジュアルプロファイラーでフィルターとして公開したい他のもののセットを作成することもできます。
Redisセットを使用する利点はここで明らかです。インメモリストアは、フロントエンドがスッキリと感じるように、非常に高速なアクセスにつながります。さらに、Redisセット操作は定数時間または線形のいずれかです。
結論
この投稿では、最も有用なRedisデータ構造の1つであるセットを例を挙げて紹介しました。 Redisデータ構造シリーズの他の投稿の一部を次に示します。
- Redisハッシュ
- Redisビットマップ
- Redisセット
- Redisの並べ替えられたセット