whitecube / laravel-search-builder
为 Laravel 构建快速、索引友好的搜索查询的包
Requires
- laravel/framework: ^9.0|^10.0|^11.0
- staudenmeir/laravel-cte: ^1.0
Requires (Dev)
- laravel/pint: ^1.8
- orchestra/testbench: ^8.5
- pestphp/pest: ^2.5
README
为 Laravel 构建快速、索引友好的搜索查询的包。
它做什么?
此包的目的是允许您构建带有分数的多条件搜索查询,并利用覆盖索引来实现超快速度。这意味着简单地使用此包并不足以做到一切——您需要有一个精心设计的数据库,并为您的搜索设计了适当的索引,才能获得良好的结果。要了解更多关于这个主题的信息,我们建议您观看免费的 PlanetScale MySQL for Developers 课程。
安装
composer require whitecube/laravel-search-builder
如何构建您的查询
为了使您的搜索查询非常快速,搜索构建器会将所有条件打包在一个子查询中,该子查询旨在尽可能多地命中覆盖索引,从而构建一个只包含相关模型的 ID(以及一个分数,稍后会有更多介绍)的聚合表。然后,将使用内部连接来使用此聚合表筛选实际表。这意味着您的搜索逻辑的处理完全在您的索引上完成,而整个表只会在最后访问,这极大地加快了整个过程。
但是,该包无法检测您的数据库结构,因此创建正确索引并确保您的搜索条件查询不会访问主表数据是您的责任。
以下是一个示例,说明我们想要实现的内容,以原始 SQL 为例。假设我们有一个产品表,我们想要通过参考和名称搜索它,并将参考放在名称之前
with id_and_total_score as ( select id, sum(score) as score from ( -- This query makes use of a covering index on the ref column select id, 100 as score from products where ref = 'SEARCH_STRING' union all -- This query makes use of a covering index on the name column select id, 50 as score from products where name = 'SEARCH_STRING' ) as ids_and_scores group by id ) select * from products inner join id_and_total_score on id_and_total_score.id = products.id order by score desc;
搜索构建器实例
您可以通过传递要搜索的模型来获取搜索构建器实例。
use \App\Models\Product; use \Whitecube\SearchBuilder\SearchBuilder; $builder = new SearchBuilder(Product::class); // You can also pass it an instance of your model
或者,如果您的模型使用了 HasSearchBuilder
特性,您可以通过这种方式轻松获取搜索构建器实例,这允许您在之后干净地链接条件方法。
use Whitecube\SearchBuilder\HasSearchBuilder; class Product extends Model { use HasSearchBuilder; }
$builder = Product::searchBuilder();
定义搜索条件
一旦您有了搜索构建器实例,您就可以通过将 Eloquent 构建器实例传递给 search
方法来使用它来定义您的搜索条件。
Product::searchBuilder() ->search(Product::select('id')->where('ref', 'SEARCH_STRING'), score: 100) ->search(Product::select('id')->where('name', 'SEARCH_STRING'), score: 50);
分数是可选的,如果缺失,将自动计算,使用定义条件的顺序,最高分数在最上面。
Product::searchBuilder() ->search(Product::select('id')->where('ref', 'SEARCH_STRING'), score: 100) // score = 100 ->search(Product::select('id')->where('name', 'SEARCH_STRING')) // score = 3 ->search(Product::select('id')->where('description', 'SEARCH_STRING')) // score = 2 ->search(Product::select('id')->where('content', 'SEARCH_STRING')); // score = 1
您可以轻松地在相关表上搜索。请记住,只选择引用您搜索的表 ID 的列。
Product::searchBuilder() // Search on a related table ->search(Lot::select('product_id')->where('barcode', 'SEARCH_STRING')) // Search on a relation of a related table ->search(Lot::select('product_id')->whereHas('delivery', function ($query) { $query->where('address', 'SEARCH_STRING'); }))
如果您希望将搜索词分割为空格、破折号、点和中划线,并对每个词进行单独的查询,您可以调用 splitTerms
方法。
$terms = 'foo bar baz'; Product::searchBuilder() ->splitTerms($terms, function (SearchBuilder $searchBuilder, string $term) { // Called once with $term = foo, once with $term = bar, and once with $term = baz return $searchBuilder->search(Product::select('id')->where('ref', $term)); });
获取结果
在定义了条件之后,您可以调用 get
方法来获取结果的集合。
$results = Product::searchBuilder() ->search(Product::select('id')->where('ref', 'SEARCH_STRING'), score: 100) ->search(Product::select('id')->where('name', 'SEARCH_STRING'), score: 50) ->get();
或者,如果您需要自己进行更多查询处理,您可以获取查询构建器实例。
$query = Product::searchBuilder() ->search(Product::select('id')->where('ref', 'SEARCH_STRING'), score: 100) ->search(Product::select('id')->where('name', 'SEARCH_STRING'), score: 50) ->getQuery();
💖 赞助
如果您在生产应用程序中依赖此包,请考虑 赞助我们!这是帮助我们继续做我们热爱的事情:制作优秀的开源软件的最佳方式。
贡献
欢迎提出更改建议、请求新功能或自行修复错误。我们相信还有很多改进空间,我们非常乐意合并有价值的pull请求。
谢谢!
单元测试
在添加新功能或修复错误时,请添加相应的单元测试。当前的测试集有限,但每个添加的单元测试都将提高包的质量。
通过调用./vendor/bin/pest
运行测试套件。
用❤️为开源社区制作
在Whitecube(Whitecube),我们每天工作中大量使用开源软件。所以当我们有机会回馈时,我们非常兴奋!
我们希望您会喜欢我们的小贡献,如果您在项目中发现它有用,我们非常乐意听到您的反馈。关注我们的Twitter获取更多更新!