多标签搜索,后端一般是怎样实现的?不会是多表直接 join 吧? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
yodhcn
V2EX    程序员

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

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

    提到多对多关系,第一个反应是 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
    F281M6Dh8DXpD1g2
        1
    F281M6Dh8DXpD1g2  
       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

    我是在看了站内的这篇帖子才产生的疑问
    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     Solana     5389 人在线   最高记录 6679     &nbs; Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 08:28 PVG 16:28 LAX 01:28 JFK 04:28
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86