我对MySQL全文搜索很新,我今天遇到了这个问题:
我的公司表在名称栏中有“e-magazine AG”的记录。我在名称列上有一个全文索引。
当我执行此查询时,找不到记录:
SELECT id, name FROM company WHERE MATCH(name) AGAINST('+"e-magazi"*' IN BOOLEAN MODE);
由于破折号我需要使用引号并使用通配符,因为我实现了“当您键入时搜索”功能。
当我搜索整个术语“电子杂志AG”时,会找到记录。
任何想法我在这里做错了什么?我读到有关将短划线添加到单词字符列表(需要配置更新)但我正在寻找一种以编程方式执行此操作的方法。
答案 0 :(得分:3)
本条
MATCH(name) AGAINST('+"e-magazi"*' IN BOOLEAN MODE);
将搜索AND "e" AND NOT "magazi"
;即“e-magazi”中的-
将被解释为not
,即使它在引号内。
因此,它不会按预期工作。
解决方案是使用LIKE应用额外的having
子句。
我知道这个having
很慢,但它只会应用于匹配的结果,因此不应涉及太多行。
我建议像:
SELECT id, name
FROM company
WHERE MATCH(name) AGAINST('magazine' IN BOOLEAN MODE)
HAVING name LIKE '%e-magazi%';
答案 1 :(得分:0)
MySQL全文将文本中的单词e-magazine
视为短语,将不视为单词。因此,它会产生两个字e
和magazine
。虽然它构建了搜索索引,但由于e
(默认为4个字符),它不会将ft_min_word_len
添加到索引中。
搜索查询使用相同的长度限制。这就是为什么搜索e-magazine
会返回与a-magazine
完全相同的结果的原因,因为完全忽略了a
和-
。
但现在你想找到确切的短语e-magazine
。通过它你使用引号,这是找到短语的完整正确的方法,但MySQL不支持短语的运算符,仅支持单词:
https://dev.mysql.com/doc/refman/5.7/en/fulltext-boolean.html
使用此修饰符,某些字符在搜索字符串中单词的开头或结尾具有特殊含义
有些人会建议使用以下查询:
SELECT id, name
FROM company
WHERE MATCH(name) AGAINST('e-magazi*' IN BOOLEAN MODE)
HAVING name LIKE 'e-magazi%';
正如我所说,MySQL忽略e-
并搜索通配符magazi*
。在获得这些结果后,它会使用HAVING
来过滤e-magazi*
的结果,包括e-
。你会发现短语e-magazine AG
。当然,只有在搜索短语包含通配符运算符且您不应该使用引号时才需要HAVING
。此操作符由您的用户使用,而不是您!
注意:只要您不使用%
包围搜索词组,它就会只找到以该词开头的字段。并且你不想包围它,因为它也会找到bee-magazine
。因此,您可能需要额外的OR HAVING name LIKE ' %e-magazi%' OR HAVING NAME LIKE '\\n%e-magazi%'
才能在文本中使用它。
<强>招强>
但最后我更喜欢一个技巧,所以根本不需要HAVING
:
up-to-date
之类的单词替换为up-to-date uptodate
。up-to-date
,请在查询中将其替换为uptodate
。即便如此,您仍然可以在specific
中找到user-specific
,但up-to-date
也可以找到date
。
<强>加成强>
如果用户搜索-well-known huge ports
MySQL,则将其视为not include *well*, could include *known* and *huge*
。当然,您也可以使用其他额外的查询变体来解决这个问题,但是使用上面的技巧可以删除连字符,因此搜索查询看起来就像这样:
SELECT id
FROM texts
WHERE MATCH(text) AGAINST('-wellknown huge ports' IN BOOLEAN MODE)