1. 要求
- 對文章內容進行關鍵詞檢索,找到符合的關鍵詞的文章
- 對數據庫表優化(針對大型項目),進行分表讀寫數據(本次創建32個表)
2. 思路
- 創建32張數據表(art0-31),包含字段(art_id,guid,cat_id,title,content,pubtime),根據需要自己可以添加
- 創建索引表(index_art),包含字段(guid,id,content)這塊可以把數據表名稱也加上,好定位到那張表,根據需要可以添加,這里要把content創建全文索引
- 這里如何讓索引表和數據表進行關聯,因為每個數據表都有自增長art_id,都是從1開始,無法和索引表進行關聯,所以需要引入uuid,即每個文章都有一個自己uuid,索引表也對應文章的uuid
- 創建了32張數據表,那么如何實現減輕數據庫壓力呢,怎么把數據隨機插入到表中,這里使用了對uuid的處理,即先對uuid進行md5加密處理轉行成16進制,然后利用substr提取前兩位字符,再用hexdec函數將其轉換成10機制,讓最后結果和32取余數,余數和art拼接就是插入的表名
- 當插入數據時,還要同時插入到索引表中(最好用數據庫事務處理),因為文章內容可能是中文,英文或者混合,這里需要判斷下,如果是含有中文就需要對中文進行處理,通過中文分詞字典,分出詞語,并用空格分開,英文的話直接插入(自帶空格)
- 當讀取修改刪除數據時,都要用到uuid,所以就不能用自增長id了(跳轉頁面時的參數)。
- 當提交檢索時,也要對語句進行判斷處理,然后用全文索引語句,在index_art索引表中搜索,存在數據,取得uuid,然后利用uuid找到對應的表,取得數據
代碼
- 數據表結構:
1 (4).png
3.png
//artadd.php
//獲取guid
$uuid4 = Uuid::uuid4();
$index['guid']=$art['guid']=$uuid4->toString();
//獲取uuid,md5加密之后再獲取前兩位數字,最后轉換成10進制,
$num=hexdec(substr(md5($uuid4->toString()),0,2));
$yu=$num%32;
$table='art'.$yu;
~
~
//當插入成功后,在索引表中添加數據
//檢查內容是什么類型(1->英文,2->中文)
$cont=isWhat($art['content']);//自己封裝的函數
if($cont==1){
$index['content']=$art['content'];
}elseif($cont==2){
//利用fenci中文字典更改內容
//實例化字典
$se=new segment();
//調用方法
$index['content'] = $se->get_keyword($art['content']);
}else{
//利用fenci中文字典更改內容
//實例化字典
$se=new segment();
//調用方法
$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');//自己封裝的插入函數
- 修改數據(刪除比較簡單就不寫了)
//artedit.php
//獲取到需要改的數據
$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);
~
~
//當有post提交時
$num=hexdec(substr(md5($_POST['guid']),0,2));
$yu=$num%32;
$table='art'.$yu;
//更新成功后把索引文件中的content字段進行更新
//檢查內容是什么類型(1->英文,2->中文)
$cont=isWhat($art['content']);
if($cont==1){
$index['content']=$art['content'];
}elseif($cont==2){
//利用fenci中文字典更改內容
//實例化字典
$se=new segment();
//調用方法
$index['content'] = $se->get_keyword($art['content']);
}else{
//利用fenci中文字典更改內容
//實例化字典
$se=new segment();
//調用方法
$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']."'");
查數據
//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';
//調用分頁函數,進行分頁
$page=getPage($num,$cnt,$curr);//自己封裝的函數
//獲取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 }?>
當提交查詢時
//index.php
//檢查內容是什么類型(1->英文,2->中文)
$cont=isWhat($_POST['search']);//自己封裝函數
if($cont==1){
$search=$_POST['search'];
}elseif($cont==2){
//利用fenci中文字典更改內容
//實例化字典
$se=new segment();
//調用方法
$search = $se->get_keyword($_POST['search']);
}else{
//利用fenci中文字典更改內容
//實例化字典
$se=new segment();
//調用方法
$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']."'";
//獲取到當前guid的值
$one=find($sql);
//將關鍵字分割為數組
$key_word=explode(' ',$search);
//獲取關鍵詞出現的次數
$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);
//將數據中的關鍵詞高亮顯示
$one['content']=preg_replace("/($v1)/i","<font color=red><b>\\1</b></font>",$one['content']);
}
$one['num']=$n;
//將num插入到$one中
$art[]=$one;
//利用冒泡法根據num排序
bubble_sort($art);
}
//頁面去遍歷$art
}
使用到封裝的函數
/**
*
*分頁函數
*當$max>=5默認顯示5個條頁碼,<5正常顯示
*@param int $num文章數
*@param int $cnt每頁顯示條數
*@param int $curr當前頁
*@return array 返回拼接的每頁的url參數
*/
function getPage($num,$cnt,$curr){
//獲取最大頁碼
$max=ceil($num/$cnt);
//判斷顯示頁碼的最左邊的位置
$left=max($curr-2,1);
//最右邊頁碼
$right=min($left+4,$max);
//存在一種情況是,當共9頁,當前處于8頁,頁面只會顯示4個分頁,所以需要根據$right重新定義下left
$left=max($right-4,1);
//將獲取到的頁碼放到數組中返回,因為對于index頁面,存在兩個查詢,一個時根據欄目查詢(有參數cat_id),一個查詢吃總的欄目,所以需要用http_build_query()函數來保留原有的參數
for($i=$left;$i<=$right;$i++){
$_GET['page']=$i;//模擬url輸出格式是?page=$i,與原有的參數拼接
$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); //檢測字符串實際長度
$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 是否去除重復值
*@return array 返回所有單詞的索引數組
*/
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;
}
}