【问题标题】:MySQL Full Text Search MysteryMySQL全文搜索之谜
【发布时间】:2011-01-30 00:20:31
【问题描述】:

我们的网站上有一个使用 MySQL 全文搜索的简单搜索,但由于某种原因,它似乎没有返回正确的结果。我不知道这是否是 Amazon RDS(我们的数据库服务器所在的位置)或我们请求的查询的某种问题。

这是数据库表的结构:

CREATE TABLE `items` (
  `object_id` int(9) unsigned NOT NULL DEFAULT '0',
  `slug` varchar(100) DEFAULT NULL,
  `name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`object_id`),
  FULLTEXT KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

下面是对该表的简单全文搜索查询和返回结果:

select object_id ,slug,name from items where MATCH (name) AGAINST ('+ski*' IN BOOLEAN MODE) order by name;

+-----------+-----------------------------------+------------------+
| object_id | slug                              | name             |
+-----------+-----------------------------------+------------------+
|  10146041 | us/new-hampshire/dartmouth-skiway | Dartmouth Skiway |
+-----------+-----------------------------------+------------------+

如果我改为使用 LIKE,我会得到一组不同的结果:

select object_id,slug,name from items where name LIKE "%ski%" order by name;

+-----------+------------------------------------------+----------------------------------+
| object_id | slug                                     | name                             |
+-----------+------------------------------------------+----------------------------------+
|  10146546 | us/new-york/brantling-ski                | Brantling Ski                    |
|  10146548 | us/new-york/buffalo-ski-club             | Buffalo Ski Club                 |
|  10146041 | us/new-hampshire/dartmouth-skiway        | Dartmouth Skiway                 |
|  10146352 | us/montana/discover-ski                  | Discover Ski                     |
|  10144882 | us/california/donner-ski-ranch           | Donner Ski Ranch                 |
|  10146970 | us/new-york/hickory-ski-center           | Hickory Ski Center               |
|  10146973 | us/new-york/holimont-ski-area            | Holimont Ski Area                |
|  10146283 | us/minnesota/hyland-ski                  | Hyland Ski                       |
|  10145911 | us/nevada/las-vegas-ski-snowboard-resort | Las Vegas Ski & Snowboard Resort |
|  10146977 | us/new-york/maple-ski-ridge              | Maple Ski Ridge                  |
|  10146774 | us/oregon/mount-hood-ski-bowl            | Mt. Hood Ski Bowl                |
|  10145949 | us/new-mexico/sipapu-ski                 | Sipapu Ski                       |
|  10145952 | us/new-mexico/ski-apache                 | Ski Apache                       |
|  10146584 | us/north-carolina/ski-beech              | Ski Beech                        |
|  10147973 | canada/quebec/ski-bromont                | Ski Bromont                      |
|  10146106 | us/michigan/ski-brule                    | Ski Brule                        |
|  10145597 | us/massachusetts/ski-butternut           | Ski Butternut                    |
|  10145117 | us/colorado/ski-cooper                   | Ski Cooper                       |
|  10146917 | us/pennsylvania/ski-denton               | Ski Denton                       |
|  10145954 | us/new-mexico/ski-santa-fe               | Ski Santa Fe                     |
|  10146918 | us/pennsylvania/ski-sawmill              | Ski Sawmill                      |
|  10145299 | us/illinois/ski-snowstar                 | Ski Snowstar                     |
|  10145138 | us/connecticut/ski-sundown               | Ski Sundown                      |
|  10145598 | us/massachusetts/ski-ward                | Ski Ward                         |
+-----------+------------------------------------------+----------------------------------+

我完全不知道为什么使用全文搜索的查询不起作用。我希望那里的一些 MySQL 专家可以指出我们查询中的错误。

提前感谢您的帮助!

【问题讨论】:

    标签: mysql full-text-search


    【解决方案1】:

    来自MySQL docs

    • + 前导加号表示 这个词必须出现在 返回的每一行。

    • * 星号作为 截断(或通配符)运算符。 与其他运算符不同,它应该 被附加到单词之后 做作的。单词匹配,如果他们开始 * 前面的单词 运算符。

      如果用 截断运算符,它不是 从布尔查询中剥离,甚至 如果它太短(如确定 来自 ft_min_word_len 设置)或 一个停用词。发生这种情况是因为 单词不会被视为太短或 停用词,,但必须作为前缀 出现在文件中 以 the 开头的单词的形式 前缀

    在上下文中:

    匹配(...) 反对(...)

    MATCH (name) AGAINST ('+ski*' IN BOOLEAN MODE) 表示您正在搜索的行中name 列中的单词必须包含 ski,并且必须以单词@ 开头 987654327@.

    在您发布的集合中,Dartmouth Skiway 是唯一符合这些要求的 name:它包含单词 ski,并以单词 ski 为前缀。

    其他name 列,虽然它们匹配第一条规则:必须包含ski,它们不ski 为前缀,如您的规定规则。您的布尔搜索返回的行是唯一具有name 列的行,该列包含两个包含 ski 的单词,并且是ski 的单词前缀 .

    按照 ajreal 的建议,尝试减少 my.cnf 中的 ft_min_len_word_setting。由于默认设置,您的搜索可能无法得到您期望的结果。尝试将其减少到 3。

    WHERE 列 LIKE %text%

    WHERE name LIKE "%ski%" 搜索具有包含skiname 列的行,无论单词出现在何处。

    【讨论】:

    • 感谢您的详尽解释!您能否建议我如何更新我的原始 MATCH(...) AGAINST(...) 查询以执行与 LIKE 查询相同的搜索?我现在明白了这个问题,但仍然不清楚解决方案。
    • 如果您不担心ski 之后是否有任何内容,那么您可以尝试删除*。这应该意味着“查找包含以ski 开头的单词的name 列的行。
    • 我遇到的问题是,无论我如何更新查询,它都会返回 0 个结果,但上面发布的表单除外。这可能与下面@ajreal 建议的 ft_min_work_len 有关吗?
    • 就像ajreal说的,你能试试吗?您需要添加他在my.cnf 中提到的行,在标准Linux MySQL 安装上的/etc/my.cnf 中找到,然后重新启动mysql。让我们知道它是否有效?
    【解决方案2】:

    要索引的单词的最小和最大长度由 ft_min_word_len 和 ft_max_word_len 系统变量定义。 (请参阅第 5.1.4 节,“服务器系统变量”。)默认最小值是四个字符;默认最大值取决于版本。如果更改任一值,则必须重建 FULLTEXT 索引。例如,如果您想搜索三个字符的单词,您可以通过将以下行放入选项文件中来设置 ft_min_word_len 变量:

    资源 - http://dev.mysql.com/doc/refman/5.1/en/fulltext-fine-tuning.html

    配置:

    [mysqld]
    ft_min_word_len=3

    【讨论】:

    • 提到的行应该放在my.cnf,可以在标准linux MySQL安装的/etc/my.cnf中找到。
    猜你喜欢
    • 1970-01-01
    • 2010-10-22
    • 2015-07-03
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 2016-08-24
    • 2021-01-28
    相关资源
    最近更新 更多