本文目录导读:

在 PHP API 中统计热搜词,通常需要以下几个核心步骤:
设计基础数据表结构
-- 方案一:简单统计表
CREATE TABLE search_hotwords (
id INT AUTO_INCREMENT PRIMARY KEY,
keyword VARCHAR(255) NOT NULL,
search_count INT DEFAULT 0,
last_search_time DATETIME,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY unique_keyword (keyword),
INDEX idx_count (search_count DESC)
);
-- 方案二:包含更多维度
CREATE TABLE search_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
keyword VARCHAR(255) NOT NULL,
user_id INT,
ip_address VARCHAR(45),
search_time DATETIME,
device_type VARCHAR(50),
INDEX idx_keyword (keyword),
INDEX idx_time (search_time)
);
记录搜索接口实现
<?php
// search.php - 搜索接口
class SearchController {
private $db;
public function __construct() {
$this->db = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass');
}
/**
* 处理搜索请求并记录热搜
*/
public function search($keyword) {
// 1. 过滤和验证关键词
$keyword = $this->sanitizeKeyword($keyword);
if (empty($keyword)) {
return $this->error('关键词不能为空');
}
// 2. 记录搜索日志(可选)
$this->logSearch($keyword);
// 3. 更新热词统计
$this->updateHotwordStats($keyword);
// 4. 执行实际搜索逻辑
$results = $this->performSearch($keyword);
return $this->success($results);
}
/**
* 更新热词统计
*/
private function updateHotwordStats($keyword) {
try {
$sql = "INSERT INTO search_hotwords (keyword, search_count, last_search_time)
VALUES (:keyword, 1, NOW())
ON DUPLICATE KEY UPDATE
search_count = search_count + 1,
last_search_time = NOW()";
$stmt = $this->db->prepare($sql);
$stmt->execute(['keyword' => $keyword]);
} catch (PDOException $e) {
// 记录错误日志
error_log("更新热词失败: " . $e->getMessage());
}
}
/**
* 记录详细搜索日志
*/
private function logSearch($keyword) {
$sql = "INSERT INTO search_logs (keyword, user_id, ip_address, search_time, device_type)
VALUES (:keyword, :user_id, :ip, NOW(), :device)";
$stmt = $this->db->prepare($sql);
$stmt->execute([
'keyword' => $keyword,
'user_id' => $_SESSION['user_id'] ?? 0,
'ip' => $_SERVER['REMOTE_ADDR'],
'device' => $this->detectDevice()
]);
}
private function sanitizeKeyword($keyword) {
// 去除 HTML 标签,限制长度等
$keyword = strip_tags($keyword);
$keyword = trim($keyword);
$keyword = mb_substr($keyword, 0, 100, 'UTF-8');
return $keyword;
}
}
获取热搜词 API
<?php
// hotwords.php - 获取热搜词接口
class HotWordsController {
private $db;
private $cache;
public function __construct() {
$this->db = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass');
// 可以使用 Redis 或文件缓存
$this->cache = new RedisCache();
}
/**
* 获取热搜词列表
*/
public function getHotWords($limit = 10, $timeRange = '24h') {
// 1. 尝试从缓存获取
$cacheKey = "hotwords:{$limit}:{$timeRange}";
$cached = $this->cache->get($cacheKey);
if ($cached !== false) {
return $this->success($cached);
}
// 2. 从数据库获取
$hotwords = $this->fetchHotWords($limit, $timeRange);
// 3. 存入缓存(5分钟过期)
$this->cache->set($cacheKey, $hotwords, 300);
return $this->success($hotwords);
}
/**
* 从数据库查询热搜词
*/
private function fetchHotWords($limit, $timeRange) {
$timeCondition = $this->buildTimeCondition($timeRange);
$sql = "SELECT keyword, search_count
FROM search_hotwords
WHERE {$timeCondition}
ORDER BY search_count DESC
LIMIT :limit";
$stmt = $this->db->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 构建时间条件
*/
private function buildTimeCondition($timeRange) {
switch ($timeRange) {
case '1h':
return "last_search_time >= DATE_SUB(NOW(), INTERVAL 1 HOUR)";
case '24h':
return "last_search_time >= DATE_SUB(NOW(), INTERVAL 24 HOUR)";
case '7d':
return "last_search_time >= DATE_SUB(NOW(), INTERVAL 7 DAY)";
case '30d':
return "last_search_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)";
default:
return "1=1"; // 全部时间
}
}
}
高级统计方案(推荐)
<?php
// AdvancedHotWords.php - 高级热搜统计
class AdvancedHotWords {
/**
* 加权热搜算法
*/
public function calculateWeightedHotWords($limit = 10) {
// 多个维度加权计算
$sql = "
SELECT
keyword,
SUM(
CASE
WHEN search_time >= NOW() - INTERVAL 1 HOUR THEN 5 -- 最近1小时搜索权重5
WHEN search_time >= NOW() - INTERVAL 24 HOUR THEN 3 -- 最近24小时权重3
WHEN search_time >= NOW() - INTERVAL 7 DAY THEN 1 -- 最近7天权重1
ELSE 0.5 -- 更早权重0.5
END
) AS hot_score
FROM search_logs
WHERE search_time >= DATE_SUB(NOW(), INTERVAL 30 DAY) -- 只统计最近30天
GROUP BY keyword
ORDER BY hot_score DESC
LIMIT :limit
";
// 执行查询...
}
/**
* 防止刷榜
*/
public function antiSpamCheck($userId, $keyword) {
// 1. 频率限制:同一用户1分钟内最多搜索3次
$recentCount = $this->getUserSearchCount($userId, 60); // 60秒内
if ($recentCount >= 3) {
return false; // 拒绝记录
}
// 2. 同IP限制
$ipCount = $this->getIpSearchCount($userId, 60);
if ($ipCount >= 10) {
return false;
}
return true;
}
/**
* 实时热搜(使用Redis)
*/
public function realTimeHotWords() {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 使用 Sorted Set 存储热词
// 每次搜索时执行:ZINCRBY hotwords 1 $keyword
// 获取top 10
$hotwords = $redis->zRevRange('hotwords', 0, 9, true);
return $hotwords;
}
}
API 路由和响应
<?php
// router.php - API路由
$route = $_GET['route'] ?? '';
switch ($route) {
case 'search':
$controller = new SearchController();
$result = $controller->search($_POST['keyword'] ?? '');
break;
case 'hotwords':
$controller = new HotWordsController();
$limit = $_GET['limit'] ?? 10;
$timeRange = $_GET['time'] ?? '24h';
$result = $controller->getHotWords($limit, $timeRange);
break;
default:
$result = ['error' => 'Invalid route'];
}
header('Content-Type: application/json');
echo json_encode($result);
前端调用示例
// 前端搜索
async function search(keyword) {
const response = await fetch('/api/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ keyword })
});
return response.json();
}
// 获取热搜词
async function getHotWords() {
const response = await fetch('/api/hotwords?limit=10&time=24h');
return response.json();
}
优化建议
- 使用缓存:Redis 或 Memcached 缓存热词结果
- 异步处理:使用消息队列(RabbitMQ、Kafka)异步更新统计
- 定时任务:定期清理过期数据,重建索引
- 防刷机制:IP限制、用户频率限制、验证码
- 数据清洗:过滤敏感词、无效词、过短词
根据你的实际访问量和需求,可以选择简单或复杂的统计方案,小型项目用方案一即可,大型项目推荐使用 Redis + 消息队列的方案。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播