1. 要求
- 對文章內(nèi)容進(jìn)行關(guān)鍵詞檢索独柑,找到符合的關(guān)鍵詞的文章
- 對數(shù)據(jù)庫表優(yōu)化(針對大型項(xiàng)目)喇勋,進(jìn)行分表讀寫數(shù)據(jù)(本次創(chuàng)建32個表)
2. 思路
- 創(chuàng)建32張數(shù)據(jù)表(art0-31)罗珍,包含字段(art_id,guid秀鞭,cat_id,title,content,pubtime),根據(jù)需要自己可以添加
- 創(chuàng)建索引表(index_art)榕茧,包含字段(guid,id诽偷,content)這塊可以把數(shù)據(jù)表名稱也加上坤学,好定位到那張表,根據(jù)需要可以添加报慕,這里要把content創(chuàng)建全文索引
- 這里如何讓索引表和數(shù)據(jù)表進(jìn)行關(guān)聯(lián)深浮,因?yàn)槊總€數(shù)據(jù)表都有自增長art_id,都是從1開始眠冈,無法和索引表進(jìn)行關(guān)聯(lián)飞苇,所以需要引入uuid,即每個文章都有一個自己uuid,索引表也對應(yīng)文章的uuid
- 創(chuàng)建了32張數(shù)據(jù)表布卡,那么如何實(shí)現(xiàn)減輕數(shù)據(jù)庫壓力呢雨让,怎么把數(shù)據(jù)隨機(jī)插入到表中,這里使用了對uuid的處理羽利,即先對uuid進(jìn)行md5加密處理轉(zhuǎn)行成16進(jìn)制宫患,然后利用substr提取前兩位字符,再用hexdec函數(shù)將其轉(zhuǎn)換成10機(jī)制这弧,讓最后結(jié)果和32取余數(shù)娃闲,余數(shù)和art拼接就是插入的表名
- 當(dāng)插入數(shù)據(jù)時,還要同時插入到索引表中(最好用數(shù)據(jù)庫事務(wù)處理)匾浪,因?yàn)槲恼聝?nèi)容可能是中文皇帮,英文或者混合,這里需要判斷下蛋辈,如果是含有中文就需要對中文進(jìn)行處理属拾,通過中文分詞字典,分出詞語冷溶,并用空格分開渐白,英文的話直接插入(自帶空格)
- 當(dāng)讀取修改刪除數(shù)據(jù)時,都要用到uuid逞频,所以就不能用自增長id了(跳轉(zhuǎn)頁面時的參數(shù))纯衍。
- 當(dāng)提交檢索時,也要對語句進(jìn)行判斷處理苗胀,然后用全文索引語句襟诸,在index_art索引表中搜索,存在數(shù)據(jù)基协,取得uuid歌亲,然后利用uuid找到對應(yīng)的表,取得數(shù)據(jù)
代碼
- 數(shù)據(jù)表結(jié)構(gòu):
//artadd.php
//獲取guid
$uuid4 = Uuid::uuid4();
$index['guid']=$art['guid']=$uuid4->toString();
//獲取uuid澜驮,md5加密之后再獲取前兩位數(shù)字陷揪,最后轉(zhuǎn)換成10進(jìn)制,
$num=hexdec(substr(md5($uuid4->toString()),0,2));
$yu=$num%32;
$table='art'.$yu;
~
~
//當(dāng)插入成功后杂穷,在索引表中添加數(shù)據(jù)
//檢查內(nèi)容是什么類型(1->英文鹅龄,2->中文)
$cont=isWhat($art['content']);//自己封裝的函數(shù)
if($cont==1){
$index['content']=$art['content'];
}elseif($cont==2){
//利用fenci中文字典更改內(nèi)容
//實(shí)例化字典
$se=new segment();
//調(diào)用方法
$index['content'] = $se->get_keyword($art['content']);
}else{
//利用fenci中文字典更改內(nèi)容
//實(shí)例化字典
$se=new segment();
//調(diào)用方法
$index['content'] = $se->get_keyword($art['content']);
$words=split_en_str($art['content'],false);
$index['content'].=" ".implode(' ',$words);
}
//插入index_art索引表中
inUp('index_art',$index,'insert');//自己封裝的插入函數(shù)
- 修改數(shù)據(jù)(刪除比較簡單就不寫了)
//artedit.php
//獲取到需要改的數(shù)據(jù)
$num=hexdec(substr(md5($_GET['id']),0,2));
$yu=$num%32;
$table='art'.$yu;
$sql="select guid,title,tags,content,cat_id from ".$table." where guid='".$_GET['id']."'";
$art=find($sql);
~
~
//當(dāng)有post提交時
$num=hexdec(substr(md5($_POST['guid']),0,2));
$yu=$num%32;
$table='art'.$yu;
//更新成功后把索引文件中的content字段進(jìn)行更新
//檢查內(nèi)容是什么類型(1->英文,2->中文)
$cont=isWhat($art['content']);
if($cont==1){
$index['content']=$art['content'];
}elseif($cont==2){
//利用fenci中文字典更改內(nèi)容
//實(shí)例化字典
$se=new segment();
//調(diào)用方法
$index['content'] = $se->get_keyword($art['content']);
}else{
//利用fenci中文字典更改內(nèi)容
//實(shí)例化字典
$se=new segment();
//調(diào)用方法
$index['content'] = $se->get_keyword($art['content']);
$words=split_en_str($art['content'],false);
$index['content'].=" ".implode(' ',$words);
}
//插入index_art索引表中
inUp('index_art',$index,'update',"guid='".$_POST['guid']."'");
查數(shù)據(jù)
//artlist.php
//分頁操作
$num='';
for($i=0;$i<32;$i++){
$sql="select count(*) from art".$i;
$num+=find($sql)['count(*)'];
}
$cnt=10;
$curr=isset($_GET['page'])? $_GET['page'] : '1';
//調(diào)用分頁函數(shù)亭畜,進(jìn)行分頁
$page=getPage($num,$cnt,$curr);//自己封裝的函數(shù)
//獲取art表的所有文章
$rs=[];
for($i=0;$i<32;$i++){
$sql="select title,guid,art_id,pubtime,catname from art".$i." left join cat on cat.cat_id=art".$i.".cat_id";
//echo $sql.'<br>';
$a=getAll($sql);
foreach($a as $v){
$rs[]=$v;
}
}
$rs=array_slice($rs,($curr-1)*$cnt,$cnt);//html頁面去遍歷$rs
~
~
//artlist.html
//遍歷文章
<?php foreach($rs as $k=>$v){?>
<tr>
<td><?php echo ($k+1);?></td>
<td><?php echo date('Y-m-d',$v['pubtime'])?></td>
<td><a href="#"><?php echo $v['title']?></a></td>
<td><?php echo $v['catname']?></td>
<td>
<a href="./artdel.php?id=<?php echo $v['guid']?>">刪除</a>|
<a href="./artedit.php?id=<?php echo $v['guid']?>">修改</a>
</td>
</tr>
<?php } ?>
//分頁
<?php if(isset($page)){ ?>
<div id="pagebar" align='center' style='font-size:20px'>
共<?php echo $num;?>條
<?php foreach($page as $k=>$v){
if($k==$curr){
?>
<span>[<?php echo $k;?>]</span>
<?php }else{?>
<a href='artlist.php?<?php echo $v; ?>'><?php echo $k; ?></a>
<?php }
}
?>
</div>
<?php }?>
當(dāng)提交查詢時
//index.php
//檢查內(nèi)容是什么類型(1->英文扮休,2->中文)
$cont=isWhat($_POST['search']);//自己封裝函數(shù)
if($cont==1){
$search=$_POST['search'];
}elseif($cont==2){
//利用fenci中文字典更改內(nèi)容
//實(shí)例化字典
$se=new segment();
//調(diào)用方法
$search = $se->get_keyword($_POST['search']);
}else{
//利用fenci中文字典更改內(nèi)容
//實(shí)例化字典
$se=new segment();
//調(diào)用方法
$search = $se->get_keyword($_POST['search']);
$words=split_en_str($_POST['search'],false);
$search.=" ".implode(' ',$words);
}
//利用全文索引的語句查詢
$sql="select guid from index_art where MATCH(content) AGAINST('".$search."' IN BOOLEAN MODE)";
$rs=getAll($sql);
$art=[];
if(!empty($rs)){
foreach($rs as $v){
$num=hexdec(substr(md5($v['guid']),0,2));
$yu=$num%32;
$table='art'.$yu;
$sql="select guid,pubtime,title,content,catname from ".$table." inner join cat on $table.cat_id=cat.cat_id where guid='".$v['guid']."'";
//獲取到當(dāng)前guid的值
$one=find($sql);
//將關(guān)鍵字分割為數(shù)組
$key_word=explode(' ',$search);
//獲取關(guān)鍵詞出現(xiàn)的次數(shù)
$sql="select content from index_art where guid='".$v['guid']."'";
//var_dump(find($sql));die;
$content=find($sql)['content'];
$n='';
foreach($key_word as $v1){
$n+=substr_count($content,$v1);
//將數(shù)據(jù)中的關(guān)鍵詞高亮顯示
$one['content']=preg_replace("/($v1)/i","<font color=red><b>\\1</b></font>",$one['content']);
}
$one['num']=$n;
//將num插入到$one中
$art[]=$one;
//利用冒泡法根據(jù)num排序
bubble_sort($art);
}
//頁面去遍歷$art
}
使用到封裝的函數(shù)
/**
*
*分頁函數(shù)
*當(dāng)$max>=5默認(rèn)顯示5個條頁碼,<5正常顯示
*@param int $num文章數(shù)
*@param int $cnt每頁顯示條數(shù)
*@param int $curr當(dāng)前頁
*@return array 返回拼接的每頁的url參數(shù)
*/
function getPage($num,$cnt,$curr){
//獲取最大頁碼
$max=ceil($num/$cnt);
//判斷顯示頁碼的最左邊的位置
$left=max($curr-2,1);
//最右邊頁碼
$right=min($left+4,$max);
//存在一種情況是拴鸵,當(dāng)共9頁玷坠,當(dāng)前處于8頁蜗搔,頁面只會顯示4個分頁,所以需要根據(jù)$right重新定義下left
$left=max($right-4,1);
//將獲取到的頁碼放到數(shù)組中返回八堡,因?yàn)閷τ趇ndex頁面樟凄,存在兩個查詢,一個時根據(jù)欄目查詢(有參數(shù)cat_id)兄渺,一個查詢吃總的欄目缝龄,所以需要用http_build_query()函數(shù)來保留原有的參數(shù)
for($i=$left;$i<=$right;$i++){
$_GET['page']=$i;//模擬url輸出格式是?page=$i,與原有的參數(shù)拼接
$page[$i]=http_build_query($_GET);
}
return $page;
}
/**
*
*判斷字符串時全英文挂谍,全中文叔壤,或者都有
*@param string $str1 需要檢查的字符串
*@return int 英文->1 中文->2 混合->3
*/
function isWhat($str1){
$strA= trim($str1);
$lenA= strlen($strA); //檢測字符串實(shí)際長度
$lenB= mb_strlen($strA, "utf-8"); //文件的編碼方式要是UTF8
if($lenA=== $lenB) {
return"1";//全英文
}else {
if($lenA% $lenB== 0) {
return"2";//全中文
}else {
return"3";//中英混合
}
}
}
/**
*
*匹配英文單詞
*@param string $str 需要匹配的字符
*@param bool $distinct 是否去除重復(fù)值
*@return array 返回所有單詞的索引數(shù)組
*/
function split_en_str($str,$distinct=true) {
preg_match_all('/([a-zA-Z]+)/',$str,$match);
if ($distinct == true) {
$match[1] = array_unique($match[1]);
}
sort($match[1]);
return $match[1];
}
/**
*
*冒泡法排序
*
*
*/
function bubble_sort(& $arr){
$number=count($arr);
for($i=0;$i<$number-1;$i++){
for($j=0;$j<$number-1-$i;$j++){
if($arr[$j]['num']<$arr[$j+1]['num']){
$tmp=$arr[$j];
$arr[$j]=$arr[$j+1];
$arr[$j+1]=$tmp;
}
}
return $arr;
}
}