【问题标题】:Identical FULLTEXT vs REGEXP vs LIKE searches returning different results相同的 FULLTEXT vs REGEXP vs LIKE 搜索返回不同的结果
【发布时间】:2019-10-23 08:02:54
【问题描述】:

我尝试使用三个不同的 MYSQL 查询来搜索单个列(类列表);目标是该列应包含_10_,但不应包含_3__15_(示例值可能类似于_4_8_10_15_,在给定_15_ 时会失败)。

我尝试了三种不同的方法,三种方法都没有错误,但结果却不同:

1) FULLTEXT 搜索(在 classlist 上启用 FULLTEXT 索引)没有返回错误,也没有返回任何结果。

SELECT classlist, classcount FROM subgroupstest WHERE MATCH (classlist) AGAINST ('+10 -3 -15' IN BOOLEAN MODE)

2) 简单的 LIKE 子句返回 516 行。

SELECT classlist, classcount FROM subgroupstest WHERE classlist LIKE "%_10_%" AND classlist NOT LIKE "%_3_%" AND classlist NOT LIKE "%_15_%"

3) LIKE/REGEXP 混合返回 1,912 个结果。它返回的一个例子是第二种方法不是_4_10_18_23_-这是一个准确的结果,并且这个结果中没有重复,所以我不得不假设第二种方法(同样是第一种!)以某种方式丢失了一些东西。

SELECT classlist, classcount FROM subgroupstest WHERE classlist LIKE '%_10_%' AND classlist NOT REGEXP '_3_|_15_'

此时我只能摇头,不确定发生了什么。我总是可以尝试寻找更深层次的问题,但是有人可以验证我是否正确地执行了 REGEXP 和/或 FULLTEXT 方法?在过去几个小时的阅读和模仿之后,它看起来就像我在 Google 上看到的那样,但这是我第一次使用其中任何一种。

【问题讨论】:

  • 一条评论:全文索引受制于最小(和最大)单词和标记长度,以及排除的单词列表dev.mysql.com/doc/refman/8.0/en/fulltext-fine-tuning.html,下划线字符也是 LIKE 中的通配符,除非它被转义
  • 啊!这解释了那部分。我现在用#替换了_书挡(如#10),并适当替换了代码;现在方法 2 和 3 正在工作。我确实意识到 FULLTEXT 需要同样的东西,所以我在这里更新了它(虽然仍然没有结果):SELECT classlist, classcount FROM subgroupstest WHERE MATCH (classlist) AGAINST ('+#10# -#3# -#15#' IN BOOLEAN MODE)
  • 对于全文:尝试将ft_min_word_len 设置为 1 并使用空格作为分隔符。
  • @AlexGold 不要在你的问题中写出解决方案。您可以就您的问题发布答案。

标签: mysql database


【解决方案1】:

根据 cmets,我找到了解决方案。首先,我将 MYSQL 条目设为纯空格(在前面的示例中为4 8 10 15)。

然后搜索工作如下:

SELECT classlist, classcount FROM subgroupstest WHERE MATCH (classlist) AGAINST ('+10 -3 -15' IN BOOLEAN MODE)

SELECT classlist, classcount FROM subgroupstest WHERE classlist LIKE "% 10 %" AND classlist NOT LIKE "% 3 %" AND classlist NOT LIKE "% 15 %"

SELECT classlist, classcount FROM subgroupstest WHERE classlist LIKE '% 10 %' AND classlist NOT REGEXP ' 3 | 15 '

有趣的是,简单的“Like”版本比其他两个快 2-3 倍!全文也比 REGEXP 稍慢。

【讨论】:

  • 这可能很明显(但以防万一)foo LIKE '% 4 %' 匹配 '4 8 16' 的 foo 值,即当列表中的第一个条目是' t 前面有一个空格,与最后一个不跟空格的条目相同......这可能需要在值的开头和结尾处使用一些特殊的“保护”字符,例如# 4 8 9 # 确保有空格。就个人而言,我倾向于避免这种“搜索存储在字符串中的列表”设计。但如果必须,我会使用逗号分隔值 '4,8,12,16' 并使用 FIND_IN_SET()
  • dev.mysql.com/doc/refman/8.0/en/… 例如使用 foo = '4,8,10,15` ,然后 ... WHERE FIND_IN_SET('10',foo) AND NOT FIND_IN_SET('3',foo) 将评估为 TRUE
猜你喜欢
  • 1970-01-01
  • 2018-01-21
  • 1970-01-01
  • 1970-01-01
  • 2014-03-27
  • 2016-11-22
  • 1970-01-01
  • 2015-06-20
  • 1970-01-01
相关资源
最近更新 更多