0

0

Laravel 8 数据库多词模糊搜索优化指南

花韻仙語

花韻仙語

发布时间:2025-11-26 11:51:39

|

149人浏览过

|

来源于php中文网

原创

Laravel 8 数据库多词模糊搜索优化指南

本文旨在解决 laravel 8 中使用 eloquent orm 进行多词模糊搜索时遇到的挑战,特别是当搜索词包含多个单词(如姓名和姓氏)时无法正确匹配的问题。通过介绍一种将搜索短语分词并结合 `orwhere` 语句进行动态查询的策略,实现更灵活、准确的数据库搜索功能。

理解多词搜索的挑战

在 Laravel 中,当我们需要在多个数据库字段中执行模糊搜索时,通常会使用 where 或 orWhere 结合 LIKE 操作符。例如,以下代码片段展示了在多个字段中搜索单个关键词的常见做法:

$query = Immovable::query()
    ->leftJoin('streets', 'streets.gus_id', '=', 'immovables.street_gus_id')
    ->select(
        'immovables.id',
        'immovables.street_gus_id',
        'immovables.building_number',
        'immovables.apartment_number',
        'streets.name as street_name'
    );

if (request()->has('search')) {
    $searchTerm = "%" . request()->search['value'] . "%";
    $query->where('streets.name', 'like', $searchTerm)
          ->orWhere('immovables.community', 'like', $searchTerm)
          // ... 其他 orWhere 条件
          ->orWhere('immovables.name', 'like', $searchTerm)
          ->orWhere('immovables.surname', 'like', $searchTerm);
}
$results = $query->get();

这种方法对于单个单词的搜索(例如,搜索 "Karol" 或 "Krawczyk")是有效的。然而,当用户输入包含多个单词的搜索短语(例如 "Karol Krawczyk")时,上述代码会将其作为一个整体进行匹配。这意味着数据库将尝试查找一个字段中同时包含 "Karol Krawczyk" 整个字符串的记录。如果 "Karol" 在 immovables.name 字段,而 "Krawczyk" 在 immovables.surname 字段,或者它们分散在不同的字段中,那么这种整体匹配的方式将无法返回任何结果,从而导致搜索失败。

要解决这个问题,我们需要将用户输入的搜索短语拆分成独立的单词,并对每个单词在所有目标字段中执行独立的模糊匹配。

解决方案:分词与动态查询

为了实现更灵活的多词搜索,我们可以采取以下策略:

百度智能云·曦灵
百度智能云·曦灵

百度旗下的AI数字人平台

下载
  1. 分词处理: 将用户输入的搜索短语(例如 "Karol Krawczyk")按照空格或其他分隔符拆分成独立的单词("Karol", "Krawczyk")。
  2. 动态构建查询: 遍历这些拆分后的单词,对每个单词在所有需要搜索的字段中应用 LIKE 操作符。关键在于,对于每个单词,我们都使用 orWhere 来连接其在不同字段上的匹配条件。

示例代码

以下是优化后的 Laravel 查询代码,它演示了如何实现上述策略:

use Illuminate\Http\Request;
use App\Models\Immovable; // 假设您的模型名为 Immovable

class SearchController extends Controller
{
    public function search(Request $request)
    {
        $query = Immovable::query()
            ->leftJoin('streets', 'streets.gus_id', '=', 'immovables.street_gus_id')
            ->select(
                'immovables.id',
                'immovables.street_gus_id',
                'immovables.building_number',
                'immovables.apartment_number',
                'streets.name as street_name'
            );

        if ($request->has('search') && !empty($request->search['value'])) {
            // 将搜索值按空格拆分成多个单词
            $searches = explode(" ", $request->search['value']);

            // 使用一个闭包来分组所有的 OR 条件,确保逻辑清晰
            $query->where(function ($q) use ($searches) {
                foreach ($searches as $search) {
                    $searchTerm = "%" . $search . "%"; // 为每个单词构建模糊匹配字符串

                    // 对每个单词在所有相关字段中执行 OR 匹配
                    $q->orWhere('streets.name', 'like', $searchTerm);
                    $q->orWhere('immovables.community', 'like', $searchTerm);
                    $q->orWhere('immovables.city', 'like', $searchTerm);
                    $q->orWhere('immovables.building_number', 'like', $searchTerm);
                    $q->orWhere('immovables.granted_comments', 'like', $searchTerm);
                    $q->orWhere('immovables.inspections', 'like', $searchTerm);
                    $q->orWhere('immovables.oze_installations', 'like', $searchTerm);
                    $q->orWhere('immovables.pesel', 'like', $searchTerm);
                    $q->orWhere('immovables.name', 'like', $searchTerm);
                    $q->orWhere('immovables.surname', 'like', $searchTerm);
                    $q->orWhere('immovables.email1', 'like', $searchTerm);
                    $q->orWhere('immovables.email2', 'like', $searchTerm);
                    $q->orWhere('immovables.email3', 'like', $searchTerm);
                    $q->orWhere('immovables.phone1', 'like', $searchTerm);
                    $q->orWhere('immovables.phone2', 'like', $searchTerm);
                    $q->orWhere('immovables.phone3', 'like', $searchTerm);
                    $q->orWhere('immovables.description', 'like', $searchTerm);
                }
            });
        }

        $results = $query->get();

        return view('your.view', compact('results')); // 假设您将结果传递给视图
    }
}

