Home > OS >  Implementing recently viewed by a user
Implementing recently viewed by a user

Time:12-29

I am using elasticsearch and gem searchkick in my application. I have an Event model, where users are able to click on the event etc.

In the event list I have a requirement for filter "viewed in the last 7 days". I am wondering what's the best way to index data so it serves the requirement appropriately.

At first I thought about storing user ids on the Event model ES index like so :

Event: {
 _id: 1,
 user_ids: [1,2,3,4...]
}

But this would give me all the event views, not only in the last 7 days. How would I create indexed data to accommodate this case?

Update per comments to provide more context:

This is an example of some events (what is being stored) :

[
  {
    _id: 1,
    name: 'Company get together',
    start_time: '10:00',
    start_date: '2022-10-01',
    duration: 3600
    ...
  },
  {
    _id: 2,
    name: 'Company break',
    start_time: '00:05',
    start_date: '2022-01-01',
    duration: 172800
    ...
  },
  {
    _id: 3,
    name: 'Sales webinar',
    start_time: '09:00',
    start_date: '2022-15-01',
    duration: 7200
    ...
  },
  ...
]

This would be an example of what is in the events right now. If some user clicks on this event, we want a record this (somehow) on the event model, so that we could return the list of events that user has clicked on in the last 7 days.

If we used a structure like this:

{
    _id: 3,
    name: 'Sales webinar',
    start_time: '09:00',
    start_date: '2022-15-01',
    duration: 7200,
    user_click_ids: [1, 2, 3]
    ...
  }

And we append to user_click_ids every time the user clicks on a specific event, then I can use user_click_ids to return the list of the users who clicked on that event (and filter on it providing current user id).

But then I need another dimension to this, not only which user clicked, but also was the click in the last 7 days or not.

How do I create an index for this case or how would I solve this?

CodePudding user response:

Maybe a solution that uses less searchkick, but you could use another model to handle this? Off the top of my head (haven't run this):

class CreateEventClicks < ActiveRecord::Migration
  def change
    create_table :event_clicks do |t|
      t.belongs_to :event, null: false, foreign_key: true
      t.belongs_to :user, null: false, foreign_key: true
      t.timestamps
    end

    add_index :event_clicks, :event, :user
  end
end
class EventClicks < ApplicationRecord
  belongs_to :user
  belongs_to :event
end
def find_clicked_events(user, event, time)
  EventClicks.where(user_id: user.id, event_id: event.id, created_at: time..Time.now)
end

CodePudding user response:

I'm not sure about searchkick since I'm .net guy but I'd store entire information about the click instead of just the id. I.e.

Event: {
 _id: 1,
 user_clicks: [{
   user_id: 1,
   timestamp: 2022-02-24 4:00:00
 }, ...]
}

However, depending on the expected usage pattern (i.e. a lot of users clicking a lot of events) documents might become large. If that is the case you might consider doing additional filtering on your backend instead of elasticsearch.

In such a case you'd go with something like user_activities index

user_id: 1,
event_clicks: [{
  event_id: 1
  timestapmp: 2022-02-24 04:00:00
}, ...]

The obvious downside of such approach is additional code on a backend with might be hard to support and complicate things.

The thing with NoSQL databases (and elasticsearch as well) is that there is no single one-size-fits-all solution and you have to understand your query patterns well. So it's up to you to decide what hinders you more: growing document size with approach 1 or adding some custom logic on your backend with approach 2.

  • Related