V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Morriaty
V2EX  ›  程序员

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

  •  
  •   Morriaty · 2020-09-15 11:27:54 +08:00 · 2658 次点击
    这是一个创建于 1511 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    请问有完整的描述,或者相关链接吗?我是指整体的技术方案,包括布隆过滤器是在代码层实现,还是通过一些 redis 等中间件实现?过滤器怎么同步数据变更?等等
    Morriaty
        5
    Morriaty  
    OP
       2020-09-15 14:17:36 +08:00
    @Nillouise 当然是后者了呀
    vZexc0m
        6
    vZexc0m  
       2020-09-15 14:57:44 +08:00
    Redis 集合(Set)
    Nillouise
        7
    Nillouise  
       2020-09-15 15:17:54 +08:00
    我理解了,你是每次查询的时时候要把 1000 个 id 拿去给 elasticsearch 查。但这里做一个分布式查询不是很简单吗? id 为 1 就只查第一台机器,id 为 2 就查第二台机器。布隆过滤器应该很难处理用户屏蔽这种功能。
    Nillouise
        8
    Nillouise  
       2020-09-15 15:19:56 +08:00
    @Nillouise 因为用户屏蔽之后可能会解除屏蔽
    mymike
        9
    mymike  
       2020-09-15 15:21:26 +08:00
    物品状态和用户屏蔽可以做缓存(两种缓存的策略要单独考虑),如果需要做到强一致必然会影响整体性能,而大量的过滤肯定是不可取的,推荐列表是否可分页,降低过滤范围
    ychost
        10
    ychost  
       2020-09-15 15:21:53 +08:00
    布隆过滤器
    Morriaty
        11
    Morriaty  
    OP
       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
        12
    Morriaty  
    OP
       2020-09-15 16:48:57 +08:00
    @mymike 终于有人说到点上了,朋友你应该也是做搜索推荐的吧。你说的这种后过滤有个比较麻烦的问题是,分页后请求,被过滤掉的部分,就得补全,补全的部分还要从下个分页里去掉,导致分页逻辑极其复杂
    mymike
        13
    mymike  
       2020-09-15 17:06:07 +08:00
    可以考虑客户端来补全,后端仅负责过滤,不保证每个分页的内容数量
    Nillouise
        14
    Nillouise  
       2020-09-15 17:14:18 +08:00
    这种过滤在应用服务器上做不就行了吗,一次从数据库把 1000 个 id 相关的信息全部提取出来,用 habse 之类应该没啥问题把。这种需求分布式系统要做到线性增加吞吐量有何难点?我学过一点分布式,但没实践过,希望有大佬说明一下。
    wysnylc
        15
    wysnylc  
       2020-09-15 17:14:38 +08:00
    bloom filter 用之前得用普通的 map 搞个白名单,要不然误判是无法处理的
    whp1473
        16
    whp1473  
       2020-09-16 17:11:37 +08:00
    实时性高效率查询,只有用内存才能办到,对 item_id 的状态进行保存,比如 Redis 使用 Hash 结构,key 保存用户 ID,Map 里保存推荐商品 ID 和状态,每个用户持有不同的推荐商品状态。Redis 和数据库同步可以考虑同步代码,也可以用消息中间件解耦,但要考虑消息的消费速率。
    whp1473
        17
    whp1473  
       2020-09-16 17:18:37 +08:00
    对于 es,数据过多深度分页时,可以考虑通过游标来进行查询,比直接使用分页效率高。
    Morriaty
        18
    Morriaty  
    OP
       2020-09-17 10:02:14 +08:00
    @whp1473 scroll 的方式满足不了线上耗时要求
    licn
        19
    licn  
       2020-09-17 10:41:44 +08:00
    这个还是和客户端一起处理,被用户屏蔽的可以由客户端在做过滤
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1166 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 18:27 · PVG 02:27 · LAX 10:27 · JFK 13:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.