Complex MulitMap / Reduce - From Stackoverflow

94 views
Skip to first unread message

Paul

unread,
Jan 27, 2012, 3:47:05 PM1/27/12
to ravendb
As requested I will bring my discussion here regarding my query.

I want to list a paged view of audio items on my website, an audio
item has several standard properties such as title & description. It
also stores multiple Tags & a Genre document, but I also want to
display some statistics for each of my audio items, there are 10 in
total:

- Total Downloads
- Total Plays
- Total Likes
- Total Favourites
- Total Comments
- This Weeks Comments
- This Weeks Plays
- This Weeks Likes
- This Weeks Favourites
- This Weeks Comments

Here are the related documents:

Audio
- Title
- Desc
- ArtistName
- AudioComment
- Tags (embed a collection of tag documents here)
- Genre (embed a genre document here)

AudioComment
- AudioId
- Comments (collection)

Genre
- Id
- Code
- Name

Tag
- Id
- Name

AudioCounters
- AudioId
- Type (play / download)
- Ip
- DateTime

Likes
- AudioId
- AccountId
- DateTime

Favs
- AudioId
- AccountId
- DateTime

The weekly counters are basically a count of the stats for the past 7
days only.

The map reduce index I have at the moment even though it looks pretty
complex works very well and pulls back results in under 10ms.

Here is the index again:

