2015年5月12日 20:16:48 星期二
效果:
原理:
1. 建立"单字"索引(倒排索引): 将汉字拆分成单个字, 作为redis hash 的一个键, 将所有包含该字的id作为hash的值
2. 每次输入一个字, 就去redis里将该字的所有id取出来, 输入第二个字的时候, 取出第二个字的所有id与第一个字的id求交集
求得同时包含这两个字的所有id, 再进一步获取id对应的信息并返回
另外:
1. 文中还建立了两个全词索引(redis hash), 一个是 {"完整汉字词语" : "id", .....} 另一个是 {"id" : "完整汉字词语" ,.......} 方便后续程序使用, 与这个自动补全关系不大
2. 小细节, 每次点选词语的时候, js自动补上"," 而且ajax请求数据的时候, 只把最后一个","后边的用户输入词语发送给服务端
话不多说, 上代码:
js+css
1 150 151
html (只用在原有的表单上加一个id, 并在下方添加一个隐藏的div, id/class如下)
1 没找到? 点这里试试2
php (php+redis:hash)
1 //创建索引 2 public function dobuildTeamAutoComplete() 3 { 4 $oneWordIndex = 'autocomplete_zi'; //单字索引 5 $allWordIndexByName = 'autocomplete_ci_name'; //全词索引, 键为全名(火箭:team_1_2) 6 $allWordIndexById = 'autocomplete_ci_id'; //全词索引, 键名为id(team_1_2:火箭) 7 8 $type = 'team_'; 9 10 //删除之前所有的旧值11 $this->redis->del($oneWordIndex);12 13 //重新构建14 $team = $this->redis->hgetall('LeagueTeamsNames');15 16 $oneWordInfo = array();17 $allWordInfoName = array();18 foreach ($team as $lid => $jsonTeam) {19 if ($lid != 8 && $lid != 12) {20 $arrTeam = json_decode($jsonTeam, true);21 foreach ($arrTeam as $name => $tid) {22 $value = $type.$tid.'_'.$lid;23 $allWordInfo[$name] = $value;24 $length = mb_strlen($name, 'UTF-8');25 for ($i=0; $i < $length; $i++) {26 $strOne = mb_substr($name, $i, 1, 'UTF-8');27 $oneWordInfo[$strOne][$value] = $value; //懒得去重了28 }29 }30 }31 }32 $oneWordInfoRedis = array();33 foreach ($oneWordInfo as $word => $ids) {34 $a = array_values($ids);35 $oneWordInfoRedis[$word] = json_encode($a);36 }37 38 //索引写入redis 39 $this->redis->hmset($oneWordIndex, $oneWordInfoRedis);40 $this->redis->hmset($allWordIndexByName, $allWordInfo);41 $this->redis->hmset($allWordIndexById, array_flip($allWordInfo));42 43 exit('over');44 }45 46 //自动补全请求处理函数47 public function dogetAutoComplete()48 {49 $oneWordIndex = 'autocomplete_zi'; //单字索引50 $allWordIndexById = 'autocomplete_ci_id'; //全词索引, 键名为id(team_1_2:火箭)51 52 $word = common::request('word', 'G');53 54 if (empty($word)) {55 exit('0');56 }57 $intWordLength = mb_strlen($word, 'UTF-8');58 59 $arrId = array();60 if (1 == $intWordLength) {61 $jsonId = $this->redisSlave->hget($oneWordIndex, $word);62 $arrId = json_decode($jsonId, true);63 } else {64 for ($i=0; $i < $intWordLength; $i++) {65 $strOne = mb_substr($word, $i, 1, 'UTF-8');66 $jsonIdTmp = $this->redisSlave->hget($oneWordIndex, $strOne);67 $arrIdTmp = json_decode($jsonIdTmp, true);68 69 $arrIdTmp = $arrIdTmp ? $arrIdTmp : array();70 $arrId = empty($arrId) ? $arrIdTmp : $arrId;71 $b = array_intersect($arrId, $arrIdTmp);72 $arrId = empty($b) ? $arrId : $b; // 新输入的词如果跟之前的没有交集, 就维持原来的交集不变73 }74 }75 $arrId = empty($arrId) ? array() : $arrId;76 77 //获取球队信息78 $arrInfo = array();79 foreach ($arrId as $v) {80 $arrInfo[$v] = $this->redisSlave->hget($allWordIndexById, $v);81 }82 83 $jsonInfo = json_encode($arrInfo);84 exit($jsonInfo);85 }