Rails应用Elasticsearch用户数据建模方案与数据库选型咨询
移动应用用户画像+行为检索场景技术方案解答
一、Elasticsearch适配性及最优数据模型
Elasticsearch完全适配当前业务需求,之前评估的两种方案存在缺陷,核心是数据模型设计没有匹配ES的特性,并非ES本身能力不足。
最优落地模型不需要硬做跨索引关联,也不需要高频更新文档,拆分三类存储逻辑即可:
- 慢更新用户画像主索引:不要按天创建画像索引,直接以
app_id做路由键、profile_id作为文档_id构建单份全量画像索引,存储所有用户的静态属性、慢更新属性(手机号、邮箱、姓名、注册信息、预聚合行为标签等)。这类数据只有用户修改资料、标签更新时才会触发写入/更新,单文档体积极小,更新压力可以忽略。
文档结构参考:// 画像主索引,路由键=app_id { "_id": "2faae1d6-5875-4b36-b119-74a14589c841", "app_id": "abbccddeeff", "whatsapp_number": "whatsapp:+61478421940", "phone": "+61478421940", "email": "user@mail.com", "first_name": "john", "last_name": "doe", "behavior_tags": ["paid_user", "last_7d_login", "viewed_course"], "last_active_time": "2022-06-09T12:00:00Z" } - append-only用户行为明细索引:保留按天+
app_id切分的行为索引,所有上报的行为数据直接写入对应索引,全程只做追加写入、不做更新操作,完全吃ES的高写入吞吐优势。按日均500万条行为的量级,3节点基础配置的ES集群就能轻松承载,不存在写入压力问题。 - 业务层封装两步查询逻辑:不要用ES的join、nested这类重开销特性做关联查询,管理员提交多条件筛选请求时,业务层自动拆分查询条件:涉及行为的筛选条件先查行为明细索引,通过
scroll或者search_after拉取符合要求的profile_id集合,再把这批ID作为过滤条件,叠加画像类筛选条件请求画像主索引,直接返回最终目标用户列表。
做两个优化就能覆盖绝大多数场景的性能要求:- 高频用到的行为规则(比如近7天登录、近30天付费)做定时预聚合,把结果更新到画像索引的
behavior_tags字段,90%的日常筛选请求直接查画像索引就能返回结果,不需要访问行为明细 - 查询逻辑完全封装在业务层,管理员保存筛选规则时只存结构化的条件配置,不需要感知底层的两次查询过程,规则复用完全可以实现。
- 高频用到的行为规则(比如近7天登录、近30天付费)做定时预聚合,把结果更新到画像索引的
注意不要踩两个ES常见的模型坑:不要把全量行为作为nested数组存在画像文档里(就是方案二的模式,每次追加行为要重写整个文档,更新压力极大);不要用parent-child关联类型,这类join查询内存开销高、延迟大,是ES为极端特殊场景预留的功能,常规业务不推荐使用。
二、其他技术选型对比
不管是切换MongoDB还是引入Hadoop生态组件,都不会比优化后的ES方案更适配,反而会增加不必要的复杂度:
- MongoDB:MongoDB适合做业务数据的持久化存储,但多维度组合检索、复杂条件过滤、聚合分析的性能远低于ES,面对管理员灵活组合的筛选条件,查询延迟很容易升到秒级以上。同时MongoDB本身也不支持高效的跨集合关联,最终还是要实现和上面一致的两步查询逻辑,换库不仅没有收益,还会丢失ES的检索性能优势。
- Hadoop生态组件:Hive、Spark等组件面向的是T+1级别的离线批量分析场景,延迟普遍在分钟到小时级,完全满足不了管理员筛选后实时触达用户的业务要求。只有当需要做长周期的用户行为离线报表、大规模数据统计时,才需要考虑引入这类组件做离线数仓,实时筛选场景完全用不上。
三、落地优化建议
- 行为索引配置索引生命周期规则,超过存储周期的冷数据自动迁移到冷节点或者归档存储,降低热节点资源占用
- 画像索引更新时用局部更新接口,不需要重写整个文档,更新性能可以提升数倍
- 提前根据数据量级规划行为索引的分片数,单分片大小控制在30-50G的最优区间即可,不需要盲目扩容集群
内容的提问来源于stack exchange,提问作者Hadii Varposhti
相关产品推荐
相关产品推荐