public class AudioWithCounters :
AbstractMultiMapIndexCreationTask<AudioWithCounters.AudioViewModel>
{
public class AudioViewModel
{
public string Id { get; set; }
public string ArtistName { get; set; }
public string Name { get; set; }
public string Identifier { get; set; }
public string Description { get; set; }
public IList<Tag> Tags { get; set; }
public Genre Genre { get; set; }
public DateTimeOffset? DateAdded { get; set; }
public UserImage Image { get; set; }
public int TotalComments { get; set; }
public int TotalDownloads { get; set; }
public int TotalPlays { get; set; }
public int TotalLikes { get; set; }
public int TotalFavourites { get; set; }
public int WeeksComments { get; set; }
public int WeeksDownloads { get; set; }
public int WeeksPlays { get; set; }
public int WeeksLikes { get; set; }
public int WeeksFavourites { get; set; }
}

public AudioWithCounters()
{
AddMap<Audio>(audios => from audio in audios
select new
{
Id = audio.Id,
ArtistName = audio.ArtistName,
Name = audio.Name,
Identifier = audio.Identifier,
Description =
audio.Description,
Tags = audio.Tags,
Genre = audio.Genre,
DateAdded = audio.DateAdded,
Image = audio.Image,
TotalDownloads = 0,
TotalComments =
audio.CommentsCount,
TotalPlays = 0,
TotalLikes = 0,
TotalFavourites = 0,
WeeksDownloads = 0,
WeeksPlays = 0,
WeeksComments = 0,
WeeksLikes = 0,
WeeksFavourites = 0
});

AddMap<AudioComments>(comments => from audioComment in
comments
from comment in
audioComment.Comments
where comment.CreatedAt
>= DateTimeOffset.Now.AddDays(-7)
select new
{
Id = audioComment.Audio.Id,
ArtistName = (string)null,
Name = (string)null,
Identifier = (string)null,
Description = (string)null,
Tags = (object)null,
Genre = (object)null,
DateAdded = (object)null,
Image = (object)null,
TotalDownloads = 0,
TotalComments = 0,
TotalPlays = 0,
TotalLikes = 0,
TotalFavourites = 0,
WeeksDownloads = 0,
WeeksPlays = 0,
WeeksComments = 1,
WeeksLikes = 0,
WeeksFavourites = 0
});


AddMap<AudioCounter>(counters => from counter in counters
where counter.Type ==
Core.Enums.Audio.AudioCounterType.Download
select new
{
Id = counter.AudioId,
ArtistName = (string)null,
Name = (string)null,
Identifier = (string)null,
Description = (string)null,
Tags = (object)null,
Genre = (object)null,
DateAdded = (object)null,
Image = (object)null,
TotalDownloads = 1,
TotalComments = 0,
TotalPlays = 0,
TotalLikes = 0,
TotalFavourites = 0,
WeeksDownloads = 0,
WeeksPlays = 0,
WeeksComments = 0,
WeeksLikes = 0,
WeeksFavourites = 0
});

AddMap<AudioCounter>(counters => from counter in counters
where counter.Type ==
Core.Enums.Audio.AudioCounterType.Play
select new
{
Id = counter.AudioId,
ArtistName =
(string)null,
Name = (string)null,
Identifier =
(string)null,
Description =
(string)null,
Tags = (object)null,
Genre = (object)null,
DateAdded =
(object)null,
Image = (object)null,
TotalDownloads = 0,
TotalPlays = 1,
TotalComments = 0,
TotalLikes = 0,
TotalFavourites = 0,
WeeksDownloads = 0,
WeeksPlays = 0,
WeeksComments = 0,
WeeksLikes = 0,
WeeksFavourites = 0
});

AddMap<AudioCounter>(counters => from counter in counters
where counter.Type ==
Core.Enums.Audio.AudioCounterType.Download
where counter.DateTime >=
DateTimeOffset.Now.AddDays(-7)
select new
{
Id = counter.AudioId,
ArtistName =
(string)null,
Name = (string)null,
Identifier =
(string)null,
Description =
(string)null,
Tags = (object)null,
Genre = (object)null,
DateAdded =
(object)null,
Image = (object)null,
TotalDownloads = 0,
TotalPlays = 0,
TotalComments = 0,
TotalLikes = 0,
TotalFavourites = 0,
WeeksDownloads = 1,
WeeksPlays = 0,
WeeksComments = 0,
WeeksLikes = 0,
WeeksFavourites = 0
});

AddMap<Like>(likes => from like in likes
select new
{
Id = like.AudioId,
ArtistName =
(string)null,
Name = (string)null,
Identifier =
(string)null,
Description =
(string)null,
Tags = (object)null,
Genre = (object)null,
DateAdded =
(object)null,
Image = (object)null,
TotalDownloads = 0,
TotalPlays = 0,
TotalComments = 0,
TotalLikes = 1,
TotalFavourites = 0,
WeeksDownloads = 0,
WeeksPlays = 0,
WeeksComments = 0,
WeeksLikes = 0,
WeeksFavourites = 0
});

AddMap<Favourite>(favs => from fav in favs
select new
{
Id = fav.AudioId,
ArtistName = (string)null,
Name = (string)null,
Identifier = (string)null,
Description = (string)null,
Tags = (object)null,
Genre = (object)null,
DateAdded = (object)null,
Image = (object)null,
TotalDownloads = 0,
TotalPlays = 0,
TotalComments = 0,
TotalLikes = 0,
TotalFavourites = 1,
WeeksDownloads = 0,
WeeksPlays = 0,
WeeksComments = 0,
WeeksLikes = 0,
WeeksFavourites = 0
});

AddMap<AudioCounter>(counters => from counter in counters
where counter.Type ==
Core.Enums.Audio.AudioCounterType.Play
where counter.DateTime >=
DateTimeOffset.Now.AddDays(-7)
select new
{
Id = counter.AudioId,
ArtistName =
(string)null,
Name = (string)null,
Identifier =
(string)null,
Description =
(string)null,
Tags = (object)null,
Genre = (object)null,
DateAdded =
(object)null,
Image = (object)null,
TotalDownloads = 0,
TotalPlays = 0,
TotalComments = 0,
TotalLikes = 0,
TotalFavourites = 0,
WeeksDownloads = 1,
WeeksPlays = 0,
WeeksComments = 0,
WeeksLikes = 0,
WeeksFavourites = 0
});

AddMap<Like>(likes => from like in likes
where like.DateCreated >=
DateTimeOffset.Now.AddDays(-7)
select new
{
Id = like.AudioId,
ArtistName = (string)null,
Name = (string)null,
Identifier = (string)null,
Description = (string)null,
Tags = (object)null,
Genre = (object)null,
DateAdded = (object)null,
Image = (object)null,
TotalDownloads = 0,
TotalPlays = 0,
TotalComments = 0,
TotalLikes = 0,
TotalFavourites = 0,
WeeksDownloads = 0,
WeeksPlays = 0,
WeeksComments = 0,
WeeksLikes = 1,
WeeksFavourites = 0
});

AddMap<Favourite>(favs => from fav in favs
where fav.DateCreated >=
DateTimeOffset.Now.AddDays(-7)
select new
{
Id = fav.AudioId,
ArtistName = (string)null,
Name = (string)null,
Identifier = (string)null,
Description = (string)null,
Tags = (object)null,
Genre = (object)null,
DateAdded = (object)null,
Image = (object)null,
TotalDownloads = 0,
TotalPlays = 0,
TotalComments = 0,
TotalLikes = 0,
TotalFavourites = 0,
WeeksDownloads = 0,
WeeksPlays = 0,
WeeksComments = 0,
WeeksLikes = 0,
WeeksFavourites = 1
});

Reduce = results => from result in results
group result by result.Id
into g
select new
{
Id = g.Key,
ArtistName = g.Select(x =>
x.ArtistName).Where(x => x != null).FirstOrDefault(),
Name = g.Select(x =>
x.Name).Where(x => x != null).FirstOrDefault(),
Identifier = g.Select(x =>
x.Identifier).Where(x => x != null).FirstOrDefault(),
Description = g.Select(x =>
x.Description).Where(x => x != null).FirstOrDefault(),
Tags = g.Select(x =>
x.Tags).Where(x => x != null).FirstOrDefault(),
Genre = g.Select(x =>
x.Genre).Where(x => x != null).FirstOrDefault(),
DateAdded = g.Select(x =>
x.DateAdded).Where(x => x != null).FirstOrDefault(),
Image = g.Select(x =>
x.Image).Where(x => x != null).FirstOrDefault(),
TotalDownloads = g.Sum(x =>
x.TotalDownloads),
TotalPlays = g.Sum(x =>
x.TotalPlays),
TotalComments = g.Sum(x =>
x.TotalComments),
TotalLikes = g.Sum(x =>
x.TotalLikes),
TotalFavourites = g.Sum(x =>
x.TotalFavourites),
WeeksComments = g.Sum(x =>
x.WeeksComments),
WeeksDownloads = g.Sum(x =>
x.WeeksDownloads),
WeeksPlays = g.Sum(x =>
x.WeeksPlays),
WeeksLikes = g.Sum(x =>
x.WeeksLikes),
WeeksFavourites = g.Sum(x =>
x.WeeksFavourites)
};

Index(x => x.Genre.Code, FieldIndexing.Analyzed);
Store(x => x.Genre.Code, FieldStorage.Yes);
}
}

