PHP+SQLite全文搜索(3)
PHP+SQLite全文搜索(3)
可以看到注释掉的信息,是mb_函数部分,我去掉他们,一方面是为了迁移,一方面是mb_很慢。我偷懒地使用了不完整的UTF8切字,只判断2个字节的和3个字节的,其实只有UTF3,呵呵……以后再说。
<?php
function _normalize_text ($text)
{
$symbol = '`~!@#$%^&*()_+=|{}[]:;"<>,.?';
$symbol = preg_quote ($symbol);
$ret = preg_replace ("/[$symbol]/", ' ', $text);
$ret = preg_replace ("/[rnt]/", ' ', $ret);
// For Chinese...
$ret = str_replace ('“', ' ', $ret);
$ret = str_replace ('”', ' ', $ret);
$ret = str_replace ('‘', ' ', $ret);
$ret = str_replace ('’', ' ', $ret);
$ret = str_replace ('!', ' ', $ret);
$ret = str_replace ('?', ' ', $ret);
$ret = str_replace ('。', ' ', $ret);
$ret = str_replace (',', ' ', $ret);
$ret = str_replace ('、', ' ', $ret);
$ret = str_replace ('·', ' ', $ret);
$ret = str_replace ('(', ' ', $ret);
$ret = str_replace (')', ' ', $ret);
$ret = str_replace ('#', ' ', $ret);
$ret = str_replace ('《', ' ', $ret);
$ret = str_replace ('》', ' ', $ret);
$ret = str_replace (';', ' ', $ret);
$ret = str_replace (':', ' ', $ret);
$ret = str_replace ('……', ' ', $ret);
$ret = str_replace (' ', ' ', $ret);
$ret = str_replace ('——', ' ', $ret);
// Cut Words...
$ret = str_replace ('的', '的 ', $ret);
$ret = str_replace ('是', '是 ', $ret);
$ret = str_replace ('吗', '吗 ', $ret);
$ret = str_replace ('吧', '吧 ', $ret);
$ret = str_replace ('呀', '呀 ', $ret);
$ret = preg_replace ("/s+/", ' ', $ret);
return (trim ($ret) . ' ');
}
?>
上面这个函数对文字做了一些简单的预处理,扔掉了一些标点符号,主要就是为了把文章先分割成“句子”,实验性函数……
我的词典是保存在内存中的,依靠memcached来维护,每一个词保存的就是一个名字为word_key,值为“t”的内存变量。memcached对这个词典进行了有效的散列。下面是词典class:
<?php
class BsmSearchDictMemcached
{
var $mc;
function BsmSearchDictMemcached ()
{
global $dict_memcached_host, $dict_memcached_port;
$this->mc = memcache ();
$this->mc->add_server ($dict_memcached_host, $dict_memcached_port);
return $this->mc;
}
function make_mem_dict ()
{
global $dict_source_file;
$fp = fopen ($dict_source_file, 'rb');
while ($word = fgets ($fp)) {
$word = trim ($word);
$key = $this->_gen_mem_key ($word);
$this->mc->set ($key, 't');
}
fclose ($fp);
}
function find ($word)
{
$key = $this->_gen_mem_key ($word);
if ($this->mc->get ($key) == 't')
return true;
else
return false;
}
function _gen_mem_key ($word)
{
if ($word) {
$md5_word = md5 ($word);
$key = substr ($md5_word, 0, 4) . substr ($md5_word, 16, 8);
$key = 'dict_' . $key;
}
else
$key = 'NO_KEY';
return $key;
}
}
?>
一些参数是在BSM的配置文件中定义的,make_mem_dict是生成内存词典的方法,它从原始词典dict.dat中导出数据插入到内存中。
一个使用实例:
<?php
define ('IN_BSM', true);
$phpEx = 'php';
error_reporting (2047);
require ('../include/kernel/common.inc.' . $phpEx);
require ($include_root . 'search/search.inc.' . $phpEx);
$search = new BsmSearch ('search/');
$str = '我是大傻瓜';
$start_time = array_sum (explode (' ', microtime()));
$db->sql_query ("INSERT INTO `data` SET `text` = '$str');
$id = $db->sql_nextid ();
$search->add_text ($id, $str);
print_r ($search->search ('傻瓜'));
$end_time = array_sum (explode (' ', microtime()));
$time = $end_time - $start_time;
echo ('<br>Spend Time: ' . $time . ' secs');
?>
它在数据库里插入一篇内容叫“我是大傻瓜”的文章,同时创建了索引,然后搜索“傻瓜”这个词,结果会返回刚刚那个ID,如果之前还插入过包含“傻瓜”的文章,会一起返回。
BsmSearch基本算是写了个框框,还有很多没有实现,我不着急,慢慢做。