PHP 同义词搜索支持吗

wen PHP项目 5

本文目录导读:

PHP 同义词搜索支持吗

  1. 使用数据库内置功能
  2. 使用 Elasticsearch / OpenSearch
  3. 使用 PHP 数组维护同义词库
  4. 使用第三方 PHP 库
  5. 使用 Redis 缓存同义词
  6. 综合实现方案(推荐)
  7. 选择建议
  8. 注意事项

是的,PHP 支持同义词搜索,但PHP 本身并不内置同义词搜索引擎,它需要借助外部技术或算法来实现,以下是 PHP 实现同义词搜索的几种常见方案:


使用数据库内置功能

MySQL / MariaDB

MySQL 本身不直接支持同义词,但可以通过以下方式实现:

// 方案1:使用 LIKE 查询匹配多个同义词
$synonyms = ['手机', '移动电话', '手提电话'];
$where = [];
foreach ($synonyms as $word) {
    $where[] = "title LIKE '%" . mysqli_real_escape_string($conn, $word) . "%'";
}
$sql = "SELECT * FROM products WHERE " . implode(' OR ', $where);

PostgreSQL

PostgreSQL 有 tsquery 和同义词词典支持:

-- 创建同义词词典
CREATE TEXT SEARCH DICTIONARY my_synonym (
    TEMPLATE = synonym,
    SYNONYMS = my_synonyms
);
CREATE TEXT SEARCH CONFIGURATION my_config (COPY = english);
ALTER TEXT SEARCH CONFIGURATION my_config
    ALTER MAPPING FOR asciiword WITH my_synonym;
-- 在 PHP 中使用
$query = "SELECT * FROM documents WHERE to_tsvector('my_config', content) @@ to_tsquery('my_config', '手机')";

使用 Elasticsearch / OpenSearch

这是最强大的方案,支持完整的同义词搜索:

// 安装 elasticsearch-php 客户端
composer require elasticsearch/elasticsearch
$client = Elasticsearch\ClientBuilder::create()->build();
// 创建索引时配置同义词分析器
$params = [
    'index' => 'products',
    'body' => [
        'settings' => [
            'analysis' => [
                'filter' => [
                    'my_synonym_filter' => [
                        'type' => 'synonym',
                        'synonyms' => [
                            '手机, 移动电话, 手提电话, mobile',
                            '电脑, 计算机, PC',
                        ]
                    ]
                ],
                'analyzer' => [
                    'my_analyzer' => [
                        'tokenizer' => 'standard',
                        'filter' => ['lowercase', 'my_synonym_filter']
                    ]
                ]
            ]
        ]
    ]
];
// 搜索时自动匹配同义词
$params = [
    'index' => 'products',
    'body' => [
        'query' => [
            'match' => [
                'title' => '手机'
            ]
        ]
    ]
];

使用 PHP 数组维护同义词库

简单但有效的方案,适合中小型项目:

class SynonymSearch {
    private $synonymMap = [
        '手机' => ['手机', '移动电话', '手提电话', 'cellphone', 'mobile'],
        '电脑' => ['电脑', '计算机', 'PC', 'computer'],
        '汽车' => ['汽车', '轿车', '车辆', 'car'],
    ];
    public function search($keyword, $data) {
        // 获取同义词
        $synonyms = $this->getSynonyms($keyword);
        $results = [];
        foreach ($data as $item) {
            foreach ($synonyms as $synonym) {
                if (strpos($item['title'], $synonym) !== false) {
                    $results[] = $item;
                    break;
                }
            }
        }
        return $results;
    }
    private function getSynonyms($keyword) {
        if (isset($this->synonymMap[$keyword])) {
            return $this->synonymMap[$keyword];
        }
        return [$keyword];
    }
}

使用第三方 PHP 库

开源方案:

  • sphinxsearch/sphinxapi - 基于 Sphinx 搜索引擎
  • solarium/solarium - 基于 Apache Solr
  • teamtnt/tntsearch - 轻量级 PHP 全文搜索引擎

TntSearch 示例:

use TeamTNT\TNTSearch\TNTSearch;
$tnt = new TNTSearch;
$tnt->loadConfig([
    'driver'    => 'mysql',
    'host'      => 'localhost',
    'database'  => 'test',
    'username'  => 'root',
    'password'  => '',
    'storage'   => '/tmp/',
]);
$tnt->selectIndex("products.index");
$res = $tnt->search("手机", 12);

使用 Redis 缓存同义词

// 存储同义词映射
$redis->hSet('synonyms', '手机', json_encode(['手机', '移动电话', '手提电话']));
// 搜索时读取
$synonyms = json_decode($redis->hGet('synonyms', $keyword), true);
$searchTerms = is_array($synonyms) ? $synonyms : [$keyword];

综合实现方案(推荐)

对于大多数 PHP 项目,推荐组合使用:

class SmartSearch {
    private $pdo;
    private $synonymTable = 'synonyms';
    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }
    public function search($keyword, $limit = 10) {
        // 1. 获取同义词
        $synonyms = $this->getSynonymsFromDB($keyword);
        // 2. 构建查询
        $sql = "SELECT * FROM products WHERE ";
        $conditions = [];
        foreach ($synonyms as $i => $word) {
            $conditions[] = "title LIKE :word" . $i;
            $params[":word" . $i] = "%" . $word . "%";
        }
        $sql .= implode(' OR ', $conditions);
        $sql .= " LIMIT " . intval($limit);
        // 3. 执行查询
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        // 4. 按相关度排序
        return $this->rankResults($stmt->fetchAll(), $keyword);
    }
    private function getSynonymsFromDB($keyword) {
        $stmt = $this->pdo->prepare("SELECT synonym FROM synonyms WHERE base_word = ?");
        $stmt->execute([$keyword]);
        $synonyms = $stmt->fetchAll(PDO::FETCH_COLUMN);
        array_unshift($synonyms, $keyword); // 在开头添加原词
        return array_unique($synonyms);
    }
}

选择建议

方案 适用场景 复杂度 性能
数据库 LIKE + PHP 数组 小规模数据 一般
PHP 词典 + 缓存 中等规模 较好
Elasticsearch 大规模、需要分词 优秀
TntSearch 中小规模独立搜索 良好
PostgreSQL 字典 使用 PostgreSQL 的项目 良好

注意事项

  • 同义词匹配模式:需要支持多语言、模糊匹配、拼音转换等
  • 性能优化:使用索引、缓存同义词映射
  • 扩展性:设计可动态添加同义词的方案
  • 相关性排序:精确匹配应优先于同义词匹配

你具体是什么场景?可以给我更多细节,我可以给你更有针对性的实现建议。

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