【问题标题】:MySQL: Special Search algorithm using MySQL relevance searchMySQL:使用 MySQL 相关搜索的特殊搜索算法
【发布时间】:2011-12-14 00:03:58
【问题描述】:

我正在尝试在用户只有一个字段的 MySQL 中进行搜索。该表如下所示:

ID          BIGINT
TITLE       TEXT
DESCRIPTION TEXT
FILENAME    TEXT
TAGS        TEXT
ACTIVE      TINYINT

现在如果用户只输入blah blubber,搜索必须检查每个单词是否出现在TITLEDESCRIOTIONFILENAMETAGS字段中。结果本身应按相关性排序,即字符串在记录中出现的频率。我得到了这个示例数据:

ID   | TITLE   | DESCRIPTION  | FILENAME | TAGS | ACTIVE
1    | blah    | blah         | bdsai    | bdha | 1
2    | blubber | blah         | blah     | adsb | 1
3    | blah    | dsabsadsab   | dnsa     | dsa  | 1

在此示例中,ID 2 必须位于顶部(2x blah,1x 鲸脂),然后是 1(2x blah),然后是 3(1x blah)。这个过程应该是动态的,因此用户也可以输入更多的单词,并且相关性与一个或多个单词相同。

这可能只在 MySQL 中实现,还是我必须使用一些 PHP?这将如何运作?

非常感谢您的帮助!问候,弗洛里安

编辑:这是我尝试了 Tom Mac 的答案后的结果:

我有四个如下所示的记录:

ID  | TITLE | DESCRIPTION | FILENAME | TAGS                          | ACTIVE
1   | s     | s           | s        | s                             | 1
2   | 0     | fdsadf      | sdfs     | a,b,c,d,e,f,s,a,a,s,s,as,sada | 1
3   | 0     | s           | s        | s                             | 1
4   | a     | a           | a        | a                             | 1

现在,如果我搜索字符串 s,我应该只得到前三个记录,按相关性 s 排序。这意味着,记录应该是这样的排序:

ID | TITLE | DESCRIPTION | FILENAME | TAGS                          | ACTIVE
2  | 0     | fdsadf      | sdfs     | a,b,c,d,e,f,s,a,a,s,s,as,sada | 1        <== 8x s
1  | s     | s           | s        | s                             | 1        <== 4x s
3  | 0     | s           | s        | s                             | 1        <== 3x s

现在,我尝试了这样的查询(表的名称是PAGES):

select t . *
  from (

        select 
              match(title) against('*s*' in boolean mode) 
            + match(description) against('*s*' in boolean mode) 
            + match(filename) against('*s*' in boolean mode) 
            + match(tags) against('*s*' in boolean mode) 
            as matchrank,
                bb . *
          from pages bb) t
 where t.matchrank > 0
 order by t.matchrank desc

这个查询返回这个:

matchRank | ID  | TITLE | DESCRIPTION | FILENAME | TAGS                          | ACTIVE
2         | 2   | 0     | fdsadf      | sdfs     | a,b,c,d,e,f,s,a,a,s,s,as,sada | 1

这是因为通配符吗?我认为,字符串*s* 也应该找到一个只有s 的值...

【问题讨论】:

  • 事实证明通配符解决方案不是ft_min_word_len 设置的有效解决方法。最好的办法是将此设置更改为 1 并重新启动 mysql。如果您无法使用 LIKE 编写解决方法,但对于多个字符串和 4 个字符以下的字符来说效果不佳,例如('s')

标签: php mysql relevance


【解决方案1】:

这可能会对您有所帮助。它确实假设您的 MySQL 表使用 MyISAM 引擎:

create table blubberBlah (id int unsigned not null primary key auto_increment,
title varchar(50) not null,
description varchar(50) not null,
filename varchar(50) not null,
tags varchar(50)not null,
active tinyint not null
) engine=MyISAM;

insert into blubberBlah (title,description,filename,tags,active) 
values ('blah','blah','bdsai','bdha',1);
insert into blubberBlah (title,description,filename,tags,active) 
values ('blubber','blah','blah','adsb',1);
insert into blubberBlah (title,description,filename,tags,active) 
values ('blah','dsabsadsab','dnsa','dsa',1);

select t.*
from
(
 select MATCH (title) AGAINST ('blubber blah' IN BOOLEAN MODE)
       +MATCH (description) AGAINST ('blubber blah' IN BOOLEAN MODE)
       +MATCH (fileName) AGAINST ('blubber blah' IN BOOLEAN MODE)
       +MATCH (tags) AGAINST ('blubber blah' IN BOOLEAN MODE) as matchRank,
       bb.*
from blubberBlah bb
) t
order by t.matchRank desc;

编辑

此解决方案的另一个假设是您搜索的字符串长度 >= 4 个字符。如果“搜索”字符串(即“blubber”或“blah”的长度可能为 1、2 或 3 个字符,那么您可以随时前往 my.cnf 文件并在 @987654325 下添加 ft_min_word_len=1 @ 配置选项。然后重启 MySQL 就可以了。

最后一件事:如果您正在考虑使用这种方法,那么您应该为每一列添加一个 FULLTEXT INDEX。因此:

ALTER TABLE blubberBlah add fulltext index `blubberBlahFtIdx1`(`title`);
ALTER TABLE blubberBlah add fulltext index `blubberBlahFtIdx2`(`description`);
ALTER TABLE blubberBlah add fulltext index `blubberBlahFtIdx3`(`filename`);
ALTER TABLE blubberBlah add fulltext index `blubberBlahFtIdx4`(`tags`);

您可以在MySQL Docs 中找到有关 BOOLEAN FULLTEXT 搜索的更多详细信息。

【讨论】:

  • 您运行的是哪个版本的 MySQL?对您的表或我的回答中的示例表运行查询时,您得到的 matchRank 值为 0?
  • 我正在运行 5.0.45,我用我的 ^^ ("PAGES") 替换了表名
  • 您能否尝试运行我的答案中的确切示例,即使用您在问题中提供的确切数据,并让我知道它是否有效?如果它确实有效,那么我怀疑问题出在 PAGES 表中的数据上
  • 见鬼,它适用于你的桌子.....我试过这样:ykg-clan.de/tables.png
  • 有了您的桌子,一切正常。如果我尝试使用我的(之前查看评论链接),我会得到错误的结果。
【解决方案2】:

不是在“布尔模式”中搜索,而是使用 Match() Against() 来确定分数。将这些分数相加以获得相关性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 2014-08-29
    • 2016-01-07
    相关资源
    最近更新 更多