You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Elasticsearch与Searchkick实现用户近7天浏览事件的索引方案咨询

解决Elasticsearch + Searchkick下的近7天事件浏览筛选问题

针对你的需求,这里提供两种可行的索引设计方案,分别适配不同的业务场景:

方案1:在Event索引中存储带时间戳的嵌套点击记录

将用户点击记录从单纯的ID数组改为嵌套对象数组,每个对象包含user_id和clicked_at字段,同时保留用户维度与时间维度的信息。

配置Event模型的Searchkick索引

class Event < ApplicationRecord
  searchkick mappings: {
    properties: {
      user_clicks: {
        type: "nested",
        properties: {
          user_id: { type: "integer" },
          clicked_at: { type: "date" }
        }
      }
      # 这里添加事件的其他基础字段,比如title、start_time等
    }
  }

  def search_data
    {
      # 映射事件基础字段
      title: title,
      start_time: start_time,
      # 映射嵌套点击记录
      user_clicks: user_clicks
    }
  end
end

用户点击时更新记录

用户点击事件时,维护user_clicks数组:若该用户已有点击记录则更新时间,否则新增记录,之后触发索引重建:

def track_user_click(user)
  existing_click = user_clicks.find { |c| c[:user_id] == user.id }
  if existing_click
    existing_click[:clicked_at] = Time.current
  else
    user_clicks << { user_id: user.id, clicked_at: Time.current }
  end
  save
  reindex
end

实现“近7天浏览”筛选

通过嵌套查询过滤当前用户近7天内点击过的事件:

seven_days_ago = 7.days.ago

Event.search(
  "*",
  where: {
    user_clicks: {
      nested: {
        path: "user_clicks",
        query: {
          bool: {
            must: [
              { term: { "user_clicks.user_id": current_user.id } },
              { range: { "user_clicks.clicked_at": { gte: seven_days_ago } } }
            ]
          }
        }
      }
    }
  }
)

方案2:单独创建用户点击记录索引(推荐高点击量场景)

如果事件的点击量较大,嵌套数组会导致Event文档体积持续膨胀,影响索引性能。此时建议单独创建UserEventClick模型,专门存储用户点击事件的时间与关联关系。

创建UserEventClick模型并配置Searchkick

class UserEventClick < ApplicationRecord
  belongs_to :user
  belongs_to :event

  searchkick
end

用户点击时创建记录

用户点击事件时,直接新增一条点击记录:

def track_user_click(user)
  UserEventClick.create!(user: user, event: self, created_at: Time.current)
end

查询用户近7天点击的事件

先通过点击记录索引获取事件ID列表,再过滤事件索引:

seven_days_ago = 7.days.ago

# 获取近7天点击的事件ID
clicked_event_ids = UserEventClick.search(
  "*",
  where: { user_id: current_user.id, created_at: { gte: seven_days_ago } },
  fields: [:event_id],
  limit: nil
).map(&:event_id)

# 查询对应的事件列表
Event.search(
  "*",
  where: { id: clicked_event_ids }
)

方案对比

  • 嵌套对象方案:适合点击量较小的场景,仅需一次查询即可获取结果,逻辑简单,但Event文档会随点击量增长。
  • 单独索引方案:适合高点击量场景,Event索引体积稳定,维护更灵活,但需要额外的模型和两次查询(或用Elasticsearch的terms lookup优化为单次查询)。

内容的提问来源于stack exchange,提问作者Remember_me

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 15:01:13