0

多くの異なるアイテムがあり、各アイテムへのヒット数を追跡​​し、特定の日時範囲内の各アイテムのヒット数を毎秒までクエリしたいと考えています。

だから私はヒットを並べ替えられたセットに保存し始めました。たとえば、毎秒(UNIXエポック時間)に1つの並べ替えられたセットです:

zincrby ItemCount:1346742000 item1 1    
zincrby ItemCount:1346742000 item2 1
zincrby ItemCount:1346742001 item1 1
zincrby ItemCount:1346742005 item9 1

特定の日付範囲内の各アイテムの総ヒット数を取得するには、次のようにします。

1. Given a start datetime and end datetime:
   Calculate the range of epochs that fall under that range.

2. Generate the key names for each sorted set using the epoch values example:
   ItemCount:1346742001, ItemCount:1346742002, ItemCount:1346742003

3. Use Union store to aggregate all the values from different sorted sets 

   ZUINIONSTORE _item_count KEYS....

4. To get the final results out:

   ZRANGE _item_count 0, -1 withscores

それはちょっとうまくいきますが、1か月のような大きな日付範囲がある場合、ステップ1と2から計算されたキー名の数が数百万(1日あたり86400エポック値)になると問題が発生します。このような多数のキーがあると、ZUINIONSTORE コマンドが失敗し、ソケットが壊れます。さらに、ループして多くのキーを生成するには時間がかかります。

これを Redis でより効率的な方法で設計し、追跡の粒度を数分や数日ではなく数秒にまで抑えるにはどうすればよいでしょうか。

4

1 に答える 1

0

ええ、ソートされたセットの大きなユニオンは避けるべきです。アイテムが 1 秒あたりに取得できる最大ヒット数を知っていると仮定すると、できる便利なトリックです。

  1. スコアと値の両方としてタイムスタンプを持つアイテムごとのソート済みセット。
  2. ただし、スコアを書き込んだ最初のクライアントでない場合、スコアは 1/(max_predicted_hits_per_second) ずつ増加します。このように、小数点の後の数値は常に hits/max_predicted_hits_per second ですが、範囲クエリを実行することもできます。

max_predicted_hits_per_second が 1000 だとしましょう。

#1. make sure only one client adds the actual timestamp, 
#by doing SETNX to a temporary key)

now = int(time.time())
rc = redis.setnx('item_ts:%s' % itemId, now)


#just the count part
val = float(1)/1000
if rc: #we are the first to incement this second
   val += now
   redis.expire('item_ts:%s' % itemId, 10) #we won't need that anymore soon, assuming all clients have the same clock

#2 increment the count
redis.zincrby('item_counts:%s' % itemId, now, amount = val) 

範囲のクエリは次のようになります。

counts = redis.zrangebyscore('item_counts:%s' % itemId, minTime, maxTime + 0.999, withscores=True)

total = 0
for value, score in counts:
    count = (score - int(value))*1000
    total += count
于 2012-06-05T09:36:11.050 に答える