让 MySQL 真正支持中文的全文检索(全文索引)
时间:2006-09-22 来源:catsup
PHP 和 MySQL 几乎也是离不开的, 后面我附一个简单的例子来说明在 PHP 中使用全文检索....
下载及完全说明正式地址: http://myft.twomice.net
在不影响 MySQL 的系统结构及其他功能的前提下,解决了 MySQL 目前对中文全文检索无法正确支持的缺陷并优化 MySQL 对中文检索处理的性能。(目前本软件包支持根据词典进行简易的正向最大匹配分词、支持包括UTF-8、GBK、BIG5 ... 在内的字符集)
经测试效果尚可, 140万行约 1.4G 数据(不含索引区空间) 检索大概都在 0.0x ~ 0.x 秒之间. 搭配做一个小型全文检索将变得十分简单.
MySQL 从 3.23 的某个小版本开始就已经支持在 MyISAM 表中建立全文索引的字段。由于 CJK(中日韩)字符集及其句法的特殊性(词与词之间没有像英文一样的间隔),MySQL 一直没有针对多字节的宽字符集作出应有的支持,也没有任何分词能力。
而 MySQL 作为 PHP 等 Web Script 的绝佳搭档,已经被广泛应用到各个角落,对于它的检索令绝大多数开发者头痛,用 SELECT ... WHERE ... LIKE %...% 的方式不仅效率差(动则扫描全表岂能不慢?),对于中文这样的特殊语言也存在严重的岐义问题(因为词才是最小的语意单位)。我也在一段时间内受限于 MySQL 的检索限制,而不得不寻求其它解决方案,但都不太尽人意。
--
顺便提一下,有一个叫作海量的分词技术公司,很早就做过 mysql-chinese 的 hack,只不过迟迟没有按照 GNU 精神及时发布源码,所以才决定自己来作。
-- 用 PHP 配合 MySQL (4.0.x) 的全文检索例子代码 --
[Copy to clipboard] CODE: <?php
if ($_GET['q'] && $q = trim($_GET['q']))
{
mysql_connect();
mysql_select_db("dot66");
$q = mysql_escape_string($q);
$r = mysql_query("SELECT SEGMENT('$q')");
$n = mysql_fetch_row($r);
$x = explode(" ", $n[0]);
$m = $str = '';
$f = $t = array();
foreach ($x as $tmp)
{
if (strlen($tmp) > strlen($m)) $m = $tmp;
$f[] = "/($tmp)/i";
$t[] = '<font color=red>\1</font>';
}
$s1 = "SELECT id,board,owner,chrono,title,SUBSTRING(body,LOCATE('$m', body)-50,200) AS xbody ";
$s2 = "FROM bbs_posts WHERE MATCH(title,body) AGAINST ('$q'";
$s2 .= (preg_match('/[<>\(\)~\*"+-]/', $q) ? ' IN BOOLEAN MODE' : '');
$s2 .= ") LIMIT 100";
$r = mysql_query("SELECT COUNT(*) $s2");
$x = mysql_fetch_row($r);
$x = $x[0];
$s = $s1 . $s2;
echo '<div style="border:1px solid red;background-color:#e0e0e0;font-family:tahoma;padding:8px;"><b>The Core SQL Query String:</b><br>' . $s . '</div><br>';
$r = mysql_query($s);
while ($tmp = mysql_fetch_assoc($r))
{
if (($pos = strpos($tmp['owner'], '.')) || ($pos = strpos($tmp['owner'], '@')))
$tmp['owner'] = substr($tmp['owner'],0,$pos).'.';
$str .= "<li><a href=\"?id=$tmp[id]\" onclick=\"return false;\" style=\"text-decoration:underline;color:blue\" title=\"点击浏览...\">$tmp[title]</a> <small><font color=green>(看板: $tmp[board])</font></small><br>\n";
$str .= "<small> ... $tmp[xbody] ...</small><br>\n";
$str .= "<small style=\"color:green;font-family:tahoma;\">Author: <u>$tmp[owner]</u> Date: " . date("Y-m-d H:i", $tmp['chrono']) . "</small>\n";
$str .= "</li><br><br>\n";
}
$f[] = '/\x1b\[.*?m/';
$t[] = '';
$str = preg_replace($f, $t, $str);
}
mysql_close();
}
?>
<title>BBS(看板检索: powered by MySQL fulltext+)</title>
<style type="text/css">
body { line- }
</style>
<h2>BBS(看板检索: powered by MySQL fulltext+)</h2>
<form method=get style="margin:0">
<input type=text name=q size=30 value="<?php echo $_GET['q'];?>">
<input type=submit value="Search!">
<small>
(随便输入字符串检索, 还可以用简单的 +/- 哦, 收录约有 140万篇文章)
</small>
</form>
<ol>
<?php echo $str; ?>
</ol>
下载及完全说明正式地址: http://myft.twomice.net
在不影响 MySQL 的系统结构及其他功能的前提下,解决了 MySQL 目前对中文全文检索无法正确支持的缺陷并优化 MySQL 对中文检索处理的性能。(目前本软件包支持根据词典进行简易的正向最大匹配分词、支持包括UTF-8、GBK、BIG5 ... 在内的字符集)
经测试效果尚可, 140万行约 1.4G 数据(不含索引区空间) 检索大概都在 0.0x ~ 0.x 秒之间. 搭配做一个小型全文检索将变得十分简单.
MySQL 从 3.23 的某个小版本开始就已经支持在 MyISAM 表中建立全文索引的字段。由于 CJK(中日韩)字符集及其句法的特殊性(词与词之间没有像英文一样的间隔),MySQL 一直没有针对多字节的宽字符集作出应有的支持,也没有任何分词能力。
而 MySQL 作为 PHP 等 Web Script 的绝佳搭档,已经被广泛应用到各个角落,对于它的检索令绝大多数开发者头痛,用 SELECT ... WHERE ... LIKE %...% 的方式不仅效率差(动则扫描全表岂能不慢?),对于中文这样的特殊语言也存在严重的岐义问题(因为词才是最小的语意单位)。我也在一段时间内受限于 MySQL 的检索限制,而不得不寻求其它解决方案,但都不太尽人意。
--
顺便提一下,有一个叫作海量的分词技术公司,很早就做过 mysql-chinese 的 hack,只不过迟迟没有按照 GNU 精神及时发布源码,所以才决定自己来作。
-- 用 PHP 配合 MySQL (4.0.x) 的全文检索例子代码 --
[Copy to clipboard] CODE: <?php
if ($_GET['q'] && $q = trim($_GET['q']))
{
mysql_connect();
mysql_select_db("dot66");
$q = mysql_escape_string($q);
$r = mysql_query("SELECT SEGMENT('$q')");
$n = mysql_fetch_row($r);
$x = explode(" ", $n[0]);
$m = $str = '';
$f = $t = array();
foreach ($x as $tmp)
{
if (strlen($tmp) > strlen($m)) $m = $tmp;
$f[] = "/($tmp)/i";
$t[] = '<font color=red>\1</font>';
}
$s1 = "SELECT id,board,owner,chrono,title,SUBSTRING(body,LOCATE('$m', body)-50,200) AS xbody ";
$s2 = "FROM bbs_posts WHERE MATCH(title,body) AGAINST ('$q'";
$s2 .= (preg_match('/[<>\(\)~\*"+-]/', $q) ? ' IN BOOLEAN MODE' : '');
$s2 .= ") LIMIT 100";
$r = mysql_query("SELECT COUNT(*) $s2");
$x = mysql_fetch_row($r);
$x = $x[0];
$s = $s1 . $s2;
echo '<div style="border:1px solid red;background-color:#e0e0e0;font-family:tahoma;padding:8px;"><b>The Core SQL Query String:</b><br>' . $s . '</div><br>';
$r = mysql_query($s);
while ($tmp = mysql_fetch_assoc($r))
{
if (($pos = strpos($tmp['owner'], '.')) || ($pos = strpos($tmp['owner'], '@')))
$tmp['owner'] = substr($tmp['owner'],0,$pos).'.';
$str .= "<li><a href=\"?id=$tmp[id]\" onclick=\"return false;\" style=\"text-decoration:underline;color:blue\" title=\"点击浏览...\">$tmp[title]</a> <small><font color=green>(看板: $tmp[board])</font></small><br>\n";
$str .= "<small> ... $tmp[xbody] ...</small><br>\n";
$str .= "<small style=\"color:green;font-family:tahoma;\">Author: <u>$tmp[owner]</u> Date: " . date("Y-m-d H:i", $tmp['chrono']) . "</small>\n";
$str .= "</li><br><br>\n";
}
$f[] = '/\x1b\[.*?m/';
$t[] = '';
$str = preg_replace($f, $t, $str);
}
mysql_close();
}
?>
<title>BBS(看板检索: powered by MySQL fulltext+)</title>
<style type="text/css">
body { line- }
</style>
<h2>BBS(看板检索: powered by MySQL fulltext+)</h2>
<form method=get style="margin:0">
<input type=text name=q size=30 value="<?php echo $_GET['q'];?>">
<input type=submit value="Search!">
<small>
(随便输入字符串检索, 还可以用简单的 +/- 哦, 收录约有 140万篇文章)
</small>
</form>
<ol>
<?php echo $str; ?>
</ol>
相关阅读 更多 +