storytlr 支持搜索标题和内容

storytlr 搜索很奇怪,比如我有一篇文章,标题为“QQ for Linux 新版本终于发布了”,内容为“发布了发布了等等等。。。。。很多字符哈哈哈”,我在搜索框里搜索以下内容可以搜到这篇文章:“Linux”、“QQ for Linux”、“新版本终于发布了”,但是搜索以下内容搜不到这篇文章:“Linu”、“QQ for”、“版本”、“新版本终于发布”。这就奇怪了,于是查看代码,在源文件

./protected/application/admin/models/Data.php

的 236 行可以看到,采用的搜索方式是 MATCH,并不是 LIKE,之前没见过 MATCH,于是查看 MySQL 官网,点击这里这里

Any word that is too short is ignored. The default minimum length of words that are found by full-text searches is four characters.

也就是说会省略小于等于 4 个字符的词会省略,所以搜索“QQ for” 搜索不到。

The FULLTEXT parser determines where words start and end by looking for certain delimiter characters; for example, “ ” (space), “,” (comma), and “.” (period). If words are not separated by delimiters (as in, for example, Chinese), the FULLTEXT parser cannot determine where a word begins or ends.

中文词与词之间没有像英文那样有个空格隔开,所以 “新版本终于发布” 和 “新版本终于发布了” 并没有匹配,它认为是两个不同的词。

找到问题所在了。为了满足我的要求,我改代码为使用 LIKE 进行搜索,并且,它默认只搜索标题,不搜索内容,我对 SQL 语句作了如下改动。

Data.php 文件的 234 到 242 行内容为:

$sql = "SELECT d.id, d.source_id, d.service, UNIX_TIMESTAMP(d.timestamp) as timestamp, d.is_hidden, d.user_id, d.comment_count, d.mention_count, d.tag_count, d.slug "
		. "FROM {$service}_data t LEFT JOIN data d ON (t.id = d.id AND t.source_id = d.source_id) "
		. "WHERE MATCH($index) AGAINST(:term) AND t.source_id= :source_id "
		. ((!$show_hidden) ? "AND is_hidden = 0 " : " ")
		. "ORDER BY timestamp DESC ";

$data = array(":term" => $term, ":source_id" => $source_id);

$stmt   = $this->_db->query($sql, $data);

更改为:

$sql = "SELECT d.id, d.source_id, d.service, UNIX_TIMESTAMP(d.timestamp) as timestamp, d.is_hidden, d.user_id, d.comment_count, d.mention_count, d.tag_count, d.slug "
		. "FROM {$service}_data t LEFT JOIN data d ON (t.id = d.id AND t.source_id = d.source_id) "
		. "WHERE (title LIKE '%{$term}%' "
		// 下面这行代码是为了搜索 content 字段,有些表没有 content 字段,所以先进行一个判断
		. (($service == 'rss') ? "OR content LIKE '%{$term}%' " : "")
		. ") AND t.source_id= {$source_id} "
		. ((!$show_hidden) ? "AND is_hidden = 0 " : " ")
		. "ORDER BY timestamp DESC ";
$stmt   = $this->_db->query($sql);

我无视了 search 函数的 $index 参数,直接在 SQL 语句里用 title 替代了。

暂时一切运行正常。可以正常搜索,可以搜索文章标题和内容。

对于 MATCH AGAINST ,如果我理解有误,请看官指点。如果有更好的解决方法,请告之~