how should I store this data in redis using native commands?

111 views
Skip to first unread message

jason

unread,
Oct 4, 2010, 1:26:20 PM10/4/10
to Redis DB
For each special page on my website, I want to store which user
accessed that page.
If I was using ruby, I would write something like:
special_pages = {}
special_pages[page_name] << username1
special_pages[page_name] << username2
I dont see how in redis I can store this using the native commands, I
don't want to pull the data out from redis and then process the data
locally and restore that data.
Is there a better way I should do this?

Mason Jones

unread,
Oct 4, 2010, 1:54:45 PM10/4/10
to redi...@googlegroups.com
Most likely what you would want to do in this case is to maintain a
set or list (depending on how you plan to use this data later), and
when a user visits a page, you would add the user to the set/list. If
you use a consistent key naming approach, then it will prevent
duplicates from being added.

Knowing how you plan to use this data later would help in recommending
the exact approach, since of course putting data in is only half the
problem!

> --
> You received this message because you are subscribed to the Google Groups "Redis DB" group.
> To post to this group, send email to redi...@googlegroups.com.
> To unsubscribe from this group, send email to redis-db+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/redis-db?hl=en.
>
>

jason

unread,
Oct 4, 2010, 3:09:11 PM10/4/10
to Redis DB
I want to use a list, but I was unable to see how I could do that with
a single redis command instead of processing the data on the client
side.
I will use the data to see what users are being visited the most, and
who each user is visiting the most.

Mason Jones

unread,
Oct 4, 2010, 4:06:13 PM10/4/10
to redi...@googlegroups.com
If what you're doing is keeping track of which users are visiting a
page the most, then I'd recommend looking at the sorted sets, and in
particular the ZINCRBY command. If you also want to keep track of
which pages are visited the most, then the most efficient way is
likely to have another sorted set for each page, with a score. When a
page is visited, you increment its score in that set, and then you can
also increment the user's score in the set dedicated to that page. You
can then also do interesting things like intersect/union sets to
aggregate user information.

jason

unread,
Oct 7, 2010, 9:57:50 PM10/7/10
to Redis DB
I also need to store the Time someone visits. So I am trying to do it
like so with ruby:
def increment_user login
r = Redis.new
hash = "user_hits"
r.multi do
times = Marshal.load(r.hget(hash, login)) rescue nil
if times && times.kind_of?(Array)
times << Time.now
else
times = [Time.now]
end
r.hset hash,login, Marshal.dump(times)
end
end



A couple of questions, when I do the r.hget(hash,login), I get
"QUEUED" returned. Can I get data inside of a transaction? Is there
a better way to do this then the way I am trying to implement it now?

Josiah Carlson

unread,
Oct 8, 2010, 1:21:42 AM10/8/10
to redi...@googlegroups.com
At some point in the future, there will be a method to script Redis
from within Redis itself, but it will only work with the internal
structures.

You are probably better off using the native Redis list rather than
using Ruby's marshalling, as your entire function could be replaced
with a single LPUSH. To get your list of logins for a user, along
with the user data would require 2 commands, but you can do that with
a pipeline.

- Josiah

jason

unread,
Oct 8, 2010, 11:14:37 AM10/8/10
to Redis DB
I was thinking of using lists before, but one thing I noticed is that
there is no way to get a whole list returned to me? So if I use lpush,
are ou recommending that I put the person's name in a "hash" inside of
the list, so something like
user_hits is the redis list. Then each item is {:login =>
'foo', :time > Time.now}

How would I query for a login name?
I was also thinking about trying to store a list inside a hash in
native redis commands, but I didn't see how I could do that.

Josiah Carlson

unread,
Oct 8, 2010, 11:46:36 AM10/8/10
to redi...@googlegroups.com
On Fri, Oct 8, 2010 at 8:14 AM, jason <ja...@sanbit.com> wrote:
> I was thinking of using lists before, but one thing I noticed is that
> there is no way to get a whole list returned to me? So if I use lpush,

LRANGE key 0 -1

> are ou recommending that I put the person's name in a "hash" inside of
> the list, so something like
> user_hits is the redis list.  Then each item is {:login =>
> 'foo', :time > Time.now}

You can do that by marshalling your hashes into a list item (because
Redis doesn't support nested structures), but there would be a lot of
wasted space with all of the 'login' and 'time' and actual login
names. No, what I'm suggesting is you use...

LPUSH login_times:<user> <current time>

If you want to get the most recent 10 login times for one user:

LRANGE login_times:<user> 0 9

You can't see system-wide who has logged in the latest with this
simple method, but if you add a single zset...

ZADD login_times <current time> <user>

Then you can fetch the most recent login times for all users with:

ZRANGE login_times 0 -1 WITHSCORES

Or you can find out the most recent 10 logged-in users with:

ZREVRANGE login_times 0 9 WITHSCORES

> How would I query for a login name?

See the above use of LRANGE.

> I was also thinking about trying to store a list inside a hash in
> native redis commands, but I didn't see how I could do that.

You can't, Redis currently only supports non-nested structures.

- Josiah

jason

unread,
Oct 8, 2010, 5:38:09 PM10/8/10
to Redis DB
Josiah, very informative, thank you for the information
Reply all
Reply to author
Forward
0 new messages