shabushabu / laravel-paradedb-search
将 ParadeDB 的 pg_search 扩展集成到 Laravel 中
Requires
- php: ^8.2
- illuminate/contracts: ^11.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^2.9
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^9.0
- pestphp/pest: ^2.34
- pestphp/pest-plugin-arch: ^2.7
- pestphp/pest-plugin-laravel: ^2.3
- pestphp/pest-plugin-type-coverage: ^2.8
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^1.1
- phpstan/phpstan-phpunit: ^1.3
- roave/security-advisories: dev-latest
- tpetry/laravel-postgresql-enhanced: ^0.39.0
- tpetry/laravel-query-expressions: ^1.3
Suggests
- tpetry/laravel-postgresql-enhanced: Adds vector operators to use in regular Eloquent where statements
- tpetry/laravel-query-expressions: Provides useful expressions for use in ParadeDB search queries
README
ParadeDB 搜索为 Laravel
将 ParadeDB 的 pg_search
Postgres 扩展集成到 Laravel 中
支持的最低版本
安装
注意
请注意,这是一个新包,尽管经过充分测试,但它应被视为预发布软件
在安装此包之前,您应安装并启用 pg_search 扩展。
然后您可以通过 composer 安装此包
composer require shabushabu/laravel-paradedb-search
您还可以发布配置文件
php artisan vendor:publish --tag="laravel-paradedb-search-config"
以下是发布配置文件的内容
return [ 'index_suffix' => '_idx', ];
用法
添加 bm25 索引
您想要可搜索的每个模型都需要相应的 bm25
索引。这些可以在迁移中生成,如下所示
use ShabuShabu\ParadeDB\Indices\Bm25; return new class extends Migration { public function up(): void { Schema::create('products', static function (Blueprint $table) { // all your product fields }); Bm25::index('products') ->addNumericFields(['amount']) ->addBooleanFields(['is_available']) ->addDateFields(['created_at', 'deleted_at']) ->addJsonFields(['options']) ->addTextFields([ 'name', 'currency', 'description' => [ 'tokenizer' => [ 'type' => 'default', ], ], ]) ->create(drop: true); } public function down(): void { Bm25::index('products')->drop(); } };
准备您的模型
只需将 Searchable
特性添加到您的模型中即可启用搜索
use Illuminate\Database\Eloquent\Model; use ShabuShabu\ParadeDB\Concerns\Searchable; class Product extends Model { use Searchable; // the rest of the model... }
ParadeQL
ParadeDB 搜索为 Laravel 附带 ParadeQL 的流畅构建器,这是一种简单的查询语言。
此构建器可以作为搜索 where
方法的一个条件传递,或者用于各种 ParadeDB 表达式。
基本查询
use ShabuShabu\ParadeDB\ParadeQL\Builder; Builder::make()->where('description', 'keyboard')->get(); // results in: description:keyboard
添加 IN 条件
Builder::make() ->where('description', ['keyboard', 'toy']) ->get(); // results in: description:IN [keyboard, toy]
添加 AND NOT 条件
Builder::make() ->where('category', 'electronics') ->whereNot('description', 'keyboard') ->get(); // results in: category:electronics AND NOT description:keyboard
增强条件
Builder::make()->where('description', 'keyboard', boost: 1)->get(); // results in: description:keyboard^1
应用 slop 操作符
Builder::make()->where('description', 'ergonomic keyboard', slop: 1)->get(); // results in: description:"ergonomic keyboard"~1
带有子条件的更复杂示例
Builder::make() ->where('description', ['keyboard', 'toy']) ->where( fn (Builder $builder) => $builder ->where('category', 'electronics') ->orWhere('tag', 'office') ) ->get(); // results in: description:IN [keyboard, toy] AND (category:electronics OR tag:office)
应用简单过滤器
use ShabuShabu\ParadeDB\ParadeQL\Operators\Filter; Builder::make()->whereFilter('rating', Filter::equals, 4)->get(); // results in: rating:4
应用布尔过滤器
use ShabuShabu\ParadeDB\ParadeQL\Operators\Filter; Builder::make()->whereFilter('is_available', '=', false)->get(); // results in: is_available:false
应用基本范围过滤器
use ShabuShabu\ParadeDB\ParadeQL\Operators\Filter; Builder::make()->whereFilter('rating', '>', 4)->get(); // results in: rating:>4
应用包含范围过滤器
use ShabuShabu\ParadeDB\ParadeQL\Operators\Range; Builder::make()->whereFilter('rating', Range::includeAll, [2, 5])->get(); // results in: rating:[2 TO 5]
应用排除范围过滤器
use ShabuShabu\ParadeDB\ParadeQL\Operators\Range; Builder::make()->whereFilter('rating', Range::excludeAll, [2, 5])->get(); // results in: rating:{2 TO 5}
ParadeDB 函数
对于更复杂的操作,将需要使用提供的某些 ParadeDB 函数,所有这些都有相应的查询表达式
获取所有记录
use ShabuShabu\ParadeDB\Query\Expressions\All; Product::search()->where(new All())->get();
获取所有记录
use ShabuShabu\ParadeDB\Query\Expressions\Blank; Product::search()->where(new Blank())->get();
增强查询
use ShabuShabu\ParadeDB\Query\Expressions\All; use ShabuShabu\ParadeDB\Query\Expressions\Boost; Product::search()->where(new Boost(new All(), 3.9))->get();
添加常数得分
use ShabuShabu\ParadeDB\Query\Expressions\All; use ShabuShabu\ParadeDB\Query\Expressions\ConstScore; Product::search()->where(new ConstScore(new All(), 3.9))->get();
执行析取最大查询
use ShabuShabu\ParadeDB\ParadeQL\Builder; use ShabuShabu\ParadeDB\Query\Expressions\DisjunctionMax; Product::search()->where( new DisjunctionMax(Builder::make()->where('description', 'keyboard')) )->get();
《DisjunctionMax》构造函数还接受查询数组,因此使用流畅接口可能更适合多个查询
Product::search()->where( DisjunctionMax::query() ->add(Builder::make()->where('description', 'keyboard')) ->add('description:blue') ->tieBreaker(1.2) )->get();
这还允许您有条件地添加查询
Product::search()->where( DisjunctionMax::query() ->add(Builder::make()->where('description', 'keyboard')) ->add('description:blue', when: false) )->get();
搜索模糊词
use ShabuShabu\ParadeDB\Query\Expressions\FuzzyTerm; Product::search()->where(new FuzzyTerm('description', 'keyboard'))->get();
突出显示搜索词
use ShabuShabu\ParadeDB\ParadeQL\Builder; use ShabuShabu\ParadeDB\Query\Expressions\Highlight; use ShabuShabu\ParadeDB\Query\Expressions\DisjunctionMax; Product::search() ->select(['*', new Highlight('id', 'name')]) ->where(new DisjunctionMax(Builder::make()->where('description', 'keyboard'))) ->get();
搜索短语
use ShabuShabu\ParadeDB\ParadeQL\Builder; use ShabuShabu\ParadeDB\Query\Expressions\Phrase; Product::search() ->where(new Phrase('description', ['robot', 'building', 'kits'])) ->get();
执行短语前缀查询
use ShabuShabu\ParadeDB\ParadeQL\Builder; use ShabuShabu\ParadeDB\Query\Expressions\PhrasePrefix; Product::search() ->where(new PhrasePrefix('description', ['robot', 'building', 'kits', 'am'])) ->get();
在给定范围内搜索
use ShabuShabu\ParadeDB\Query\Expressions\Range; use ShabuShabu\ParadeDB\Query\Expressions\Ranges\Int4; use ShabuShabu\ParadeDB\Query\Expressions\Ranges\Bounds; Product::search() ->stableSort() ->where(new Range('rating', new Int4(1, 3, Bounds::includeStartExcludeEnd))) ->get();
以下是支持的类型(所有类型都在 ShabuShabu\ParadeDB\Query\Expressions\Ranges
命名空间内),以及它们对应的 Postgres 类型
Int4::class;
或int4range
Int8::class;
或int8range
Numeric::class;
或numrange
Date::class;
或daterange
Timestamp::class;
或tsrange
TimestampTz::class;
或tstzrange
执行正则表达式查询
use ShabuShabu\ParadeDB\ParadeQL\Builder; use ShabuShabu\ParadeDB\Query\Expressions\Regex; Product::search() ->where(new Regex('description', '(team|kits|blabla)')) ->get();
搜索术语
use ShabuShabu\ParadeDB\ParadeQL\Builder; use ShabuShabu\ParadeDB\Query\Expressions\Term; Product::search() ->where(new Term('description', 'building')) ->get();
搜索术语集
use ShabuShabu\ParadeDB\ParadeQL\Builder; use ShabuShabu\ParadeDB\Query\Expressions\Term; use ShabuShabu\ParadeDB\Query\Expressions\TermSet; Product::search() ->where(new TermSet([ new Term('description', 'building'), new Term('description', 'things'), ])) ->get();
上述查询也可以以流畅的方式编写
Product::search()->where( TermSet::query() ->add(new Term('description', 'building')) ->add(new Term('description', 'things')) )->get();
《term》方法允许您有条件地添加术语
$when = false; Product::search()->where( TermSet::query()->add(new Term('description', 'things'), $when) )->get();
执行复杂布尔查询
use App\Models\Product; use ShabuShabu\ParadeDB\Query\Expressions\Range; use ShabuShabu\ParadeDB\Query\Expressions\Boolean; use ShabuShabu\ParadeDB\Query\Expressions\FuzzyTerm; use ShabuShabu\ParadeDB\Query\Expressions\Ranges\TimestampTz; Product::search() ->where(new Boolean( must: [ new Range('created_at', new TimestampTz(null, now())), ], should: [ new Boost(new FuzzyTerm('name', 'keyboard'), 2), new FuzzyTerm('description', 'keyboard'), ], mustNot: [ new Range('deleted_at', new TimestampTz(null, now())), ], )) ->get();
布尔查询也可以以流畅的方式构建
Product::search()->where( Boolean::query() ->must(new Range('created_at', new TimestampTz(null, now()))) ->should(new Boost(new FuzzyTerm('name', 'keyboard'), 2)) ->should(new FuzzyTerm('description', 'keyboard')) ->mustNot(new Range('deleted_at', new TimestampTz(null, now()))) )->get();
上述两个查询是相同的。流畅的方法允许您有条件地添加查询。
$when = false; Product::search()->where( Boolean::query() ->must(new Range('created_at', new TimestampTz(null, now()))) ->should(new Boost(new FuzzyTerm('name', 'keyboard'), 2), $when) )->get();
按排名排序
use ShabuShabu\ParadeDB\ParadeQL\Builder; use ShabuShabu\ParadeDB\Query\Expressions\Term; use ShabuShabu\ParadeDB\Query\Expressions\Rank; Product::search() ->addSelect(new Rank('id')) ->where(new Term('description', 'building')) ->get();
分页
还可以对结果进行分页。`paginate`和`simplePaginate`方法都使用了底层的`limit`和`offset`功能,因此性能将更优。
use App\Models\Product; use App\Models\Product; use ShabuShabu\ParadeDB\ParadeQL\Builder; Product::search() ->where(Builder::make()->where('description', 'keyboard')) ->paginate(20);
搜索参数
ParadeDB的`search`函数允许您设置各种参数以微调您的搜索。所有这些都可以在此设置。
use App\Models\Product; use App\Models\Product; use ShabuShabu\ParadeDB\ParadeQL\Builder; Product::search() ->where(Builder::make()->where('description', 'keyboard')) ->alias('alias') ->stableSort() ->limit(12) ->offset(24) ->get();
混合搜索
每当提供相似性查询时,该包将自动执行混合搜索。请注意,仍需要ParadeDB查询!
use App\Models\Product; use ShabuShabu\ParadeDB\ParadeQL\Builder; use ShabuShabu\ParadeDB\Query\Expressions\Distance; use ShabuShabu\ParadeDB\Query\Expressions\Similarity; Product::search() ->where(Builder::make()->where('description', 'keyboard')) ->where(new Similarity('embedding', Distance::l2, [1, 2, 3])) ->get();
搜索参数
与全文搜索类似,混合搜索也有可以设置的参数
Product::search() ->where(Builder::make()->where('description', 'keyboard')) ->where(new Similarity('embedding', Distance::l2, [1, 2, 3])) ->bm25Limit(100) ->bm25Weight(0.5) ->similarityLimit(100) ->similarityWeight(0.5) ->get();
修改底层查询
有时,需要修改基本查询,例如为了预加载某些关系。可以这样完成
use App\Models\Product; use Illuminate\Database\Eloquent; use ShabuShabu\ParadeDB\ParadeQL\Builder; Product::search() ->modifyQueryUsing(fn (Eloquent\Builder $builder) => $builder->with('tags')) ->where(Builder::make()->where('description', 'keyboard')) ->get();
注意事项
虽然可以将ParadeDB查询与常规Eloquent查询结合起来,但这将产生一些性能损失。
为了获得最佳性能,建议让`bm25`索引尽可能多地执行工作,因此,尽可能使用内置过滤器以及limit和offset!
获取帮助
如果您的相关问题与该包有关,请使用问题和讨论!
如果您的相关问题与`pg_search`有关,请在ParadeDB仓库中创建一个讨论。
为了使其更简单一些,您可以使用此包附带的所有`paradedb:help`命令
php artisan paradedb:help
请注意,此命令只是`paradedb.help()`函数的一个实现。请明智地使用此命令!
测试
测试需要PostgreSQL数据库,可以通过运行以下脚本来轻松设置
composer testdb
警告
请注意,`pg_search`和`pgvector`扩展都需要已经可用。
然后运行测试
composer test
或者使用测试覆盖率
composer test-coverage
或者使用类型覆盖率
composer type-coverage
或者运行PHPStan
composer analyse
ParadeDB测试表
还有一个命令允许您创建和删除内置测试表
php artisan paradedb:test-table create
变更日志
有关最近更改的更多信息,请参阅变更日志。
贡献
有关详细信息,请参阅贡献。
安全漏洞
有关如何报告安全漏洞的详细信息,请参阅我们的安全策略。
鸣谢
- Taylor Otwell 为创建Laravel
- ParadeDB 为创建`pg_search`
- ShabuShabu
- 所有贡献者
免责声明
这是一个第三方包,ShabuShabu与Laravel或ParadeDB无关。
许可协议
MIT许可(MIT)。有关更多信息,请参阅许可文件。