本文目录导读:

- 基础SQL LIKE 搜索(适合小项目/快速原型)
- MySQL 全文索引(中小型项目的最佳选择)
- 使用 Elasticsearch(大型/复杂搜索场景)
- 使用 Meilisearch(轻量级/易用的替代方案)
- 混合搜索方案(推荐:数据库 + 全文搜索引擎)
- 搜索最佳实践
- 总结选择
在PHP项目中实现搜索功能,根据项目规模和实时性要求,有多种实现方式,以下从简单到复杂,介绍几种主流方案。
基础SQL LIKE 搜索(适合小项目/快速原型)
最简单直接的方式,通过数据库的 LIKE 子句进行模糊匹配。
示例代码:
<?php
// 连接数据库
$pdo = new PDO('mysql:host=localhost;dbname=your_db;charset=utf8mb4', 'username', 'password');
// 获取搜索关键词(注意XSS防护,示例做了简单过滤)
$keyword = isset($_GET['q']) ? trim($_GET['q']) : '';
// 基本查询
$sql = "SELECT * FROM articles
WHERE title LIKE :keyword
OR content LIKE :keyword
ORDER BY created_at DESC
LIMIT 20";
$stmt = $pdo->prepare($sql);
$searchTerm = '%' . $keyword . '%';
$stmt->bindParam(':keyword', $searchTerm, PDO::PARAM_STR);
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
优点: 实现简单,无需额外组件
缺点: 性能差(无法利用索引),不支持分词、排序权重等高级功能
MySQL 全文索引(中小型项目的最佳选择)
MySQL 5.6+ 支持中文全文索引(需要对应字符集支持),性能远优于 LIKE。
创建全文索引
ALTER TABLE articles ADD FULLTEXT INDEX ft_title_content (title, content) WITH PARSER ngram;
搜索查询
<?php
$keyword = 'PHP项目搜索';
$sql = "SELECT *,
MATCH(title, content) AGAINST(:keyword IN BOOLEAN MODE) AS relevance
FROM articles
WHERE MATCH(title, content) AGAINST(:keyword IN BOOLEAN MODE)
ORDER BY relevance DESC
LIMIT 20";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':keyword', $keyword, PDO::PARAM_STR);
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
支持高级语法(布尔模式):
| 符号 | 含义 | 示例 |
|---|---|---|
| 必须包含 | +PHP +Laravel |
|
| 必须排除 | +PHP -ThinkPHP |
|
| 通配符 | PHP* (匹配PHP、PHP开发等) |
|
| 精确短语 | "PHP框架" (完全匹配) |
优点: 性能好,支持相关性排序,原生支持
缺点: 中文支持依赖于 ngram 解析器(需 MySQL 5.7+),索引维护有一定开销
使用 Elasticsearch(大型/复杂搜索场景)
当需要:实时搜索、高并发、复杂过滤聚合、多语言分词、拼写纠错时,Elasticsearch 是最佳选择。
架构图示
[用户] → [PHP应用] → [Elasticsearch] → [返回结果]
↕
[MySQL] (作为主数据源)
安装与集成
# Elasticsearch 安装 # 还需要安装 php-elasticsearch 扩展 composer require elasticsearch/elasticsearch
PHP 集成代码
<?php
require 'vendor/autoload.php';
use Elasticsearch\ClientBuilder;
// 建立连接
$client = ClientBuilder::create()
->setHosts(['localhost:9200'])
->build();
// 索引文档
$params = [
'index' => 'articles',
'id' => 123,
'body' => [
'title' => 'PHP项目搜索技术指南',
'content' => '本文详细介绍如何在PHP项目中实现高效搜索...',
'category' => '技术教程',
'created_at' => '2024-01-15'
]
];
$response = $client->index($params);
// 执行搜索
$searchParams = [
'index' => 'articles',
'body' => [
'query' => [
'bool' => [
'must' => [
['match' => ['content' => 'PHP搜索']]
],
'filter' => [
['term' => ['category' => '技术教程']]
]
]
],
'highlight' => [
'fields' => [
'content' => ['fragment_size' => 150, 'number_of_fragments' => 3]
]
],
'sort' => [
'created_at' => ['order' => 'desc']
]
]
];
$results = $client->search($searchParams);
// 处理结果
foreach ($results['hits']['hits'] as $hit) {
echo $hit['_source']['title'] . "<br>";
echo $hit['highlight']['content'][0]; // 高亮片段
}
?>
中文分词配置
在 Elasticsearch 中安装 IK 分词器:
// 创建索引时设置分析器
PUT /articles
{
"settings": {
"analysis": {
"analyzer": {
"ik_smart_analyzer": {
"type": "ik_smart"
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
优点: 功能强大,支持分词、聚合、高亮、纠错等
缺点: 需要额外部署服务,运维成本较高
使用 Meilisearch(轻量级/易用的替代方案)
如果你觉得 Elasticsearch 太重,Meilisearch 是很好的选择,它原生支持中文搜索。
安装
# 下载 Meilisearch curl -L https://install.meilisearch.com | sh ./meilisearch
PHP 集成
<?php
require 'vendor/autoload.php';
use Meilisearch\Client;
$client = new Client('http://localhost:7700', 'masterKey');
// 添加文档
$client->index('articles')->addDocuments([
[
'id' => 1,
'title' => 'PHP项目搜索实现',
'content' => '使用Meilisearch实现快速搜索...',
'category' => '技术'
]
]);
// 搜索
$results = $client->index('articles')->search('PHP', [
'limit' => 20,
'sort' => ['created_at:desc']
]);
// 获取结果
foreach ($results->getHits() as $hit) {
echo $hit['title'] . "<br>";
}
?>
优点: 安装简单,几分钟即可使用,支持中文和模糊搜索,速度快
缺点: 开源版功能有限,集群支持需要付费
混合搜索方案(推荐:数据库 + 全文搜索引擎)
对于大多数项目,推荐采用分层策略:
| 场景 | 方案 | 说明 |
|---|---|---|
| 简单关键词搜索 | MySQL FULLTEXT | 覆盖 80% 需求 |
| 复杂搜索、高并发 | Elasticsearch | 处理重度搜索 |
| 快速原型、小项目 | MySQL LIKE | 快速验证 |
| 想快速上手中文搜索 | Meilisearch | 折中方案 |
典型架构
用户搜索 → 缓存检查(Redis) → 命中:直接返回
↓ 未命中
Elasticsearch → 返回结果ID列表
↓
MySQL (根据ID获取完整数据)
↓
缓存到Redis
↓
返回给前端(Twig/Blade模板渲染)
搜索最佳实践
安全性处理
// 1. 使用参数化查询(永远不要拼接SQL)
$stmt = $pdo->prepare("SELECT * FROM articles WHERE title LIKE :keyword");
$stmt->execute(['keyword' => '%' . $keyword . '%']);
// 2. XSS防护(输出时处理)
echo htmlspecialchars($result['title'], ENT_QUOTES, 'UTF-8');
// 3. 限制搜索长度
$keyword = mb_substr($_GET['q'], 0, 100);
性能优化
- 缓存搜索结果 (Redis/Memcached)
- 限制搜索结果数量
- 使用分页而不是无限加载
- 对长尾/低频搜索词做降级处理
搜索增强
- 自动完成:使用前端库如
typeahead.js,后端返回预搜索建议 - 拼写纠错:ES 的
fuzzy查询或 Meilisearch 的typo tolerance - 搜索日志:记录搜索词,用于优化热门搜索和推荐
总结选择
| 你的项目情况 | 推荐方案 |
|---|---|
| 数据量 < 10万,单一字段 | MySQL LIKE |
| 数据量 < 100万,需要中文分词 | MySQL FULLTEXT + ngram |
| 数据量 > 100万,或需要复杂搜索 | Elasticsearch |
| 想要快速上手、中文友好 | Meilisearch |
| 想保持简单但性能优于 LIKE | SQLite FTS5 (如果你用SQLite) |
我的建议: 大部分 PHP 项目用 MySQL FULLTEXT 即可满足需求,当确实遇到性能瓶颈或需要高级搜索功能时,再考虑迁移到 Elasticsearch。