If it doesn't format properly you can see it here on SO:
http://stackoverflow.com/questions/9035452/multimap-reduce-index-field-issue/9038753?iemail=1#9038753

The issue I have at the moment is that in the reduce part of the index
I am returning the Tags & Genre as hydrated objects and I think this
is confusing the Index when I want to query by the Genre.Code.

Sorry about the long post, just wanted to ensure I give you all the
details...if you need any more details let me know.

Paul

Paul

unread,
Feb 2, 2012, 10:04:13 AM2/2/12
to ravendb
Hi,

Can anybody help with this query, am I going about this the wrong way?

I thought about using denormalized counters that sit within the audio
document, but someone advised against it on stack overflow.

Thank You,
Paul

Oren Eini (Ayende Rahien)

unread,
Feb 2, 2012, 2:24:56 PM2/2/12
to rav...@googlegroups.com
You can't index into a _nested_ property like that, we only index root properties.

Paul Hinett

unread,
Feb 2, 2012, 2:32:47 PM2/2/12
to rav...@googlegroups.com

Yes I understand that now which is no longer an issue, however is the design of this index ok, would it scale well?

 

There will be thousands of new AudioCounter documents added daily.

 

Also, for the Weekly counters, in my index I am limiting the results by date for the last 7 days…is this good design?

 

I am just looking for approval on the way I am implementing this, or to see if there is a better alternative.

 

Thank You,

Paul

