在线场景下,对于大量 ID 进行筛选过滤的最佳技术方案是什么?

2020-09-15 11:27:54 +08:00
 Morriaty

具体场景是,每个用户有个推荐列表,推荐列表是千级别的物品 ID,但物品是高频度变更的,下架、失效、用户屏蔽等等,所以希望是近实时在线的去判断这几千个 ID 的状态。

目前有尝试使用 elasticsearch 进行实时的请求,但实际发现在峰值请求下,每次 request 都是千级别的 ID 过滤,es 还是扛不住,查了下 Google,es 官方也表示不适合这种超多的过滤场景。

因此想请教更合适的技术方案是什么?

2686 次点击
所在节点    程序员
19 条回复
li24361
2020-09-15 11:30:56 +08:00
bloom filter
chihiro2014
2020-09-15 11:38:06 +08:00
布隆过滤器,宁错杀不放过,可以用 Guava 里面的。
前段时间一朋友的电网项目里就用了这个,因为机器原因,处理几十万条还是扛得住的
Nillouise
2020-09-15 11:39:59 +08:00
虽然不了解这个场景,但没看明白难点是什么?几千个商品放在内存里处理不就行了吗?还是每个用户的推荐商品都不一样,要实时处理每个用户*1000 个商品的数量?
Morriaty
2020-09-15 14:17:17 +08:00
@li24361
@chihiro2014

请问有完整的描述,或者相关链接吗?我是指整体的技术方案,包括布隆过滤器是在代码层实现,还是通过一些 redis 等中间件实现?过滤器怎么同步数据变更?等等
Morriaty
2020-09-15 14:17:36 +08:00
@Nillouise 当然是后者了呀
vZexc0m
2020-09-15 14:57:44 +08:00
Redis 集合(Set)
Nillouise
2020-09-15 15:17:54 +08:00
我理解了,你是每次查询的时时候要把 1000 个 id 拿去给 elasticsearch 查。但这里做一个分布式查询不是很简单吗? id 为 1 就只查第一台机器,id 为 2 就查第二台机器。布隆过滤器应该很难处理用户屏蔽这种功能。
Nillouise
2020-09-15 15:19:56 +08:00
@Nillouise 因为用户屏蔽之后可能会解除屏蔽
mymike
2020-09-15 15:21:26 +08:00
物品状态和用户屏蔽可以做缓存(两种缓存的策略要单独考虑),如果需要做到强一致必然会影响整体性能,而大量的过滤肯定是不可取的,推荐列表是否可分页,降低过滤范围
ychost
2020-09-15 15:21:53 +08:00
布隆过滤器
Morriaty
2020-09-15 16:31:01 +08:00
@Nillouise 实际是有个千万级的 item 索引,每次查询 1000 个左右的 item_id 的 status,对应的 es query 是:
{
"query": {
"bool": {
"filter": [
{
"term": {
"status": {
"value": "1"
}
}
},
{
"terms": {
"item_id": ["id1", "id2", ..., "id1000"]
}
}
]
}
}
}

流量大峰值的时段,其中 terms 那个查询 es 扛不住
Morriaty
2020-09-15 16:48:57 +08:00
@mymike 终于有人说到点上了,朋友你应该也是做搜索推荐的吧。你说的这种后过滤有个比较麻烦的问题是,分页后请求,被过滤掉的部分,就得补全,补全的部分还要从下个分页里去掉,导致分页逻辑极其复杂
mymike
2020-09-15 17:06:07 +08:00
可以考虑客户端来补全,后端仅负责过滤,不保证每个分页的内容数量
Nillouise
2020-09-15 17:14:18 +08:00
这种过滤在应用服务器上做不就行了吗,一次从数据库把 1000 个 id 相关的信息全部提取出来,用 habse 之类应该没啥问题把。这种需求分布式系统要做到线性增加吞吐量有何难点?我学过一点分布式,但没实践过,希望有大佬说明一下。
wysnylc
2020-09-15 17:14:38 +08:00
bloom filter 用之前得用普通的 map 搞个白名单,要不然误判是无法处理的
whp1473
2020-09-16 17:11:37 +08:00
实时性高效率查询,只有用内存才能办到,对 item_id 的状态进行保存,比如 Redis 使用 Hash 结构,key 保存用户 ID,Map 里保存推荐商品 ID 和状态,每个用户持有不同的推荐商品状态。Redis 和数据库同步可以考虑同步代码,也可以用消息中间件解耦,但要考虑消息的消费速率。
whp1473
2020-09-16 17:18:37 +08:00
对于 es,数据过多深度分页时,可以考虑通过游标来进行查询,比直接使用分页效率高。
Morriaty
2020-09-17 10:02:14 +08:00
@whp1473 scroll 的方式满足不了线上耗时要求
licn
2020-09-17 10:41:44 +08:00
这个还是和客户端一起处理,被用户屏蔽的可以由客户端在做过滤

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/707113

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX