PHP项目搜索联想词如何开发实现

wen PHP项目 26

本文目录导读:

PHP项目搜索联想词如何开发实现

  1. 原生PHP + MySQL 简单实现(适合小项目)
  2. 使用 Redis 缓存方案(推荐,性能更好)
  3. 使用全文搜索引擎(推荐大规模应用)
  4. 优化建议
  5. 完整示例项目结构
  6. 选择建议

在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,这样既保证了性能又节省了内存。

抱歉,评论功能暂时关闭!