我怎样才能操纵MySQL全文search的相关性,使一个领域比另一个更有价值?

假设我有两列,关键字和内容。 我有两个全文索引。 我想要在关键字中与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 

实际上,使用case语句来创build一对标志可能是更好的解决scheme:

 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 

同样,只有所有关键字匹配的排名高于所有仅匹配内容的排名。 我也做了一个假设,即关键字和内容的匹配度是最高的。

创build三个全文索引

  • 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) 

问题是rel1只是在keyword列中给你提供了查询的相关性(因为你只在该列上创build了索引)。 rel2也一样,但是对于content栏。 您现在可以将这两个相关性分数加在一起,应用您喜欢的任何权重。

但是,您没有将这两个索引用于实际search。 为此,你使用你的第三个索引,这是在两列。

(关键字,内容)上的索引控制您的召回。 又名,什么是返回。

两个单独的索引(一个仅用于关键字,一个仅用于内容)控制您的相关性。 你可以在这里应用你自己的权重标准。

请注意,您可以使用任意数量的不同索引(或者,基于其他因素,可能会改变查询时使用的索引和权重…也可能只查询关键字,如果查询包含停用词…则减less加权偏差关键字如果查询包含3个以上的单词…等)。

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

你应该基准性能(注意closuresmysql查询caching进行基准testing,否则你的结果将会出现偏差)。 这不是谷歌级的高效率,但它是非常容易和“开箱即用”,它几乎肯定比在查询中使用“like”好多了。

我觉得它运作得很好。

据我所知,这是不支持MySQL全文search,但您可以通过某种方式在关键字字段中重复该单词多次达到的效果。 而不是关键字“富酒吧”,有“富酒吧富酒吧富”栏,这样的两个富和酒吧是同样重要的关键字列内,因为他们多次出现,他们变得更相关的MySQL。

我们在我们的网站上使用这个工具。

几年前我做了这个,但没有全文索引。 我没有方便的代码(前雇主),但我记得很好的技术。

简而言之,我从每列中select一个“重量”。 例如:

 select table.id, keyword_relevance + content_relevance as relevance from table left join (select id, 1 as keyword_relevance from table_name where keyword match) a on table.id = a.id left join (select id, 0.75 as content_relevance from table_name where content match) b on table.id = b.id 

请在这里放弃任何粗制滥造的SQL,自从我需要写任何东西以来,已经有几年了,而且我正在从头到尾做这件事。

希望这可以帮助!

J.Js

在布尔模式下,MySQL支持“>”和“<”运算符来改变单词对分配给一行的相关性值的贡献。

我不知道这样的事情会起作用吗?

 SELECT *, MATCH (Keywords) AGAINST ('>watermelon' IN BOOLEAN MODE) AS relStrong, MATCH (Title,Keywords,Content) AGAINST ('<watermelon' IN BOOLEAN MODE) AS relWeak FROM about_data WHERE MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE) ORDER by (relStrong+relWeak) desc 

我需要类似的东西,并使用OP的解决scheme,但我注意到全文不匹配部分单词。 因此,如果“西瓜”在“关键字”或“内容”中作为单词的一部分(如watermelonsalesmanager),则不匹配,因为WHERE MATCH而不包含在结果中。 所以我愚弄了一下,并调整了OP的查询:

 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 (Keywords LIKE '%watermelon%' OR Title LIKE '%watermelon%' OR MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE)) HAVING (keywordmatch > 0 OR contentmatch > 0 OR relevance > 0) ORDER BY keywordmatch DESC, contentmatch DESC, relevance DESC 

希望这可以帮助。

更简单的版本只使用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; 

那么,这取决于你到底意味着什么:

我想要在关键字中与foo相关联的行比在内容中具有foo的行更具相关性。

如果你的意思是关键字中的foo的行应该在内容中的foo的任何一行之前 ,那么我将执行两个单独的查询,一个用于关键字,然后(可能懒洋洋地,只有在被请求时)另一个内容。

如果指标只是所有关键字匹配比所有内容匹配更“有价值”,那么您可以使用行计数的联合。 沿着这些线的东西。

 select * from ( select row_number() over(order by blahblah) as row, t.* from thetable t where keyword match union select row_number() over(order by blahblah) + @@rowcount + 1 as row, t.* from thetable t where content match ) order by row 

对于任何比这更复杂的事情,如果你想在每一行都加上一个实际的重量,我不知道如何提供帮助。