Kim*_*cks 2 php mysql search full-text-search
使用mysql和PHP
我已经使用了MATCH AGAINST条款.
它可以很好地对抗各个表.就像我想在商店桌上搜索一样.没问题.
我想要的是能够在单个结果页面中搜索和显示不同表格的结果.
例如,如果我输入"巧克力衣服"
我可以得到4个结果如下:
Shop1结果
ShopItem1结果
ShopItem2结果
Shop2结果
当然,最相关的结果应该排在第一位.
我有很多问题.设计明智和实施明智
1)我应该改变我的设计吗?我正在考虑有一个名为搜索结果的单独表格,其中包含来自SHOPS和SHOPPRODUCTS表的数据.但这意味着我有一些数据重复.
2)我应该保留目前的设计吗?如果是这样,那么我怎么能在两个不同的表中按相关性排序搜索结果呢?
我看到rottentomatoes将他们的搜索结果组织在不同的组中.但是,我们更喜欢搜索结果不受不同类型的限制,特别是当我们进行分页时,UI更难以导航.
http://www.rottentomatoes.com/search/full_search.php?search=girl
或者那实际上是最好的出路?
我希望有人可以就这类事情向我提供指导,如果您有跨多数表格生成搜索结果的经验.
因为按需求,我会把表结构放在这里
CREATE TABLE `shopitems` (
`id` int(10) unsigned NOT NULL auto_increment,
`ShopID` int(10) unsigned NOT NULL,
`ImageID` int(10) unsigned NOT NULL,
`name` varchar(100) NOT NULL,
`description` varchar(255) NOT NULL,
`pricing` varchar(45) NOT NULL,
`datetime_created` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;
/*Table structure for table `shops` */
DROP TABLE IF EXISTS `shops`;
CREATE TABLE `shops` (
`id` int(11) NOT NULL auto_increment,
`title` varchar(100) default NULL,
`description` text,
`keywords` text,
`url` varchar(255) default '',
`owner_id` varchar(255) default NULL,
`datetime_created` datetime default NULL,
`created_by` varchar(255) default NULL,
`datetime_modified` datetime default NULL,
`modified_by` varchar(255) default NULL,
`overall_rating_avg` decimal(4,2) default '0.00',
PRIMARY KEY (`id`),
FULLTEXT KEY `url` (`url`),
FULLTEXT KEY `TitleDescFullText` (`keywords`,`title`,`description`,`url`)
) ENGINE=MyISAM AUTO_INCREMENT=3051 DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)
我打算搜索shopproducts表的描述和名称列.
但是你可以看到它还没有实现.
虽然对商店的搜索已经开始运行.
这里有一些"游戏规则",你必须记住解决这个问题.您可能已经知道这些,但明确说明它们可能有助于确认其他读者.
MATCH()针对全文索引查询必须针对全文索引的所有列匹配,在索引声明的顺序.我会创建第三个表来存储您要索引的内容.无需冗余存储此内容 - 仅将其存储在第三个表中.这借用了面向对象设计的"通用超类"概念(只要我们可以将其应用于RDBMS设计).
CREATE TABLE Searchable (
`id` SERIAL PRIMARY KEY,
`title` varchar(100) default NULL,
`description` text,
`keywords` text,
`url` varchar(255) default '',
FULLTEXT KEY `TitleDescFullText` (`keywords`,`title`,`description`,`url`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `shopitems` (
`id` INT UNSIGNED NOT NULL,
`ShopID` INT UNSIGNED NOT NULL,
`ImageID` INT UNSIGNED NOT NULL,
`pricing` varchar(45) NOT NULL,
`datetime_created` datetime NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `shops` (
`id` INT UNSIGNED NOT NULL,
`owner_id` varchar(255) default NULL,
`datetime_created` datetime default NULL,
`created_by` varchar(255) default NULL,
`datetime_modified` datetime default NULL,
`modified_by` varchar(255) default NULL,
`overall_rating_avg` decimal(4,2) default '0.00',
PRIMARY KEY (`id`),
FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)
请注意,现在只有一个带有自动增量键的表Searchable.这些表格shops和shopitems使用与兼容的数据类型的关键,但不会自动递增.所以,你必须创建一个行Searchable产生的id值,然后才能创建无论是在相应的行shops或shopitems.
我已添加FOREIGN KEY声明用于说明目的,即使MyISAM将默默地忽略这些约束(并且您已经知道必须使用MyISAM来支持全文索引).
现在,您可以同时搜索的文本内容shops,并shopitems在一个单一的查询,使用单一的全文索引:
SELECT S.*, sh.*, si.*,
MATCH(keywords, title, description, url) AGAINST('dummy') As score
FROM Searchable S
LEFT OUTER JOIN shops sh ON (S.id = sh.id)
LEFT OUTER JOIN shopitems si ON (S.id = si.id)
WHERE MATCH(keywords, title, description, url) AGAINST('dummy')
ORDER BY score DESC;
Run Code Online (Sandbox Code Playgroud)
当然,对于Searchable只有一个表中的给定行,应该匹配商店或商店,并且这些表具有不同的列.因此,结果中的任何一个sh.*或si.*将为NULL.您可以在应用程序中格式化输出.
其他几个答案建议使用Sphinx Search.这是另一种补充MySQL的技术,增加了更复杂的全文搜索功能.它具有出色的查询性能,因此有些人对此非常着迷.
但是创建索引并特别是逐步添加到索引是昂贵的.实际上,更新Sphinx搜索索引的成本非常高,建议的解决方案是为较旧的归档数据创建一个索引,为更新的数据创建另一个较小的索引,以便更新.然后,每个搜索都必须针对两个单独的索引运行两个查询.如果你的数据自然不适合旧数据不变的模式,那么无论如何你可能无法利用这个技巧.
重新评论:以下是Sphinx Search文档中有关索引实时更新的摘录:
当总数据集太大而无法从头开始重新编制索引时,会出现频繁的情况,但新记录的数量相当小.示例:一个包含1,000,000个已归档帖子的论坛,但每天只有1,000个新帖子.
在这种情况下,可以使用所谓的"主+增量"方案来实现"实时"(几乎实时)索引更新.
我们的想法是,由于更新Sphinx搜索索引的成本很高,因此他们的解决方案是让您更新的索引尽可能小.因此,只有最新的论坛帖子(在他们的示例中),而存档的论坛帖子的较大历史永远不会更改,因此您只为该集合构建一个第二个更大的索引.当然,如果要进行搜索,则必须查询两个索引.
定期地说,每周一次,"最近的"论坛消息将被视为"存档",您必须将最近帖子的当前索引合并到存档索引,并启动较小的索引.他们确实指出,在更新数据后,合并两个Sphinx搜索索引比重新索引更有效.
但我的观点是,与最近频繁更新的数据相比,并非所有数据集都自然地落入了永不改变的归档数据集模式中.
以您的数据库为例:您有商店和商店.与新行相比,如何将这些行分成永不改变的行?应允许目录中的任何商店或产品更新其描述.但是,由于每次进行更改都需要重建整个Sphinx搜索索引,因此这将成为一项非常昂贵的操作.也许你会排队更改并批量应用它们,每周重建一次索引.但是试着向商店供应商解释为什么对他们的商店描述进行微小改动直到周日晚上都不会生效.