Oren Eini (Ayende Rahien)

unread,
Feb 2, 2012, 2:33:58 PM2/2/12
to rav...@googlegroups.com
Can you post that in a format that is more readable?

Paul Hinett

unread,
Feb 2, 2012, 2:58:45 PM2/2/12
to rav...@googlegroups.com

The same index code was posted on StackOverflow in a related question…

 

http://stackoverflow.com/questions/9035452/multimap-reduce-index-field-issue/9038753#9038753

Oren Eini (Ayende Rahien)

unread,
Feb 2, 2012, 3:07:10 PM2/2/12
to rav...@googlegroups.com
This won't work:

                                              where comment.CreatedAt >= DateTimeOffset.Now.AddDays(-7)



You can't assume that the Now would be stable.

What you want to do is to actually include the weekly stats as something like:

comment.CreatedAt.Year + "-" + comment.CreatedAt.DayOfYear / 7

Which gives you the week number, and gives you a way to aggregate on that.

Paul

unread,
Mar 1, 2012, 10:36:25 AM3/1/12
to ravendb
Sorry to bring this one back up, I've only just had chance to get back
to this.

I'm not quite sure what I need to do here to get away from using
DateTime.Now in my index.

You say I should use something like:
comment.CreatedAt.Year + "-" + comment.CreatedAt.DayOfYear / 7

Where does this need to go, inside my MultiMap, or in my document? How
do pass to the index the current week to filter / aggregate on?

Thank You.

Oren Eini (Ayende Rahien)

unread,
Mar 1, 2012, 11:07:05 AM3/1/12
to rav...@googlegroups.com
Inside your multi map, this gives you an output of 2012-15 (where 15 is the week number)
And you can do queries on that.

Paul Hinett

unread,
Mar 1, 2012, 11:13:28 AM3/1/12
to rav...@googlegroups.com

Ok, I understand that part.

 

But my query returns stats from several documents, both weekly and totals…if I query by that specific week how would it include the stats from each document and include the overall totals?

 

I need:

TotalComments

WeeksComments

TotalDownloads

WeeksDownloads

TotalPlays

WeeksPlays

 

And a few more…

 

Sorry if these are basic questions, it’s just something I haven’t wrapped my head around yet.

 

From: rav...@googlegroups.com [mailto:rav...@googlegroups.com] On Behalf Of Oren Eini (Ayende Rahien)
Sent: 01 March 2012 16:07
To: rav...@googlegroups.com
Subject: Re: [RavenDB] Re: Complex MulitMap / Reduce - From Stackoverflow

 

Inside your multi map, this gives you an output of 2012-15 (where 15 is the week number)

Oren Eini (Ayende Rahien)

unread,
Mar 1, 2012, 11:14:11 AM3/1/12
to rav...@googlegroups.com
You have two different indexes, one for per week, one for total.

Paul Hinett

unread,
Mar 1, 2012, 7:29:34 PM3/1/12
to rav...@googlegroups.com

Struggling to get this to work how I want…

 

I have managed to get it working with 3 indexes.

 

1)      Audio_Index

2)      AudioStatsTotals_Index

3)      AudioStatsWeekly_Index

 

I query my Audio_Index and filter on several properties, then query the 2 stats indexes and merge them together into my ViewModel, this works fine.

 

But I need to be able to OrderBy on the statistics, either on the weekly or total statistics but I can’t do this until I have merged them which is too late.

 

I have also tried to get a single index to work which just includes my weekly statistics, ignoring the total stats. Here is my index code:

http://pastie.org/3500540

 

This brings back incorrect results, they either have a NULL WeekNumber but with valid Audio properties, or a valid WeekNumber but null Audio properties.

 

Is this going to be possible, I really hope I can use some indexing magic rather than denormalize my statistic counters.

 

Sorry to be such a pain, I am 95% done re-writing my website to use RavenDb and I’m VERY happy so far, just apart from a couple of indexing issues, probably due to my lack of understanding.

 

Paul

Oren Eini (Ayende Rahien)

