如何在搜索查询中允许使用连字符进行全文搜索

时间:2011-03-04 10:25:10

标签: mysql search special-characters full-text-search hyphen

我有像“some-or-other”这样的关键字,其中连字符在搜索我的mysql数据库时很重要。我目前正在使用全文功能。

有没有办法逃脱连字符? 我知道一个选项是在 myisam / ftdefs.h 文件中注释掉#define HYPHEN_IS_DELIM,但不幸的是我的主持人不允许这样做。还有其他选择吗?

编辑3-8-11 这是我现在的代码:

$search_input = $_GET['search_input'];
$keyword_safe = mysql_real_escape_string($search_input);
$keyword_safe_fix = "*'\"" . $keyword_safe . "\"'*";


$sql = "
    SELECT *,
        MATCH(coln1, coln2, coln3) AGAINST('$keyword_safe_fix') AS score
        FROM table_name
    WHERE MATCH(coln1, coln2, coln3) AGAINST('$keyword_safe_fix')
    ORDER BY score DESC
";

5 个答案:

答案 0 :(得分:16)

从这里http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

找到带有破折号或连字符的单词的一种解决方案是在BOOLEAN MODE中使用FULL TEXT SEARCH,并用双引号将连字符/破折号括起来。

或者从这里http://bugs.mysql.com/bug.php?id=2095

还有另一种解决方法。它最近被添加到手册中: “ 修改字符集文件:这不需要重新编译。 true_word_char()宏 使用“字符类型”表来区分字母和数字与其他字母和数字 字符。 。您可以编辑其中一个字符集XML中的内容 指定' - '的文件是“字母”。然后使用给定的字符集 FULLTEXT索引。 “

没有亲自尝试过。

修改:此处还有一些来自http://dev.mysql.com/doc/refman/5.0/en/fulltext-boolean.html

的其他信息

包含在双引号(“”“)字符中的短语仅匹配包含短语的行,因为它是键入的。全文引擎将短语拆分为单词并在FULLTEXT索引中执行搜索在MySQL 5.0.3之前,引擎然后对找到的记录中的短语执行子字符串搜索,因此匹配必须在短语中包含非单词字符。从MySQL 5.0.3开始,非单词字符不必是完全匹配:短语搜索只需要匹配包含与短语完全相同的单词并且顺序相同。例如,“测试短语”与MySQL 5.0.3中的“test,phrase”匹配,但之前不匹配。

如果短语不包含索引中的单词,则结果为空。例如,如果所有单词都是停用词或短于索引单词的最小长度,则结果为空。

答案 1 :(得分:3)

使用Binary运算符可能更简单。

SELECT * 
FROM your_table_name 
WHERE BINARY your_column = BINARY "Foo-Bar%AFK+LOL"

http://dev.mysql.com/doc/refman/5.0/en/cast-functions.html#operator_binary

BINARY运算符将其后面的字符串转换为二进制字符串。这是一种简单的方法,可以逐个字节而不是逐个字符地强制进行列比较。这会导致比较区分大小写,即使该列未定义为BINARYBLOBBINARY也会导致尾随空格显着。

答案 2 :(得分:2)

有些人会建议使用以下查询:

SELECT id 
FROM texts
WHERE MATCH(text) AGAINST('well-known' IN BOOLEAN MODE)
HAVING text LIKE '%well-known%';

但是,根据使用的全文运算符,您需要许多变体。任务:实现+well-known +(>35-hour <39-hour) working week*之类的查询。太复杂了!

并且不要忘记ft_min_word_len的默认len,因此搜索up-to-date只会在结果中返回date

<强>招

因为我更喜欢一个技巧,所以根本不需要使用HAVING等构造:

  1. 而不是将以下文本添加到数据库表中:

    "The Up-to-Date Sorcerer" is a well-known science fiction short story.
    将不带超级的连字词复制到注释中文本的末尾:
    "The Up-to-Date Sorcerer" is a well-known science fiction short story.<!-- UptoDate wellknown -->

  2. 如果用户搜索up-to-date,请删除sql查询中的连字符:
    MATCH(text) AGAINST('uptodate ' IN BOOLEAN MODE)

  3. 用户可以将up-to-date作为一个单词找到,而不是获取仅包含date的所有结果(因为ft_min_word_len会导致up和{{1} })。

    当然,在您to文本之前,您应删除echo条评论。

    <强>优点

    • 查询更简单
    • 用户可以像往常一样使用所有全文运算符
    • 查询更快。
    • 如果用户搜索<!-- ... -->,则将其视为-well-known +science。这不是用户期望的。这个技巧也解决了这个问题(因为sql查询搜索not include *well*, could include *known* and must include *science*

答案 3 :(得分:0)

这可能听起来很糟糕,但经过一段时间的努力,我意识到我通过从搜索表达式中删除连字符得到了我想要的结果。例如,如果我搜索单词分隔的&#39;

s3.Bucket('bucketname').upload_file('/local/file/here.txt','folder/sub/path/to/s3key')

返回&#39;单词分隔&#39;如所须。这也会返回其他分隔和单词的实例,但是为每个单词添加SELECT * FROM table WHERE MATCH(column) AGAINST ('word separated'); 运算符可以实现连字符搜索。

+

答案 4 :(得分:0)

我对此的首选解决方案是从搜索词和正在搜索的数据中删除连字符。我在全文表中保留了两列-searchreturnsearch包含已删除各种字符的已清理数据,并且在我的代码也已对其进行清理之后,将这些数据与用户的搜索字词进行了比较。

然后显示return列。

这确实意味着我在数据库中有两个数据副本,但是对我而言,这种折衷是值得的。我的FT表只有约50万行,因此在我的用例中没什么大不了的。