27

みなさん、こんにちは。よろしくお願いします。私はNoSQLゲームを初めて使用しますが、現在の勤務先では、いくつかのビッグデータのセット比較を行う必要があります。

私たちのシステムには、顧客タグセットとターゲットタグセットがあります。タグは8桁の数字です。
顧客のタグセットには最大300個のタグがあり、平均で100個のタグがあります
。ターゲットのタグセットには最大300個のタグがありますが、平均は40個のタグです。

10億人のユーザーの潜在的な顧客ベースを狙っているので、事前計算はオプションではありません。

(これらのタグは階層的であるため、1つのタグがあるということは、その親タグと祖先タグもあることを意味します。その情報は今のところ脇に置いておきます。)

顧客が私たちのサイトにアクセスしたとき、私たちは彼らのタグセットを100万のターゲットタグセットとできるだけ早く交差させる必要があります。顧客セットには、一致するターゲットセットのすべての要素が含まれている必要があります。

私は自分の選択肢を模索してきましたが、Redisの交差点は理想的だと思われます。しかし、インターネットを介したトローリングでは、100万個のタグセットを保持するために必要なRAMの量は明らかになりませんでした。交差点は非常に高速であると思いますが、これはRedisで実行可能なソリューションです。

これはブルートフォースで非効率的だと思います。また、この種の問題が過去にどのように処理されたかについての提案を得るための手段として、この質問を使用したいと思いました。前に述べたように、タグはツリーに保存されます。考えられる解決策としてMongodbも検討し始めました。

再度、感謝します

4

3 に答える 3

29

これは興味深い問題であり、Redisがここで役立つと思います。

Redisは、最適化された「intset」形式を使用して整数のセットを格納できます。詳細については、 http://redis.io/topics/memory-optimizationを参照してください。

ここでの正しいデータ構造は、ターゲットタグセットのコレクションに加えて、タグをターゲットタグセットにマップするための逆インデックスであると思います。

2つのターゲットタグセットを保存するには:

 0 -> [ 1 2 3 4 5 6 7 8 ]
 1 -> [ 6 7 8 9 10 ]

私は使うだろう:

 # Targeted tag sets
 sadd tgt:0 1 2 3 4 5 6 7 8
 sadd tgt:1 2 6 7 8 9 10
 # Reverse index
 sadd tag:0 0
 sadd tag:1 0
 sadd tag:2 0 1
 sadd tag:3 0
 sadd tag:4 0
 sadd tag:5 0
 sadd tag:6 0 1
 sadd tag:7 0 1
 sadd tag:8 0 1
 sadd tag:9 1
 sadd tag:10 1

この逆インデックスは、ターゲットタグセットがシステムに追加/システムから削除されたときに維持するのが非常に簡単です。

グローバルメモリ消費量は、複数のターゲットタグセットに共通するタグの数によって異なります。疑似データをRedisに保存し、メモリ消費をシミュレートするのは非常に簡単です。単純なnode.jsスクリプトを使用して実行しました。

100万のターゲットタグセット(タグは8桁の数字、セットあたり40タグ)の場合、ターゲットタグセットによって共有されるタグが非常に少ない場合(リバースインデックスに3200万以上のエントリ)、メモリ消費量は4GBに近くなります。タグが大量に共有される場合は約500MB(リバースインデックスのエントリは100Kのみ)。

このデータ構造を使用すると、特定の顧客のすべてのタグを含むターゲットタグセットを見つけることが非常に効率的です。

1- Get customer tag set (suppose it is 1 2 3 4)
2- SINTER tag:1 tag:2 tag:3 tag:4
   => result is a list of targeted tag sets having all the tags of the customer

Redisはカーディナリティごとにセットを注文するのに十分スマートであり、カーディナリティが最も低いセットから開始するため、交差操作は効率的です。

これで、逆の操作を実装する必要があることを理解しました(つまり、顧客タグセットにすべてのタグがあるターゲットタグセットを見つける)。逆インデックスはまだ役立ちます。

ここに醜い擬似コードの例があります:

1- Get customer tag set (suppose it is 1 2 3 4)
2- SUNIONSTORE tmp tag:1 tag:2 tag:3 tag:4
   => result is a list of targeted tag sets having at least one tag in common with the customer
3- For t in tmp (iterating on the selected targeted tag sets)
      n = SCARD tgt:t (cardinality of the targeted tag sets)
      intersect = SINTER customer tgt:t
      if n == len(intersect), this targeted tag set matches

したがって、100万のターゲットタグセットに対して顧客タグセットをテストする必要はありません。逆インデックスを使用して、検索の範囲を許容可能なレベルに制限できます。

于 2012-06-19T20:10:02.873 に答える
6

これは役立つかもしれません:

ケーススタディ:Redisの使用は、非常に大きなセット(120M+と120M+)で交差します

http://redis4you.com/articles.php?id=016&name=Case+Study%3A+Using+Redis+intersect+on+very+large+sets

于 2012-08-29T15:34:53.387 に答える
5

提供された答えは最初私を助けました。しかし、顧客ベースが拡大するにつれて、redis文字列ビットとビット演算子を使用して数億人のユーザーの分析を非常に迅速に実行するという優れた手法に出くわしました。

この記事をチェックしてください。redisの作成者であるAntirezもこれをよく参照しています。

http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/

于 2013-02-20T20:50:08.990 に答える