如何操纵MySQL全文搜索相关性以使一个字段比另一个字段更"有价值"?

Buz*_*uzz 38 mysql indexing search full-text-search relevance

假设我有两列,关键字和内容.我有两个全文索引.我希望关键字中的foo行与内容中的foo行具有更多相关性.我需要做些什么才能使MySQL对关键字中的匹配项进行加权?

我正在使用"匹配"语法.

解:

能够以下列方式完成这项工作:

SELECT *, 
CASE when Keywords like '%watermelon%' then 1 else 0 END as keywordmatch, 
CASE when Content like '%watermelon%' then 1 else 0 END as contentmatch,
MATCH (Title, Keywords, Content) AGAINST ('watermelon') AS relevance 
FROM about_data  
WHERE MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE) 
HAVING relevance > 0  
ORDER by keywordmatch desc, contentmatch desc, relevance desc 
Run Code Online (Sandbox Code Playgroud)

min*_*ker 81

创建三个全文索引

  • a)关键字列中的一个
  • b)内容栏中的一个
  • c)关键字和内容列中的一个

然后,您的查询:

SELECT id, keyword, content,
  MATCH (keyword) AGAINST ('watermelon') AS rel1,
  MATCH (content) AGAINST ('watermelon') AS rel2
FROM table
WHERE MATCH (keyword,content) AGAINST ('watermelon')
ORDER BY (rel1*1.5)+(rel2) DESC
Run Code Online (Sandbox Code Playgroud)

关键在于,rel1只在keyword列中为您提供查询的相关性(因为您仅在该列上创建了索引). rel2做同样的事情,但对于content专栏.您现在可以将这两个相关性分数一起应用于您喜欢的任何权重.

但是,您没有将这两个索引中的任何一个用于实际搜索.为此,您使用第三个索引,它位于两列上.

(关键字,内容)上的索引控制您的召回.阿卡,还有什么.

两个单独的索引(一个仅关键字,一个仅关于内容)控制您的相关性.您可以在此处应用自己的加权标准.

请注意,您可以使用任意数量的不同索引(或者根据其他因素改变您在查询时使用的索引和权重...如果查询包含停用词,则仅搜索关键字...减少加权偏差关键字,如果查询包含超过3个单词...等).

每个索引都占用磁盘空间,因此索引越多,磁盘越多.而反过来,mysql的内存占用更高.此外,插入将花费更长时间,因为您有更多的索引要更新.

对于您的情况,您应该对性能进行基准测试(小心关闭mysql查询缓存以进行基准测试,否则您的结果将会出现偏差).这不是谷歌级效率,但它非常容易和"开箱即用",它几乎肯定比你在查询中使用"喜欢"好很多.

我发现它的效果非常好.

  • @mintywalker命令By不应该是`ORDER BY(rel1*1.5)+(rel2)DESC`以获得最高分,因此首先更相关? (2认同)
  • @PanPipes是的它应该是`DESC`,因为更高的相关性是更好的匹配 (2认同)
  • @mintywalker 我只是想说谢谢,这个确切的查询(适应我们的模式)已经在一个社区网站上运行了至少五年,有数万篇新闻文章和数十万注册用户(还有更多)未登记的访客)。始终能够完美地满足我们的需求,而且我们从未遇到过性能问题。 (2认同)

not*_*not 19

实际上,使用case语句来生成一对标志可能是更好的解决方案:

select 
...
, case when keyword like '%' + @input + '%' then 1 else 0 end as keywordmatch
, case when content like '%' + @input + '%' then 1 else 0 end as contentmatch
-- or whatever check you use for the matching
from 
   ... 
   and here the rest of your usual matching query
   ... 
order by keywordmatch desc, contentmatch desc
Run Code Online (Sandbox Code Playgroud)

同样,只有当所有关键字匹配排名高于所有仅内容匹配时,才会这样.我还假设关键字和内容的匹配是最高等级.

  • 使用like语句不是运行搜索的好方法.首先,除非你拆分字符串,否则你只会按照确切的顺序进行匹配.即搜索"LIKE"%T恤red%''与数据库中的"红色T恤"不匹配.其次,您最终会有更长的时间来执行查询,因为LIKE会执行全表扫描. (3认同)
  • @ChrisG`LIKE`在`FROM`子句中使用而不是在`SELECT`中进行全表扫描 (2认同)

lub*_*sdz 6

仅使用2个全文索引的简化版本(贷记来自@mintywalker):

SELECT id, 
   MATCH (`content_ft`) AGAINST ('keyword*' IN BOOLEAN MODE) AS relevance1,  
   MATCH (`title_ft`) AGAINST ('keyword*' IN BOOLEAN MODE) AS relevance2
FROM search_table
HAVING (relevance1 + relevance2) > 0
ORDER BY (relevance1 * 1.5) + (relevance2) DESC
LIMIT 0, 1000;
Run Code Online (Sandbox Code Playgroud)

这将针对检索两个完全索引的列,keyword然后将匹配的相关性选择为两个单独的列。我们将排除不匹配项(关联1和关联2均为零),并通过增加content_ft列的权重对结果进行重新排序。我们不需要复合全文索引。