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

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

  •  
  •   yodhcn ·
    yodhcn · 73 天前 · 2286 次点击
    这是一个创建于 73 天前的主题,其中的信息可能已经有所发展或是发生改变。

    提到多对多关系,第一个反应是 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  
       73 天前
    谁告诉你多表 join 效率低的?
    liuzhen
        2
    liuzhen  
       73 天前
    脱离数据量说效率是耍流氓;大表 join 效率是低的,可以考虑拆 sql 多次查询,小表 join 就完事了
    Ashore
        3
    Ashore  
       73 天前
    @liprais csdn(狗头
    CNife
        4
    CNife  
       73 天前
    建议自己实验一下,用 EXPLAIN ANALYZE 看看如何处理和代价如何
    LeegoYih
        5
    LeegoYih  
       73 天前
    表设计合理可以 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  
       73 天前
    有个问题,为啥多标签是交集而不是并集?搜索我一般喜欢并集,筛选喜欢交集。
    zoharSoul
        7
    zoharSoul  
       73 天前
    es 直接拍平了
    codespots
        8
    codespots  
       73 天前
    @iwishing metoo
    yodhcn
        9
    yodhcn  
    OP
       73 天前
    @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  
       73 天前
    这就是 es 出现的原因
    xuelu520
        11
    xuelu520  
       73 天前
    --直接将 3 张表 JOIN 在一起?感觉查询效率会很低。
    这个思维就是错的。
    正常情况 JOIN 查就是了,大表 JOIN 就需要 es 了。
    512357301
        12
    512357301  
       73 天前 via Android
    效率低那是阿里巴巴提出来的吧,好像他们有个 MySQL 开发规范,不过如楼上所说,脱离数据量谈效率就是耍流氓,你一个配置表几千几万条数据,谈效率低,啧啧啧。
    join 效率低说的是百万千万量级的时候效率低,这也不是 join 的锅,这是 MySQL 的锅
    yodhcn
        13
    yodhcn  
    OP
       73 天前 via Android
    @512357301 假设主表(商品表)有 100 万条记录,并且除了 tag 以外,还有 2 个多对多的关系,也需要加入到查询条件中。如果是这种情况,最好还是上倒排索引比较好吧?
    yodhcn
        14
    yodhcn  
    OP
       73 天前 via Android
    @xuelu520 商品表有 100 万条记录,这算大表吗?
    aw2350
        15
    aw2350  
       73 天前
    r_product_tag 不必 一对一吧,这个完全可以用一个数组列解决
    notejava
        16
    notejava  
       73 天前
    直接 join ,然后从产品设计上,让查询时尽量多带命中索引的筛选条件,比如时间筛选。
    lasuar
        17
    lasuar  
       73 天前
    @yodhcn 不算。千万级表加内存即可。
    xuanbg
        18
    xuanbg  
       73 天前
    不要感觉,实际情况是上百万的数据多表关联也能毫秒级查出结果。只要你能够清楚的认识到索引的作用以及优化的第一原则:缩小结果集。
    关于   ·   帮助文档   ·   博客   ·   nftychat   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5263 人在线   最高记录 5634   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 02:18 · PVG 10:18 · LAX 19:18 · JFK 22:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.