postgres查询按AND部分匹配排序,然后OR匹配

Posted

技术标签:

【中文标题】postgres查询按AND部分匹配排序,然后OR匹配【英文标题】:postgres query to order by AND partial matches and then OR matches 【发布时间】:2020-08-18 12:23:17 【问题描述】:

所以我有一张places 的表格。每个地方可以有多个posts。每个帖子可以有多个tags。每个posttag 都通过tags_map 表连接。所以:

places
  id

posts
  place_id

tags
  id
  name

tags_map
  post_id
  tag_id

我正在尝试编写一个排名/搜索查询,例如如果有人搜索标签ab,那么他们将获得所有标记为ab 的地点的结果,然后是标记为ab 的地点。

如果一个地方有 2 个与之关联的帖子,则它具有所有这些帖子的标签。我正在寻找部分匹配 - 我一直在尝试使用 SIMILAR TO %(a|b)% 但这只是给了我 OR 结果。

排名应该如下:

如果一个地方有两个标签,它的排名高于有一个或的地方。如果它们同时具有两个标签,则总匹配标签较多的标签排名高于匹配标签较少的标签。并且在查询的 OR 部分,它们是按照哪个地方有更多匹配的标签来排名的。

我无法理解所需的必要 JOINS 以及如何聚合 AND 结果并确定其优先级,然后是 OR 结果

这可行吗?

编辑:示例

Places: a, b, c
Posts: a1, a2, b1, b2, c1
Tags: 
  * a1_wand, a1_ball
  * a1_wander
  * b1_baller
  * b2_wand
  * c1_kaballer, c1_bababall

如果您搜索wandball,您首先会得到与球和魔杖部分匹配的那些,因此请放置ab,因为a 有更多匹配项(2 代表wand 和 1 用于球)它会在 b 之前订购(其中 1 用于球,1 用于魔杖)。而c 只匹配一个查询词(两次,但仍然只是其中一个词),所以接下来是。

如果您只搜索ball,那么您将首先发布c,因为它有2 个匹配项,然后ab 都有一个匹配项,因此它们只会在created_at 中排序日期什么的。

【问题讨论】:

【参考方案1】:

如果我理解正确,这只是将所有表格连接在一起,过滤您想要的标签,然后汇总以进行计数:

select pl.*, array_agg(distinct t.name) as tags,
       count(*) as num_matches
from places pl join
     posts p
     on pl.place_id = p.place_id join
     tags_map tm
     on tm.post_id = p.post_id join
     tags t
     on t.tag_id = tm.tag_id
where t.name in ('a', 'b')
group by pl.place_id
order by count(distinct t.name) desc,
         count(*) desc;

编辑:

对于部分匹配,它会是这样的:

select pl.*, array_agg(distinct t.name) as tags,
       count(*) as num_matches
from places pl join
     posts p
     on pl.place_id = p.place_id join
     tags_map tm
     on tm.post_id = p.post_id join
     tags t
     on t.tag_id = tm.tag_id
where t.name ~ 'a|b'
group by pl.place_id
order by (max(t.name ~ 'a')::int) + (max(t.name ~ 'b')::int) desc,
         count(*) desc;

【讨论】:

我想是的!我认为你表达它的方式听起来或多或少是正确的。但是,您可以使用in 运算符进行部分匹配吗?因此,如果有标签aaaaabb,那么它会将aaaaa 作为单个“匹配”并且bbb 部分匹配? @aliak 。 . .不,不使用in。您将使用like 或正则表达式。然而,这不是你在这里问的问题。 也许你没有看到,但我确实在帖子中明确写了:“我正在寻找部分匹配”......它也在标题中。 @aliak 。 . .作为事后的想法,您确实没有示例说明您的意思,以及看起来不正确的匹配代码。但是,我确实将其添加到了答案中。 添加了一个例子。 (让我知道您认为匹配的描述似乎不正确,然后我可以更好地描述它)

以上是关于postgres查询按AND部分匹配排序,然后OR匹配的主要内容,如果未能解决你的问题,请参考以下文章

Python 操作Redis

python爬虫入门----- 阿里巴巴供应商爬虫

Python词典设置默认值小技巧

《python学习手册(第4版)》pdf

Django settings.py 的media路径设置

Python中的赋值,浅拷贝和深拷贝的区别