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
。每个post
和tag
都通过tags_map
表连接。所以:
places
id
posts
place_id
tags
id
name
tags_map
post_id
tag_id
我正在尝试编写一个排名/搜索查询,例如如果有人搜索标签a
和b
,那么他们将获得所有标记为a
和b
的地点的结果,然后是标记为a
或b
的地点。
如果一个地方有 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
如果您搜索wand
和ball
,您首先会得到与球和魔杖部分匹配的那些,因此请放置a
和b
,因为a
有更多匹配项(2 代表wand 和 1 用于球)它会在 b
之前订购(其中 1 用于球,1 用于魔杖)。而c
只匹配一个查询词(两次,但仍然只是其中一个词),所以接下来是。
如果您只搜索ball
,那么您将首先发布c
,因为它有2 个匹配项,然后a
和b
都有一个匹配项,因此它们只会在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
运算符进行部分匹配吗?因此,如果有标签aa
、aaa
、bb
,那么它会将aa
和aaa
作为单个“匹配”并且bb
与b
部分匹配?
@aliak 。 . .不,不使用in
。您将使用like
或正则表达式。然而,这不是你在这里问的问题。
也许你没有看到,但我确实在帖子中明确写了:“我正在寻找部分匹配”......它也在标题中。
@aliak 。 . .作为事后的想法,您确实没有示例说明您的意思,以及看起来不正确的匹配代码。但是,我确实将其添加到了答案中。
添加了一个例子。 (让我知道您认为匹配的描述似乎不正确,然后我可以更好地描述它)以上是关于postgres查询按AND部分匹配排序,然后OR匹配的主要内容,如果未能解决你的问题,请参考以下文章