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

多标签搜索,后端一般是怎样实现的?不会是多表直接 join 吧?

  •  
  •   yodhcn ·
    yodhcn · 2023-03-27 10:25:56 +08:00 · 3260 次点击
    这是一个创建于 610 天前的主题,其中的信息可能已经有所发展或是发生改变。

    提到多对多关系,第一个反应是 3 张表 —— 即,两张数据表、一张关系表,例如:

    t_product
    | id (integer) | name (character verying) |
    
    t_tag
    | id (integer) | name (character verying) |
    
    r_product_tag
    | product_id (integer) | tag_id (integer) |
    

    但需要根据多个 tag 查询 product 时(/product?tags=苹果,橘子),只用数据库该怎样实现?

    • 直接将 3 张表 JOIN 在一起?感觉查询效率会很低。
    • 建立倒排索引?例如,将表 t_product 新增一冗余tags (character verying),并在该列上建立 PostgreSQLGIN 索引。这种方式顺便还可以通过分词单个标签的字符串拆分成多个关键字,更容易搜索。
    t_product
    | id (integer) | name (character verying) | tags (character verying) |
    

    如果只按标签的 id 查询(/product?tag_ids=22,12,45),表 t_product 新增一冗余列 tag_ids (integer[]),这种情况该在此列上建立 B+树索引 还是 倒排索引

    t_product
    | id (integer) | name (character verying) | tag_ids (integer[]) |
    

    不知道 PostgreSQLinteger[] 类型字段的索引机制是怎样的?

    18 条回复    2023-03-27 22:26:58 +08:00
    liprais
        1
    liprais  
       2023-03-27 10:38:21 +08:00
    谁告诉你多表 join 效率低的?
    liuzhen
        2
    liuzhen  
       2023-03-27 10:49:16 +08:00
    脱离数据量说效率是耍流氓;大表 join 效率是低的,可以考虑拆 sql 多次查询,小表 join 就完事了
    Ashore
        3
    Ashore  
       2023-03-27 10:49:47 +08:00
    @liprais csdn(狗头
    CNife
        4
    CNife  
       2023-03-27 10:54:06 +08:00
    建议自己实验一下,用 EXPLAIN ANALYZE 看看如何处理和代价如何
    LeegoYih
        5
    LeegoYih  
       2023-03-27 10:54:24 +08:00
    表设计合理可以 join ,走索引性能不会差,如果是微服务或者后续需要分库分表还是拆分成三次查询吧

    1. select id from t_tag where name in ("苹果","橘子")
    2. select product_id from r_product_tag where tag_id in (...)
    3. select * from t_product where id in (...)

    如果 t_tag 更新频率较低可以放缓存里
    iwishing
        6
    iwishing  
       2023-03-27 11:19:30 +08:00
    有个问题,为啥多标签是交集而不是并集?搜索我一般喜欢并集,筛选喜欢交集。
    zoharSoul
        7
    zoharSoul  
       2023-03-27 11:23:31 +08:00
    es 直接拍平了
    codespots
        8
    codespots  
       2023-03-27 11:42:07 +08:00
    @iwishing metoo
    yodhcn
        9
    yodhcn  
    OP
       2023-03-27 11:45:47 +08:00
    @liprais @Ashore #1

    我是在看了站内的这篇帖子才产生的疑问
    https://www.v2ex.com/t/767754

    最后还是在 Google 找到了答案,不论是按字符串还是 int id 搜索,都得建立倒排索引。只不过针对 int[] 有更方便的扩展( intarray )
    https://stackoverflow.com/questions/8242643/search-in-integer-array-in-postgres
    https://www.postgresql.org/docs/current/intarray.html
    TWorldIsNButThis
        10
    TWorldIsNButThis  
       2023-03-27 11:54:00 +08:00
    这就是 es 出现的原因
    xuelu520
        11
    xuelu520  
       2023-03-27 12:01:16 +08:00
    --直接将 3 张表 JOIN 在一起?感觉查询效率会很低。
    这个思维就是错的。
    正常情况 JOIN 查就是了,大表 JOIN 就需要 es 了。
    512357301
        12
    512357301  
       2023-03-27 12:11:17 +08:00 via Android
    效率低那是阿里巴巴提出来的吧,好像他们有个 MySQL 开发规范,不过如楼上所说,脱离数据量谈效率就是耍流氓,你一个配置表几千几万条数据,谈效率低,啧啧啧。
    join 效率低说的是百万千万量级的时候效率低,这也不是 join 的锅,这是 MySQL 的锅
    yodhcn
        13
    yodhcn  
    OP
       2023-03-27 12:18:45 +08:00 via Android
    @512357301 假设主表(商品表)有 100 万条记录,并且除了 tag 以外,还有 2 个多对多的关系,也需要加入到查询条件中。如果是这种情况,最好还是上倒排索引比较好吧?
    yodhcn
        14
    yodhcn  
    OP
       2023-03-27 12:20:10 +08:00 via Android
    @xuelu520 商品表有 100 万条记录,这算大表吗?
    aw2350
        15
    aw2350  
       2023-03-27 12:24:58 +08:00
    r_product_tag 不必 一对一吧,这个完全可以用一个数组列解决
    notejava
        16
    notejava  
       2023-03-27 13:04:00 +08:00
    直接 join ,然后从产品设计上,让查询时尽量多带命中索引的筛选条件,比如时间筛选。
    lasuar
        17
    lasuar  
       2023-03-27 13:04:30 +08:00
    @yodhcn 不算。千万级表加内存即可。
    xuanbg
        18
    xuanbg  
       2023-03-27 22:26:58 +08:00
    不要感觉,实际情况是上百万的数据多表关联也能毫秒级查出结果。只要你能够清楚的认识到索引的作用以及优化的第一原则:缩小结果集。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5943 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 01:51 · PVG 09:51 · LAX 17:51 · JFK 20:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.