unread,
Mar 2, 2012, 3:32:53 AM3/2/12
to rav...@googlegroups.com
Paul,
On a first glance, you indexing code looks good.
Can you try creating a failing test that demonstrate what you are trying to do?
Message has been deleted
Message has been deleted

Paul

unread,
Mar 2, 2012, 9:02:17 AM3/2/12
to ravendb
Hi Oren,

I have zipped up a small test project containing a single self-
contained test with my index and POCO classes.

http://www.house-mixes.com/raven/HM.Tests.Individual.zip

Sorry if this has duplicated, Google Groups just doesn't seem to be
posting my reply for some reason.

Thank You,
Paul

On Mar 2, 8:32 am, "Oren Eini (Ayende Rahien)" <aye...@ayende.com>
wrote:
> Paul,
> On a first glance, you indexing code looks good.
> Can you try creating a failing test that demonstrate what you are trying to
> do?
>
> On Fri, Mar 2, 2012 at 2:29 AM, Paul Hinett <p...@ukcreativedesigns.com>wrote:
>
>
>
>
>
>
>
> > Struggling to get this to work how I want…****
>
> > ** **
>
> > I have managed to get it working with 3 indexes.****
>
> > ** **
>
> > **1)      **Audio_Index****
>
> > **2)      **AudioStatsTotals_Index****
>
> > **3)      **AudioStatsWeekly_Index****
>
> > ** **
>
> > I query my Audio_Index and filter on several properties, then query the 2
> > stats indexes and merge them together into my ViewModel, this works fine.*
> > ***
>
> > ** **
>
> > But I need to be able to OrderBy on the statistics, either on the weekly
> > or total statistics but I can’t do this until I have merged them which is
> > too late.****
>
> > ** **
>
> > I have also tried to get a single index to work which just includes my
> > weekly statistics, ignoring the total stats. Here is my index code:****
>
> >http://pastie.org/3500540****
>
> > ** **
>
> > This brings back incorrect results, they either have a NULL WeekNumber but
> > with valid Audio properties, or a valid WeekNumber but null Audio
> > properties.****
>
> > ** **
>
> > Is this going to be possible, I really hope I can use some indexing magic
> > rather than denormalize my statistic counters.****
>
> > ** **
>
> > Sorry to be such a pain, I am 95% done re-writing my website to use
> > RavenDb and I’m VERY happy so far, just apart from a couple of indexing
> > issues, probably due to my lack of understanding.****
>
> > ** **
>
> > Paul****
>
> > ** **
>
> > *From:* rav...@googlegroups.com [mailto:rav...@googlegroups.com] *On
> > Behalf Of *Oren Eini (Ayende Rahien)
> > *Sent:* 01 March 2012 16:14
>
> > *To:* rav...@googlegroups.com
> > *Subject:* Re: [RavenDB] Re: Complex MulitMap / Reduce - From
> > Stackoverflow****
>
> > ** **
>
> > You have two different indexes, one for per week, one for total.****
>
> > On Thu, Mar 1, 2012 at 6:13 PM, Paul Hinett <p...@ukcreativedesigns.com>
> > wrote:****
>
> > Ok, I understand that part.****
>
> >  ****
>
> > But my query returns stats from several documents, both weekly and
> > totals…if I query by that specific week how would it include the stats from
> > each document and include the overall totals?****
>
> >  ****
>
> > I need:****
>
> > TotalComments****
>
> > WeeksComments****
>
> > TotalDownloads****
>
> > WeeksDownloads****
>
> > TotalPlays****
>
> > WeeksPlays****
>
> >  ****
>
> > And a few more…****
>
> >  ****
>
> > Sorry if these are basic questions, it’s just something I haven’t wrapped
> > my head around yet.****
>
> >  ****
>
> > *From:* rav...@googlegroups.com [mailto:rav...@googlegroups.com] *On
> > Behalf Of *Oren Eini (Ayende Rahien)
> > *Sent:* 01 March 2012 16:07****
>
> > *To:* rav...@googlegroups.com
> > *Subject:* Re: [RavenDB] Re: Complex MulitMap / Reduce - From
> > Stackoverflow****
>
> >  ****
>
> > Inside your multi map, this gives you an output of 2012-15 (where 15 is
> > the week number)****
>
> > And you can do queries on that.****
>
> > On Thu, Mar 1, 2012 at 5:36 PM, Paul <p...@ukcreativedesigns.com> wrote:**
> > **
>
> > Sorry to bring this one back up, I've only just had chance to get back
> > to this.
>
> > I'm not quite sure what I need to do here to get away from using
> > DateTime.Now in my index.
>
> > You say I should use something like:****
>
> > comment.CreatedAt.Year + "-" + comment.CreatedAt.DayOfYear / 7****
>
> > Where does this need to go, inside my MultiMap, or in my document? How
> > do pass to the index the current week to filter / aggregate on?
>
> > Thank You.****
>
> >  ****
>
> > ** **

