本文目录导读:

在PHP项目中实现搜索联想词(自动补全/搜索建议)通常有以下几种主流方案,我会从简单到复杂逐一介绍:
原生PHP + MySQL 简单实现(适合小项目)
数据库设计
-- 搜索日志表
CREATE TABLE search_history (
id INT AUTO_INCREMENT PRIMARY KEY,
keyword VARCHAR(100) NOT NULL,
search_count INT DEFAULT 1,
INDEX idx_keyword (keyword)
);
PHP搜索接口
<?php
// search_suggest.php
header('Content-Type: application/json; charset=utf-8');
$keyword = $_GET['keyword'] ?? '';
$keyword = trim($keyword);
if (mb_strlen($keyword) < 1) {
echo json_encode([]);
exit;
}
$db = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'root', '');
$stmt = $db->prepare("SELECT DISTINCT keyword FROM search_history
WHERE keyword LIKE :keyword
ORDER BY search_count DESC
LIMIT 10");
$stmt->execute([':keyword' => $keyword . '%']);
$results = $stmt->fetchAll(PDO::FETCH_COLUMN);
echo json_encode($results);
前端实现
<input type="text" id="search" placeholder="输入搜索关键词" autocomplete="off">
<div id="suggestions"></div>
<script>
document.getElementById('search').addEventListener('input', function(e) {
const keyword = e.target.value;
if (keyword.length < 1) {
document.getElementById('suggestions').innerHTML = '';
return;
}
fetch(`search_suggest.php?keyword=${encodeURIComponent(keyword)}`)
.then(response => response.json())
.then(data => {
let html = '';
data.forEach(item => {
html += `<div class="suggestion-item">${item}</div>`;
});
document.getElementById('suggestions').innerHTML = html;
});
});
</script>
使用 Redis 缓存方案(推荐,性能更好)
数据存储结构
<?php
// 使用 Redis 有序集合存储热门搜索词
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->zIncrBy('hot_searches', 1, $keyword); // 搜索次数+1
// 存储联想词(使用集合)
$prefix = mb_substr($keyword, 0, 1);
$redis->sAdd("suggest:{$prefix}", $keyword); // 按首字分组存储
$redis->expire("suggest:{$prefix}", 86400 * 7); // 设置7天过期
联想词获取
<?php
function getSuggestions($keyword, $limit = 10) {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$results = [];
$prefix = mb_substr($keyword, 0, 1);
// 先查询精确前缀匹配
$members = $redis->sMembers("suggest:{$prefix}");
foreach ($members as $word) {
if (strpos($word, $keyword) === 0) {
$results[] = $word;
}
if (count($results) >= $limit) break;
}
return $results;
}
使用全文搜索引擎(推荐大规模应用)
Elasticsearch 方案
<?php
require 'vendor/autoload.php';
use Elasticsearch\ClientBuilder;
$client = ClientBuilder::create()->build();
$params = [
'index' => 'search_suggest',
'body' => [
'suggest' => [
'keyword_suggest' => [
'prefix' => $_GET['keyword'],
'completion' => [
'field' => 'suggest',
'size' => 10
]
]
]
]
];
$response = $client->search($params);
$suggestions = [];
foreach ($response['suggest']['keyword_suggest'][0]['options'] as $option) {
$suggestions[] = $option['text'];
}
echo json_encode($suggestions);
数据索引创建
// 创建索引映射
$params = [
'index' => 'search_suggest',
'body' => [
'mappings' => [
'properties' => [
'suggest' => [
'type' => 'completion'
]
]
]
]
];
$client->indices()->create($params);
// 批量索引数据
$params = ['body' => []];
$keywords = ['PHP教程', 'PHP框架', 'JavaScript', 'Python入门'];
foreach ($keywords as $kw) {
$params['body'][] = [
'index' => ['_index' => 'search_suggest']
];
$params['body'][] = [
'suggest' => ['input' => $kw]
];
}
$client->bulk($params);
优化建议
防抖处理
// 前端添加防抖
let debounceTimer;
document.getElementById('search').addEventListener('input', function(e) {
clearTimeout(debounceTimer);
const keyword = e.target.value;
debounceTimer = setTimeout(() => {
fetchSuggestions(keyword);
}, 300); // 300ms延迟
});
结果缓存
// 使用文件缓存
$cacheKey = md5($keyword);
$cacheFile = "/tmp/suggest_{$cacheKey}.json";
if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < 300)) {
echo file_get_contents($cacheFile);
exit;
}
// 查询数据库...
// 保存缓存
file_put_contents($cacheFile, json_encode($results));
性能优化
- 限制返回数量:通常10-20条足够
- 使用索引:数据库LIKE查询要加索引
- 预热缓存:热门搜索词提前加载到缓存
- 定期清理:删除长时间未使用的搜索词
完整示例项目结构
search-suggest/
├── api/
│ └── suggest.php # 联想词API接口
├── admin/
│ └── manage.php # 后台管理搜索词
├── config/
│ └── database.php # 数据库配置
├── static/
│ ├── css/
│ │ └── style.css
│ └── js/
│ ├── suggest.js # 前端联想逻辑
│ └── app.js # 主应用
├── index.html # 搜索页面
└── README.md
选择建议
| 方案 | 数据量 | 实时性 | 实现难度 | 推荐场景 |
|---|---|---|---|---|
| MySQL LIKE | <10万条 | 高 | 低 | 小型网站 |
| Redis | <100万条 | 很高 | 中 | 中型项目 |
| Elasticsearch | 无限 | 高 | 高 | 大型搜索系统 |
最佳实践:建议使用 Redis + MySQL 组合方案,对热门词使用Redis缓存,冷门词直接查询MySQL,这样既保证了性能又节省了内存。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播