如何改进mysql NATURAL LANGUAGE MODE搜索查询?

时间:2016-06-01 20:02:14

标签: mysql sql

这是我的查询

SELECT * FROM myTable WHERE MATCH (name) AGAINST ("Apple M1" IN NATURAL LANGUAGE MODE) 

如果我搜索Apple M1作为结果我得到Orange M1然后第三个或更多位置我得到Apple M-1 - 这是我存储的值,我假设应该是第一个!

我的问题是:有一种方法可以微调mysql搜索吗?

1 个答案:

答案 0 :(得分:5)

改善MySQL自然语言模式搜索的最佳方法是使用Boolean Full-Text Searches代替。它将与自然语言模式搜索相同,但您可以使用其他修饰符来微调您的结果,例如:由

  

<强>&GT; &LT;

     

这两个运算符用于更改单词对分配给行的相关性值的贡献。 &gt;运算符增加了贡献和&lt;运营商减少它。

有一个小的区别,布尔模式搜索不会根据相关性自动排序,所以你必须自己订购。

SELECT * FROM myTable 
WHERE MATCH (name) AGAINST (">Apple M1" IN BOOLEAN MODE) 
ORDER BY MATCH (name) AGAINST (">Apple M1" IN BOOLEAN MODE) desc

并注意:如果您与M-1匹配,则两个版本的全文搜索都找不到M1(即使最小字长设置为2)。它只会查找exakt(通常不区分大小写)单词匹配,它不会查找类似的单词(除非您使用*)。它将“仅”通过某种算法权衡(精确)单词的组合,如果使用它们,则使用修饰符。

更新根据评论进行了一些额外的澄清:

如果您与Apple M1匹配,则会按任意顺序返回包含(不区分大小写)AppleM1的行,例如M1 appleApple M4Apple M-1Orange M1。它找不到Apples M4Orange M-1,因为它们不完全是那个词。例如。 like '%M-1%'也找不到Apple M1。但是如果你愿意,你可以匹配Apple*来查找AppleApples,但它总是在单词的末尾,*Apple*是不可能的,你必须然后使用like '%Apple%'

这些行然后由评分算法排序,这将基本上对文本中较不常见的单词进行评分,而不是非常常见的单词。如果您添加>Apple,则会为Apple提供更高的值。它只是一个数字,您可以将它们添加到您的选择中,例如select ..., MATCH (name) AGAINST (">Apple M1" IN BOOLEAN MODE) as score感受到这一点。

还有其他一些事情需要考虑:

  • 只有具有最小长度的单词才会添加到索引中。该长度由innodb的innodb_ft_min_token_size或myisam的ft_min_word_len给出。所以你应该把它设置为例如2要包含M1(否则,此单词对您的搜索不会产生任何影响。因为在您的示例中,您找到了Orange M1,我认为它设置正确)。

  • -通常被视为连字符。因此,您文本中的M-1将分为两个单词M1(根据您的最小单词长度设置可能包含也可能不包含,因此可能将其设置为1) 。您可以通过向字符集添加-来更改该行为(请参阅Fine-Tuning MySQL Full-Text Search,以Modify a character set file开头的部分),但如果您搜索,则不会再找到blue-green blue和/或green

  • 全文搜索使用stopwords。这些单词不包含在您的索引中。此列表包含ai,因此即使最小字长为1,您也找不到它们。您可以编辑该列表。

关于M1 / M-1潜在问题的一些想法。要根据您的具体要求进行调整,您必须添加有关搜索和数据的更多信息(可能是另一个问题),但有些想法:

  • 您可以通过将两个版本都包含在搜索查询中来替换包含-的用户输入:一次使用-,但会在""中包含,一次不包含Apple M-1。因此,如果用户输入Apple M1 "M-1",您将创建搜索M1(可以使用或不使用已修改的字符集,但没有新的字符集,您的最小字长必须为1)。如果用户输入M1 "M-1",您应检测到该内容并将其替换为match (name, clean_name) against ("M1" ...

  • 另一种方法是使用干净的连字词保存其他列,并将该列添加到全文索引,然后where match(...) against(...) or product_id like 'M%1%'

  • 你当然可以将喜欢和匹配结合起来,例如:如果您在输入中检测到产品编号,则可以使用where match(...) against(...) or product_id = 'M-1' or product_id = 'M1'where match(...) against(...) or name like '%M%1%'甚至var info = JSON.parse(body); // Get File From Website var itemforjson = item.market_hash_name; // Get The Item Name To Try To Use It In Json depitems[i].value = parseInt(info.itemforjson); // Has To Be A Number 之类的内容,但后者可能会慢很多并且包含大量噪音。并且它可能无法正确评分,但至少它将在结果集中。

但正如我所说,这取决于您的数据和您的要求。