我应该如何在Redis中对此进行建模?

时间:2013-05-17 21:21:30

标签: redis

仅供参考:Redis n00b。

我需要在我的网络应用中存储搜索字词。

每个术语都有两个属性:" search_count" (整数)和" last_searched_at" (时间)

示例I&尝试过:

Redis.hset("search_terms", term, {count: 1, last_searched_at: Time.now})

我可以想到一些不同的方法来存储它们,但没有好的方法来查询数据。我需要生成的报告是过去30天内的最佳搜索字词"。在SQL中,这将是一个where子句和一个order by。

我如何在Redis中做到这一点?我应该使用不同的数据类型吗?

提前致谢!

2 个答案:

答案 0 :(得分:4)

我会考虑两个有序集。

提交搜索term后,获取当前的timestamp和:

zadd timestamps timestamp term
zincrby counts 1 term

以上两个操作应该是原子的。

然后查找给定时间间隔timestamp_fromtimestamp_to中的所有字词:

zrangebyscore timestamps timestamp_from timestamp_to

获得这些后,循环遍历它们并从counts获取计数。

或者,我很好奇你是否可以使用zunionstore。这是我在Ruby中的测试:

require 'redis'

KEYS = %w(counts timestamps results)
TERMS = %w(test0 keyword1 test0 test1 keyword1 test0 keyword0 keyword1 test0)

def redis
  @redis ||= Redis.new
end

def timestamp
  (Time.now.to_f * 1000).to_i
end

redis.del KEYS

TERMS.each {|term|
  redis.multi {|r|
    r.zadd 'timestamps', timestamp, term
    r.zincrby 'counts', 1, term
  }
  sleep rand
}

redis.zunionstore 'results', ['timestamps', 'counts'], weights: [1, 1e15]

KEYS.each {|key|
  p [key, redis.zrange(key, 0, -1, withscores: true)]
}

# top 2 terms
p redis.zrevrangebyscore 'results', '+inf', '-inf', limit: [0, 2]

编辑:在某些时候,您需要清除counts集。类似于@Eli建议的东西(https://stackoverflow.com/a/16618932/410102)。

答案 1 :(得分:2)

取决于您想要优化的内容。假设您希望能够非常快速地运行该查询并且不介意花费一些内存,我将按照以下方式执行此操作。

  1. 每看一次搜索就保持一个键(如果你愿意,你可以或多或少地去细化)。键应该指向$search_term -> $count的散列,其中$ count是第二次看到$ search_term的次数。
  2. 为每个时间间隔保留另一个密钥(我们称之为$ time_int_key),你需要数据(在你的情况下,这只是你的间隔是最后30天的一个密钥)。这应该指向一个有序集合,其中集合中的项目是过去30天内查看的所有搜索字词,它们排序的分数是过去30天内看到的次数。
  3. 让背景工作者每秒抓住30天前发生的第二个密钥并循环附加到它的散列。对于该键中的每个$ search_term,它应该从$ time_int_key中与$ search_term相关联的分数中减去$ count
  4. 这样,您可以使用ZRANGE $time_int_key 0 $m在O(log(N)+ m)时间内获取最顶层搜索([WITHSCORES],如果您想要搜索它们的金额)。这非常便宜,能够在Redis中以任意频率运行几乎任何合理的m并始终实时更新数据。