我发现当您在一个字符串中寻找关键字时,Levenshtein距离可能对于完整字符串的搜索很好用,但是此方法有时不会返回所需结果。此外,SOUNDEX函数不适用于除英语以外的其他语言,因此它相当受限制。您可以使用LIKE,但它只适用于基本搜索。您可能需要研究其他搜索方法来实现您想要的目标。例如:
您可以将
Lucene用作项目的搜索基础。它已在大多数主要编程语言中实现,并且速度相当快且多才多艺。这种方法可能是最好的,因为它不仅搜索子字符串,还搜索字母转换、前缀和后缀(全部组合)。但是,您需要保留单独的索引(使用CRON定期从独立脚本更新它即可)。
或者,如果您想要MySQL解决方案,则全文功能非常好,并且肯定比存储过程更快。如果您的表不是MyISAM,则可以创建一个临时表,然后执行全文搜索:
CREATE TABLE IF NOT EXISTS `tests`.`data_table` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(2000) CHARACTER SET latin1 NOT NULL,
`description` text CHARACTER SET latin1 NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1 ;
使用
数据生成器来生成一些随机数据,如果您不想自己创建的话...
** 注意 **:列类型应为
latin1_bin
,以执行区分大小写的搜索而不是区分大小写的
latin1
。对于Unicode字符串,我建议使用
utf8_bin
进行区分大小写搜索和
utf8_general_ci
进行不区分大小写搜索。
DROP TABLE IF EXISTS `tests`.`data_table_temp`;
CREATE TEMPORARY TABLE `tests`.`data_table_temp`
SELECT * FROM `tests`.`data_table`;
ALTER TABLE `tests`.`data_table_temp` ENGINE = MYISAM;
ALTER TABLE `tests`.`data_table_temp` ADD FULLTEXT `FTK_title_description` (
`title` ,
`description`
);
SELECT *,
MATCH (`title`,`description`)
AGAINST ('+so* +nullam lorem' IN BOOLEAN MODE) as `score`
FROM `tests`.`data_table_temp`
WHERE MATCH (`title`,`description`)
AGAINST ('+so* +nullam lorem' IN BOOLEAN MODE)
ORDER BY `score` DESC;
DROP TABLE `tests`.`data_table_temp`;
请从MySQL API参考页面了解更多相关信息。
这样做的缺点是它不会查找字母转换或"类似,发音相似"的单词。
** 更新 **
使用Lucene进行搜索,您只需要创建一个cron作业(所有Web主机都具有此"功能"),其中此作业将仅执行一个PHP脚本(例如"cd /path/to/script; php searchindexer.php"),该脚本将更新索引。原因在于索引数千个"文档"(行、数据等)可能需要几秒甚至几分钟,但这是为了确保所有搜索尽可能快地执行。因此,您可能希望创建一个延迟作业由服务器运行。可以是在晚上或下一个小时,这取决于您。PHP脚本应该长这样:
$indexer = Zend_Search_Lucene::create('/path/to/lucene/data');
Zend_Search_Lucene_Analysis_Analyzer::setDefault(
// change this option for your need
new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()
);
$rowSet = getDataRowSet();
foreach ($rowSet as $row) {
$doc = new Zend_Search_Lucene_Document();
$doc->addField(Zend_Search_Lucene_Field::text('field1', $row->field1, 'utf-8'))
->addField(Zend_Search_Lucene_Field::text('field2', $row->field2, 'utf-8'))
->addField(Zend_Search_Lucene_Field::unIndexed('someValue', $someVariable))
->addField(Zend_Search_Lucene_Field::unIndexed('someObj', serialize($obj), 'utf-8'))
;
$indexer->addDocument($doc);
}
$indexer->optimize();
$indexer->commit();
那么,这基本上就是如何进行搜索(基本搜索)的方法:
$index = Zend_Search_Lucene::open('/path/to/lucene/data');
Zend_Search_Lucene_Analysis_Analyzer::setDefault(
new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive()
);
Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('utf-8');
$query = 'php +field1:foo';
$hits = $index->find($query);
$numHits = count($hits);
foreach ($hits as $hit) {
$score = $hit->score;
$field1 = $hit->field1;
}
以下是关于Lucene的优秀站点,包括Java、PHP和.Net。
总之,每种搜索方法都有其优缺点:
- 你提到了Sphinx搜索,看起来非常好,只要你能让守护程序在Web主机上运行。
- Zend Lucene需要一个cron作业来重新索引数据库。虽然对用户而言相当透明,但这意味着任何新数据(或删除的数据!)不一定与您的数据库中的数据同步,因此不会立即显示在用户搜索中。
- MySQL FULLTEXT搜索很快,但无法提供前两者的所有功能和灵活性。
如果我遗漏/错过了什么,请随时评论。