Oren Eini (Ayende Rahien)

unread,
Mar 4, 2012, 9:45:54 AM3/4/12
to rav...@googlegroups.com
Paul,
Okay, now I got what you are doing.
Note that you have this:
WeekNumber = (string)null

And then you try to group by this.

But the major problem is that what you are trying to do isn't a good way to go about this.
You are trying to force all the data into the index, and this really isn't how you do this sort of thing with RavenDB.

I attached a modified version of the test that works and gives you all of the results in one request.
I also think it is significantly simpler.
StatsTest.cs

Paul Hinett

unread,
Mar 4, 2012, 1:15:52 PM3/4/12
to rav...@googlegroups.com

Hi,

 

Thank you for taking the time to have a look at this, however I don’t think this will work for me as I also need to filter on properties of my Audio document, such as the AudioType or several other properties.

 

With the index you have provided, I will only have access to the properties of the statistics and the audio Id until I call ToList(), this isn’t going to work when I need to introduce paging & filtering on other properties.

 

Any other ideas?

Oren Eini (Ayende Rahien)

unread,
Mar 4, 2012, 4:05:54 PM3/4/12
to rav...@googlegroups.com
Do you actually need to filter on the aggregation properties? Would you need to do something like "WeeklyPlay > 100" ?
Because it sounds like this is just another aspect of trying to do a join query when you can query for that information separately.

Paul Hinett

unread,
Mar 4, 2012, 4:48:53 PM3/4/12
to rav...@googlegroups.com

I need to filter on the properties of my Audio document, however I need to order by on the aggregation properties which is the reason I was trying to get this all into a single index.

 

I have found a solution, not perfect but I think it will work.

 

In my AudioCounter document I have included a property called IsRecent, this is set to True when created.

 

I will then have a console application run once per hour to find all the AudioCounter documents older than 7 days where IsRecent = true, and update them to False, probably using a patch command.

 

This enables me to use my original index, but instead of comparing the Dates and using DateTime.Now.AddDays(-7) I can simply check for IsRecent = true.

 

As long as nothing stands out obvious why this is a bad idea, I’m happy to compromise with it.

 

Thank You,

Paul

Oren Eini (Ayende Rahien)

unread,
Mar 5, 2012, 3:42:56 AM3/5/12
to rav...@googlegroups.com
Paul,
Why would you want to go to all that trouble?

You would need two queries. First, find all the relevant audios. Then find all of their current stats.
That would be a very easy thing to do, and doesn't require a separate process to run.

Also, is there a reason why you need IsRecent vs. the data it was created?

Paul Hinett

unread,
Mar 5, 2012, 5:27:27 AM3/5/12
to rav...@googlegroups.com

Is what I have is hundreds and thousands of media files on my site, users can then play them, download them, like them, add them to favourites etc.

 

Each time they do this it’s logged down as a statistic, I then need the user to be able to view media of type ‘Mix’ and tagged  with ‘Techno’, but also give them the option to order by the most downloaded in the past 7 days, the most played overall (since it was first uploaded) etc, the list of media are then displayed in pages to the user along with many properties from the Audio document such as name etc, the statistics for the past 7 days, and also that statistics since it was first uploaded.

 

If I am using 2 queries to get my data, how can I perform paging correctly. Forgive me if I am missing something but from the code you provided I don’t think it was possible, surely I need to perform my paging after I have done my filtering and my OrderBy, I can’t get the relevant audios as a list, then query their stats because I can’t OrderBy my stats correctly then.

 

