关键词匹配项目深入研究(二)- 分表思想的引入
(二)分表思想的引入
近期的文章: 1)高并发数据采集的架构应用(redis的应用)
2)高可用数据采集平台(如何玩转3门语言php+.net+aauto)
手把手教你做关键词匹配项目这块基本已经完成,深入研究是对系统的性能作为分析,在一些环境的刺激下所必需要做的一些改变。
手把手教你做关键词匹配项目: 手把手教你做关键词匹配项目(搜索引擎)---- 第一天~手把手教你做关键词匹配项目(搜索引擎)---- 第二十二天 (共22篇)
深入研究:上节讲到 关键词匹配项目深入研究-过滤器的引入。
每一篇会分为问题的前因、解决方案以及有些必要的实现方案。
本篇正文正式开始。
问题的前因
随着自动采集数据的爆炸式的增长,词库的容量蒸蒸日上,一下从几w数据猛增几百万数据,小帅帅看着数据库的查询越来越感到无能为力。
再加上小丁丁常对小帅帅说的最多的一句:何时那么选词能快一点,每次我都等好久都莫有反应,真是急死我了。
小帅帅也比较焦急,心力憔悴,真正的感觉到原来这就是挑战。小帅帅无可奈何的继续找到于老大,求于老大赏赐高招。
于老大拍拍小帅帅的肩膀:小伙子,知道项目的难度了吧!
小帅帅回答道:别挖苦我了,我已深深的感受到了,我想我心脏估计快承受不了了。
于老大:就这点你就承受不了,那估计以后有的是给你受的。
小帅帅:大哥,别说这些虚的行不,赶紧的解决方案丫。
于老大:急啥,事情是急不来的,过来,哥给你指条明路。
“每个宝贝是不是有类别的属性,那么这几百万数据真正属于这个类别的词能够有多少?假设我们只取这个类别的词库我们的项目是否可以继续稳定下来”。
解决方案
按照某种业务需要,我们可以对数据表实行分割,可以纵向或者横向分割,可以有效的进行性能优化。
纵向分割也称列分割,把不常用的列或者长字段分割来保证实体处于一个相对适用的状态,常见的有一对一关联。
横向分割也称行分割,按照某种业务拆分数据的记录来存放在不同的表,常见的有按日期分表操作。
本案例是使用横向分割,把数据按照类别的形式进行拆分。
实现方案
我们为了不更改数据表的结构,这样设计了,我们按照表名来区分项目使用那个数据表。这样一来的改动相对是非常少的。我们只需稍微改动下代码就可以解决了,这很心塞的一件事情。
修改keyword的代码,增加获取数据源。
phpdefine('database_host','127.0.0.1');define('database_user','xiaoshuaishuai');define('database__password','xiaoshuaishuai');define('database_charset','utf-8');class keyword { public $word; public static $conn = null; public function getdbconn(){ if(self::$conn == null){ self::$conn = mysql_connect(database_host,database_user,database__password); mysql_query(set names '.database_charset.',self::$conn); mysql_select_db(dict,self::$conn); return self::$conn; } return self::$conn; } public function save(){ $sql = insert into keywords(word) values ('$this->word'); return mysql_query($sql,$this->getdbconn()); } public static function getwordssource($cid,$limit=0,$offset=40){ $sql = select * from keywords_$cid limit $limit,$ffset; return db::makearray($sql); } public static function getwordscount($cid){ $sql = select count(*) from keywords_$cid; return db::queryscalar($sql); }}
db类新增queryscalar,用于算总量
php#@author oshinedefine('database_host','127.0.0.1');define('database_user','xiaoshuaishuai');define('database__password','xiaoshuaishuai');define('database_charset','utf-8');class db { public static $conn = null; public static function connect(){ if(self::$conn == null){ self::$conn = mysql_connect(database_host,database_user,database__password); mysql_query(set names '.database_charset.',self::$conn); mysql_select_db(dict,self::$conn); return self::$conn; } return self::$conn; } public static function query($sql){ return mysql_query($sql,self::connect()); } public static function makearray($sql){ $rs = self::query($sql); $result = array(); while($data = mysql_fetch_assoc($rs)){ $result[] = $data; } return $result; } public static function queryscalar($sql){ $rs = self::query($sql); $data = mysql_fetch_array($rs); if($data == false || empty($data) || !isset($data[1])) return 0; return $data[1]; }}
修改selector的代码,用于选词:
php#@filename:selector/selector.php#@author:oshinerequire_once dirname(__file__) . '/selectoritem.php';require_once dirname(__file__) . '/charlist/charlist.php';require_once dirname(__file__) . '/charlist/charlisthandle.php';require_once dirname(dirname(__file__)) . '/lib/logger.php';class selector{ private static $charlisthandle = array( 黑名单 => backlistcharlisthandle, 近义词 => linklistcharlisthandle ); public static function select($num_iid) { $selectoritem = selectoritem::createfromapi($num_iid); logger::trace($selectoritem->props_name); $charlist = new charlist(); foreach (self::$charlisthandle as $matchkey => $classname) { $handle = self::createcharlisthandle($classname, $charlist, $selectoritem); $handle->exec(); } $selectwords = array(); $wordscount = keyword::getwordscount(selectoritem->cid); $offset = 40; $page = ceil($wordscount/$offset); for($i=0;$i$page;$i++){ $limit = $i*$offset; $keywords = keyword::getwordssource(selectoritem->cid,$limit,$offset); foreach ($keywords as $val) { # code... $keywordentity = splitterapp::split($val[word]); # code... if(macthexector::macth($keywordentity,$charlist)){ $selectwords[] = $val[word]; } } } return $selectwords; } public static function createcharlisthandle($classname, $charlist, $selectoritem) { if (class_exists($classname)) { return new $classname($charlist, $selectoritem); } throw new exception(class not exists, 0); }}
总结
小帅帅又学到了新的知识点,这是要犒劳于老大的节奏吗?你们是否也要犒劳下我呢,求赞哈!