0

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

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

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

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 blubber),然后是 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

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

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......

4

2 回答 2

2

这可能会帮助你。它确实假设您的 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 文件并ft_min_word_len=1[mysqld]配置选项下添加。然后重新启动 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 搜索的更多详细信息。

于 2011-10-24T11:22:35.740 回答
1

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

于 2012-06-06T13:51:09.813 回答