如何在基于MySQL的Strapi CMS中实现模糊搜索?
在MySQL版Strapi中实现近似模糊搜索的方案
我来分享几个在MySQL版Strapi中实现这种近似模糊搜索的可行方案,刚好能满足你提到的'tvs ad'匹配'tv syd'这类发音/拼写近似的需求:
方案一:利用MySQL的SOUNDEX/SOUNDS LIKE(发音相似匹配)
这是最贴合你示例场景的方案,因为SOUNDS LIKE是基于发音规则的匹配,能识别发音相近的单词组合。
实现步骤:
- 创建自定义控制器:在你的目标内容类型控制器中添加搜索方法,比如
api/your-content-type/controllers/your-content-type.js:
module.exports = { async phoneticSearch(ctx) { const { keyword } = ctx.query; if (!keyword) { return ctx.badRequest('搜索关键词不能为空'); } // 将关键词拆分为独立词汇,分别匹配发音 const searchTerms = keyword.split(' ').filter(term => term.trim().length > 0); // 构建SQL查询,每个词汇用SOUNDS LIKE匹配目标字段(这里假设字段名为name) let sqlQuery = 'SELECT * FROM your_content_type_table WHERE 1=1'; const queryParams = []; searchTerms.forEach((term) => { sqlQuery += ' AND SOUNDEX(name) SOUNDS LIKE SOUNDEX(?)'; queryParams.push(term); }); // 执行原生SQL查询 const searchResults = await strapi.db.connection.raw(sqlQuery, queryParams); return ctx.send(searchResults[0]); } };
注意:把
your_content_type_table替换成你实际的数据库表名(Strapi表名一般是内容类型的复数形式,比如items),name替换成你要搜索的字段名。
- 测试接口:启动Strapi后,访问
http://your-strapi-url/api/your-content-type/phonetic-search?keyword=tvs ad,就能获取发音匹配的结果。
优缺点:
- ✅ 优点:实现简单,完全基于MySQL原生功能,对英语发音相似的匹配效果好,正好适配你的示例需求。
- ❌ 缺点:对非英语语言支持较差,发音规则适配有限。
方案二:MySQL全文索引(FULLTEXT)
如果你的数据量较大,需要更高效的模糊搜索,可以用MySQL的全文索引功能,支持关键词的近似匹配和权重排序。
实现步骤:
- 创建全文索引:先给目标字段创建全文索引(比如给
name字段):
ALTER TABLE your_content_type_table ADD FULLTEXT INDEX idx_fulltext_name (name);
注意:MySQL默认全文索引的最小词长是4,如果你需要搜索短词(比如示例中的
tv),需要修改MySQL配置ft_min_word_len=2,然后重建索引。
- 编写Strapi搜索控制器:
module.exports = { async fulltextSearch(ctx) { const { keyword } = ctx.query; if (!keyword) { return ctx.badRequest('搜索关键词不能为空'); } // 使用BOOLEAN模式,支持通配符和近似匹配 const searchResults = await strapi.db.connection.raw( `SELECT *, MATCH(name) AGAINST(? IN BOOLEAN MODE) AS relevance FROM your_content_type_table WHERE MATCH(name) AGAINST(? IN BOOLEAN MODE) ORDER BY relevance DESC`, [`*${keyword}*`, `*${keyword}*`] ); return ctx.send(searchResults[0]); } };
*${keyword}*表示匹配包含关键词任意部分的内容,BOOLEAN模式还支持+(必须包含)、-(排除)等语法。
优缺点:
- ✅ 优点:搜索效率高,适合大数据量,支持复杂的关键词组合匹配。
- ❌ 缺点:近似匹配的灵活性不如发音匹配或编辑距离,短词需要调整MySQL配置。
方案三:Levenshtein编辑距离(拼写相似匹配)
如果需要基于拼写的相似度(比如允许一定数量的拼写错误),可以用Levenshtein距离计算两个字符串的编辑次数,筛选距离较小的结果。
实现步骤:
- 在MySQL中创建Levenshtein函数:先在你的MySQL数据库中执行以下SQL创建自定义函数:
DELIMITER // CREATE FUNCTION LEVENSHTEIN(s1 VARCHAR(255), s2 VARCHAR(255)) RETURNS INT DETERMINISTIC BEGIN DECLARE s1_len, s2_len, i, j, c, c_temp INT; DECLARE s1_char CHAR; DECLARE cv0, cv1 VARBINARY(256); SET s1_len = CHAR_LENGTH(s1), s2_len = CHAR_LENGTH(s2); IF s1_len = 0 THEN RETURN s2_len; END IF; IF s2_len = 0 THEN RETURN s1_len; END IF; SET cv0 = 0x00; FOR i FROM 1 TO s2_len DO SET cv0 = CONCAT(cv0, UNHEX(HEX(i))); END FOR; FOR i FROM 1 TO s1_len DO SET s1_char = SUBSTRING(s1, i, 1), cv1 = UNHEX(HEX(i)), j = 1; FOR j FROM 1 TO s2_len DO SET c = IF(s1_char = SUBSTRING(s2, j, 1), 0, 1); SET c_temp = CONV(HEX(SUBSTRING(cv0, j, 1)), 16, 10) + c; SET cv1 = CONCAT(cv1, UNHEX(HEX(IF(CONV(HEX(SUBSTRING(cv0, j+1, 1)), 16, 10) + 1 > c_temp, c_temp, CONV(HEX(SUBSTRING(cv0, j+1, 1)), 16, 10) + 1)))); END FOR; SET cv0 = cv1; END FOR; RETURN CONV(HEX(SUBSTRING(cv0, s2_len+1, 1)), 16, 10); END// DELIMITER ;
- 编写Strapi搜索控制器:
module.exports = { async fuzzySearch(ctx) { const { keyword } = ctx.query; if (!keyword) { return ctx.badRequest('搜索关键词不能为空'); } // 设置最大允许的编辑距离(比如2,表示最多2个字符的差异) const maxDistance = 2; const searchResults = await strapi.db.connection.raw( `SELECT *, LEVENSHTEIN(name, ?) AS distance FROM your_content_type_table WHERE LEVENSHTEIN(name, ?) <= ? ORDER BY distance ASC`, [keyword, keyword, maxDistance] ); return ctx.send(searchResults[0]); } };
优缺点:
- ✅ 优点:精准控制拼写相似度,适合处理拼写错误的搜索请求,支持所有语言。
- ❌ 缺点:计算量较大,数据量非常大时可能影响性能,需要合理设置最大距离。
内容的提问来源于stack exchange,提问作者Jonatanbs
相关产品推荐
相关产品推荐