The reason I can’t use the date in my index is because apparently (I’m not entirely sure why) I can’t use DateTime.Now inside my static index to compare against to filter my statistics to get a subset for only the last 7 days.

 

I may be making this sound more complex than it actually is, but from doing lots of Googling and plenty of tests and alterations this is the only way I can get it working.

Oren Eini (Ayende Rahien)

unread,
Mar 5, 2012, 6:31:28 AM3/5/12
to rav...@googlegroups.com
Paul,
You can't use DateTime.Now in the _index_, you can use it in the _query_.

var recentAudios = session.Query<Audio>().Where(x=>x.CreatedAt >= DateTime.Now.AddDays(-7)).ToList();

Let us try to narrow down the problem. It is very easy to pull data from RavenDB, the only complexity is whatever you are going to need to be able to do sorting on the weekly stats as well. Is this something that you need?
And how accurate would that sorting need to be?

Paul Hinett

unread,
Mar 5, 2012, 6:43:14 AM3/5/12
to rav...@googlegroups.com

I don’t want to filter by date, that’s pretty simple. I need to order by the stats that each Audio document has had in the past 7 days AND overall.

 

It doesn’t need to be PERFECTLY accurate, I have a page which lists the most popular audio, basically sorts Audio by how many downloads it has had in the last 7 days.

 

What I need in a simplified way (I have more stats than just downloads such as plays, comments, likes etc):

 

Audios

-          Name

-          AudioType

-          Description

-          Etc…

 

AudioDownloads

-          AudioId

-          DownloadDate

 

My index needs to include:

 

AudioIndex

-          AudioId

-          Name

-          WeeksDownloads  (a Sum of all the downloads from the AudioDownloads documents from the past 7 days only)

-          TotalDownloads (a Sum of all the downloads from the AudioDownloads document)

 

Then I can perform filtering by Name, AudioType and also order by either WeeksDownloads or TotalDownloads very easily.

 

Sorry if I’m not expressing what I need very well.

Oren Eini (Ayende Rahien)

unread,
Mar 5, 2012, 7:02:10 AM3/5/12
to rav...@googlegroups.com
Paul,
Okay, that make sense. And the answer is that you are going to want to do something like this:

Create an index that sum things by day. (not a week).
In the Audio document, have a property named WeeklyPlays, etc
Once an hour, query that summing index and update the  WeeklyPlays, etc based on the last 7 days.

That would give you everything, but won't create complex scenarios for the indexing.

Paul Hinett

unread,
Mar 5, 2012, 7:37:47 AM3/5/12
to rav...@googlegroups.com

Sounds good, will give it a go.

 

When you say update hourly, I take it you mean with a console application in the background.

 

Will updating every document in my index hourly affect my index performance in any way?

 

Thank you for the help, really appreciated!

Oren Eini (Ayende Rahien)

unread,
Mar 5, 2012, 7:40:28 AM3/5/12
to rav...@googlegroups.com
Paul,
Yes, I mean a console app as a task, yes.
You won't update all your docs, only the ones that have any views, and no, it won't affect the perf of the system.

Paul Hinett

unread,
Mar 5, 2012, 5:25:44 PM3/5/12
to rav...@googlegroups.com

Hi Oren,

 

I have implemented this for my weekly statistics and it’s working great thank you, should I follow the same principles for the Total statistics though?

 

Total statistics means it needs to include all AudioCounter documents for that AudioId rather than just from the previous 7 days, it means my Console app will need to query an index containing  the totals every hour and will virtually include every Audio document (currently around 200,000), this is how I have set it up at the moment, I’m just hoping I don’t get any nasty performance issues later when in production?

Oren Eini (Ayende Rahien)

unread,
Mar 6, 2012, 3:43:28 AM3/6/12
to rav...@googlegroups.com
Paul,
No, total statistics can just aggregate on the audio id, which means that it is very easy to merge the values from the audio.
You won't need the same system in that manner.
Reply all
Reply to author
Forward
0 new messages