MySQL 全文搜索并按相关性 + TIME 排序
MySQL fulltext search and sort by relevance + TIME
我正在尝试在我的网站上显示 "related articles" 块。为此,我使用以下查询:
SELECT *, MATCH(title, content) AGAINST('search string') AS score
FROM news_items
WHERE MATCH(title, content) AGAINST('search string')
ORDER BY score DESC LIMIT 4
但是,它经常显示非常旧的文章,而我想显示最新的文章,因此我将查询修正如下:
SELECT *, MATCH(title, content) AGAINST('search string') AS score
FROM news_items
WHERE MATCH(title, content) AGAINST('search string') > 4
ORDER BY ctime DESC, score DESC LIMIT 4
但在这种情况下,我无法获得最相关的文章:(
关于如何同时找到最相关和最新的文章有什么想法吗?
提前致谢!
您可以更改为总分...像这样:
SELECT *,
(
MATCH(title, content) AGAINST('search string')
-
(ABS(DATEDIFF(`timestampfield`, NOW())) / 365)
) AS score
FROM news_items
WHERE
MATCH(title, content) AGAINST('search string') > 4
ORDER BY score DESC LIMIT 4
因为有一个有点时髦的添加,你想要清理它:
- (ABS(DATEDIFF(`timestampfield`, NOW())) / 365)
这是您的 age
分数部分...目前按 <year> = 1 point
缩放
为此,我们首先获取时间戳字段与现在(绝对值)之间的天数:
ABS(DATEDIFF(`timestampfield`, NOW()))
然后我们扩展...
我决定您可能不想根据天数来放宽分数,因为如果某个东西已经存在 30 天,那么它会是 -30... 似乎太苛刻了。所以我选择了年......如果你想按周数计算,除以52
而不是365
......等等。
这个比例因子将是您控制得分匹配和年龄之间的值的方式。
所以它最终是这样的:<match score> - <yearsAgo>
如果你这样做:
- 5(匹配分数)- 0.1(<1 年前)= 4.9 (匹配,但最新)
- 5(匹配分数)- 0.01(<1 年前)= 4.99
- 5(比赛得分)- 1(1 年前)= 4
- 6(比赛得分)- 2(2 年前)= 4
- 9(匹配分数)- 5(5 年前)= 4 (最佳匹配,但旧)
- 7(比赛得分)- 10(10 年前)= -3
注意这假定您的时间戳字段是一个完整的日期时间字段...否则,您将需要重新转换为日期,或者直接操作 unix 时间戳的逻辑。
这里是查询的调试版本:
SELECT
`created`,
MATCH(title, content) AGAINST('awesome') as match_score,
(ABS(DATEDIFF(`created`, NOW())) / 365) as years_ago,
(
MATCH(title, content) AGAINST('awesome')
-
(ABS(DATEDIFF(`created`, NOW())) / 365)
) AS score
FROM news_items
WHERE
MATCH(title, content) AGAINST('awesome') > 4
ORDER BY score DESC LIMIT 4
我正在尝试在我的网站上显示 "related articles" 块。为此,我使用以下查询:
SELECT *, MATCH(title, content) AGAINST('search string') AS score
FROM news_items
WHERE MATCH(title, content) AGAINST('search string')
ORDER BY score DESC LIMIT 4
但是,它经常显示非常旧的文章,而我想显示最新的文章,因此我将查询修正如下:
SELECT *, MATCH(title, content) AGAINST('search string') AS score
FROM news_items
WHERE MATCH(title, content) AGAINST('search string') > 4
ORDER BY ctime DESC, score DESC LIMIT 4
但在这种情况下,我无法获得最相关的文章:(
关于如何同时找到最相关和最新的文章有什么想法吗?
提前致谢!
您可以更改为总分...像这样:
SELECT *,
(
MATCH(title, content) AGAINST('search string')
-
(ABS(DATEDIFF(`timestampfield`, NOW())) / 365)
) AS score
FROM news_items
WHERE
MATCH(title, content) AGAINST('search string') > 4
ORDER BY score DESC LIMIT 4
因为有一个有点时髦的添加,你想要清理它:
- (ABS(DATEDIFF(`timestampfield`, NOW())) / 365)
这是您的 age
分数部分...目前按 <year> = 1 point
为此,我们首先获取时间戳字段与现在(绝对值)之间的天数:
ABS(DATEDIFF(`timestampfield`, NOW()))
然后我们扩展...
我决定您可能不想根据天数来放宽分数,因为如果某个东西已经存在 30 天,那么它会是 -30... 似乎太苛刻了。所以我选择了年......如果你想按周数计算,除以52
而不是365
......等等。
这个比例因子将是您控制得分匹配和年龄之间的值的方式。
所以它最终是这样的:<match score> - <yearsAgo>
如果你这样做:
- 5(匹配分数)- 0.1(<1 年前)= 4.9 (匹配,但最新)
- 5(匹配分数)- 0.01(<1 年前)= 4.99
- 5(比赛得分)- 1(1 年前)= 4
- 6(比赛得分)- 2(2 年前)= 4
- 9(匹配分数)- 5(5 年前)= 4 (最佳匹配,但旧)
- 7(比赛得分)- 10(10 年前)= -3
注意这假定您的时间戳字段是一个完整的日期时间字段...否则,您将需要重新转换为日期,或者直接操作 unix 时间戳的逻辑。
这里是查询的调试版本:
SELECT
`created`,
MATCH(title, content) AGAINST('awesome') as match_score,
(ABS(DATEDIFF(`created`, NOW())) / 365) as years_ago,
(
MATCH(title, content) AGAINST('awesome')
-
(ABS(DATEDIFF(`created`, NOW())) / 365)
) AS score
FROM news_items
WHERE
MATCH(title, content) AGAINST('awesome') > 4
ORDER BY score DESC LIMIT 4