代码解析

  1. explode(" ", $request->search['value']): 这行代码将用户输入的搜索字符串 $request->search['value'] 按照空格进行分割,生成一个包含所有独立单词的数组 $searches。例如,"Karol Krawczyk" 将变为 ['Karol', 'Krawczyk']。
  2. $query->where(function ($q) use ($searches) { ... }): 这是一个关键的优化。通过使用 where 闭包,我们将所有针对搜索词的 OR 条件封装在一个独立的逻辑组中。这在 SQL 中通常会生成类似 WHERE (condition1 OR condition2 OR ...) 的语句,确保了搜索逻辑的正确优先级,避免与其他潜在的 AND 条件发生冲突。
  3. foreach ($searches as $search): 循环遍历每个拆分后的单词。
  4. $searchTerm = "%" . $search . "%": 为当前循环的单词构建一个 LIKE 匹配字符串,例如 "%Karol%"。
  5. $q->orWhere('column_name', 'like', $searchTerm): 对于每个单词 $search,我们遍历所有需要搜索的字段,并使用 orWhere 将它们连接起来。这意味着只要任何一个字段包含当前单词,该记录就会被匹配。
    • 例如,如果搜索词是 "Karol Krawczyk",循环将首先处理 "Karol"。此时,查询会添加一系列 orWhere 条件,查找任何字段中包含 "Karol" 的记录。
    • 接着,循环处理 "Krawczyk"。此时,又会添加一系列 orWhere 条件,查找任何字段中包含 "Krawczyk" 的记录。
    • 最终生成的 SQL 查询将是一个大的 OR 逻辑块,例如: WHERE ( (streets.name LIKE '%Karol%' OR immovables.community LIKE '%Karol%' OR ... OR immovables.surname LIKE '%Karol%') OR (streets.name LIKE '%Krawczyk%' OR immovables.community LIKE '%Krawczyk%' OR ... OR immovables.surname LIKE '%Krawczyk%') )
    • 这样,无论 "Karol" 和 "Krawczyk" 出现在哪个字段,或者是否同时出现,只要满足任一条件,记录都会被检索出来。

注意事项

  • 性能考量: 这种方法在搜索字段较多且数据量庞大时,可能会导致性能下降。因为 LIKE %...% 操作符通常无法有效利用索引,尤其是前导通配符 (%)。
    • 优化建议: 对于高并发或大数据量的搜索需求,可以考虑使用专门的全文搜索解决方案,如:
      • MySQL Full-Text Search: 如果您的数据库是 MySQL,可以为相关字段创建全文索引。
      • Elasticsearch 或 Solr: 专业的搜索服务,提供强大的搜索功能、分词、相关性排序等。
      • Laravel Scout: Laravel 提供的一个驱动,可以轻松地将 Eloquent 模型与 Algolia、Elasticsearch 等搜索服务集成。
  • 搜索词清理: 在实际应用中,建议对用户输入的搜索词进行额外的清理,例如:
    • trim():去除首尾空格。
    • mb_strtolower():转换为小写(如果搜索不区分大小写)。
    • 去除多余的空格(例如,将 "Karol Krawczyk" 变为 "Karol Krawczyk")。
  • 用户体验: 结合前端技术,可以提供搜索建议、实时搜索、搜索结果高亮等功能,进一步提升用户体验。
  • SQL 注入: Laravel Eloquent ORM 已经内置了对 SQL 注入的防护,通过参数绑定来处理所有用户输入。因此,只要您通过 Eloquent 的方法构建查询,就无需担心 SQL 注入问题。

总结

通过将用户输入的搜索短语进行分词,并结合 Laravel Eloquent 的 orWhere 闭包和循环结构,我们可以有效地实现多词模糊搜索功能。这种方法解决了单一 LIKE 匹配无法处理多单词搜索的局限性,使得搜索结果更加灵活和符合用户预期。然而,对于大规模应用,仍需权衡性能,并考虑引入更专业的全文搜索解决方案。

相关专题

更多
laravel组件介绍
laravel组件介绍

laravel 提供了丰富的组件,包括身份验证、模板引擎、缓存、命令行工具、数据库交互、对象关系映射器、事件处理、文件操作、电子邮件发送、队列管理和数据验证。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

316

2024.04.09

laravel中间件介绍
laravel中间件介绍

laravel 中间件分为五种类型:全局、路由、组、终止和自定。想了解更多laravel中间件的相关内容,可以阅读本专题下面的文章。

271

2024.04.09

laravel使用的设计模式有哪些
laravel使用的设计模式有哪些

laravel使用的设计模式有:1、单例模式;2、工厂方法模式;3、建造者模式;4、适配器模式;5、装饰器模式;6、策略模式;7、观察者模式。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

369

2024.04.09

thinkphp和laravel哪个简单
thinkphp和laravel哪个简单

对于初学者来说,laravel 的入门门槛较低,更易上手,原因包括:1. 更简单的安装和配置;2. 丰富的文档和社区支持;3. 简洁易懂的语法和 api;4. 平缓的学习曲线。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

368

2024.04.10

laravel入门教程
laravel入门教程

本专题整合了laravel入门教程,想了解更多详细内容,请阅读专题下面的文章。

81

2025.08.05

laravel实战教程
laravel实战教程

本专题整合了laravel实战教程,阅读专题下面的文章了解更多详细内容。

64

2025.08.05

laravel面试题
laravel面试题

本专题整合了laravel面试题相关内容,阅读专题下面的文章了解更多详细内容。

67

2025.08.05

数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

676

2023.10.12

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.8万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 792人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号