shabushabu/laravel-paradedb-search

将 ParadeDB 的 pg_search 扩展集成到 Laravel 中

v0.6.0 2024-06-19 06:28 UTC

This package is auto-updated.

Last update: 2024-09-19 11:08:56 UTC


README

ParadeDB Search for Laravel

ParadeDB 搜索为 Laravel

Latest Version on Packagist Total Downloads

将 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

变更日志

有关最近更改的更多信息,请参阅变更日志

贡献

有关详细信息,请参阅贡献

安全漏洞

有关如何报告安全漏洞的详细信息,请参阅我们的安全策略

鸣谢

免责声明

这是一个第三方包,ShabuShabu与Laravel或ParadeDB无关。

许可协议

MIT许可(MIT)。有关更多信息,请参阅许可文件