[扩展推荐] 为 Laravel Eloquent 提供搜索支持

file

在这个系列的第一部分 https://github.com/jarektkaczyk/eloquence – 这个包允许以更加简单的管理方式来使用 Eloquent 模型 - 接下来我将向你介绍 Builder 类的可搜索特性。

假设一个拥有简单好友关系的应用:

// 用户模型

// 多对多关联
public function friends()
{
   return $this->belongsToMany(static::class, 'friends', 'user_id', 'friend_id');
}

// 1-1 relation
public function profile()
{
   return $this->hasOne(Profile::class);
}

一个简单的基于用户为核心的表 usersfriends 表作为好友多对多关联表,这对于演示来说是足够的。 在用户表中我们只存储邮箱和用户名,在用户简介表 profiles 中存储用户的真实数据比如用户的名字、姓氏(first_name, last_name)等。

显然密码、时间戳等其他相关的字段不是我们现在应该关心的内容。

现在, 为了找到一个人,我们可以使用几个字段的组合:users.username, users.email, profiles.first_name, profiles.last_name, friends.first_name, friends.last_name

以下是原始的 Eloquent 做法::

$name = strtolower(Input::get('query'));

$matchingUsers = User::where(function ($q) use ($name) {
      $q->where('email', 'like', '%'.str_replace(' ', '', $name).'%')
        ->orWhere('username', 'like', "%{$name}%")
        ->orWhereHas('profile', function ($q) {
          $q->where(function ($q) {
            $q->where('first_name', 'like', "%{$name}%")
              ->orWhere('last_name', 'like', "%{$name}%");
        });
      });
    })->get();

它很简单但是缺乏关键的搜索元素 - 相关性分数,也使得搜索朋友行不通。

像这样的查询返回分数需要一些计算,但是很显现,我们没有必要再创造一个谷歌哈?

不过,理论上我们喜欢这样的方式:

$name = 'john doe';

$matchingUsers = User::search($name, [
    'profile.last_name' => 20,
    'email' => 10,
    'username' => 10,
    'profile.first_name' => 5,
    'friends.username' => 2,
    'friends.email' => 2,
    'friends.profile.first_name' => 1,
    'friends.profile.last_name' => 1,
  ])->get()

//如果这些字段不轻易变动,那么在模型中定义下它们:
protected $searchableColumns = [
    'profile.last_name' => 20,
    'email' => 10,
    'username' => 10,
    'profile.first_name' => 5,
    'friends.username' => 2,
    'friends.email' => 2,
    'friends.profile.first_name' => 1,
    'friends.profile.last_name' => 1,
];

//然后简单地调用
User::search($name)->get()

这些列都是定义在模型中的普通关联映射,只需要这些。每个列对应的数字是它的权重,我们通过分数来定义它们的重要性。

Eloquence\Builder 这个包的工作原理是自动地加入关联表格,添加一些履行条款并且通过关联搜索排序结果。

这个功能和得分算法的创意都是基于这个包 https://github.com/nicolaslopezj/searchable ,但它更加灵活易于使用,更重要的是速度提高了四倍(甚至更高,实际依赖查询中附加的 where 子句)

通过下面几个例子,你可以知道怎么使用这种方式来搜索。这个搜索方式同样会提升搜索速度 – 全文搜索不会使用索引,所以在大表或者多个连接表进行搜索时会变的很慢。

假如你的需求是这样,你想禁用掉全文索引,并且使用右侧通配符 ( word *) 来代替全文索引。

// 全文搜索 + 指定字段搜索权重:
User::search('john doe', ['email' => 10, 'profile.name' => 20, 'friends.profile.name' => 5])->take(10)->get()

// 全文搜索默认的字段:
User::search('"going to LA"')->get()

// 指定搜索
User::search('"going to LA"', $fulltext = false)->get()

// 通配符搜索
User::search(['going to *', '*LA*', '*NY*'], $fulltext = false)->get()

二楞徐的闲谈杂鱼

原文地址:https://softonsofa.com/laravel-searchabl...

译文地址:https://learnku.com/laravel/t/13041/exte...

本帖已被设为精华帖!
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 1
eiomi

:+1:

6个月前

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!