illuma-law / laravel-hybrid-search
Portable Full-Text Search (FTS) schema macros and the Reciprocal Rank Fusion (RRF) algorithm.
Package info
github.com/eloquage/laravel-hybrid-search
pkg:composer/illuma-law/laravel-hybrid-search
Fund package maintenance!
Requires
- php: ^8.3
- illuminate/contracts: ^11.0||^12.0||^13.0
- illuminate/database: ^11.0||^12.0||^13.0
- illuminate/support: ^11.0||^12.0||^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- mrpunyapal/peststan: ^0.2.12
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^10.1
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-health: ^1.39
- spatie/laravel-ray: ^1.35
Suggests
- spatie/laravel-health: Required to use the ScoutEngineCheck health probe.
Provides
None
Conflicts
None
Replaces
None
README
Portable full-text search macros and Reciprocal Rank Fusion (RRF) for Laravel. Use the same query API across PostgreSQL, MySQL, SQL Server, and SQLite, then combine ranked results from separate search systems.
Requires PHP 8.3+ and Laravel 11, 12, or 13.
Install
composer require illuma-law/laravel-hybrid-search
Create and query a full-text index
The hybridFullText migration macro uses native full-text indexes on
PostgreSQL and MySQL. SQLite uses FTS5 with an external-content table and
triggers, and expects an integer id primary key. SQL Server requires you to
create a full-text catalog and index manually.
use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; Schema::table('articles', function (Blueprint $table): void { $table->hybridFullText(['title', 'body'], 'articles_search'); });
Query with whereHybridFullText on a query builder or Eloquent model:
$articles = Article::query() ->whereHybridFullText(['title', 'body'], 'laravel macros') ->limit(20) ->get(); // Exclude matching rows: $otherArticles = Article::query() ->whereHybridFullText('title', 'deprecated', not: true) ->get();
Use $table->dropHybridFullText('articles_search') in the rollback migration.
Combine ranked result lists
RRF combines ranked IDs from sources such as keyword and vector search. This package does not generate embeddings or run vector searches; pass it the ranked results from your search providers.
use IllumaLaw\HybridSearch\ReciprocalRankFusion; $scores = ReciprocalRankFusion::combine([ 'keyword' => collect([12, 8, 3]), 'vector' => collect([8, 5, 12]), ]); $rankedIds = $scores->keys(); // IDs sorted by descending RRF score
The default RRF constant is 60; pass k: to override it.
Optional Scout helpers
Use EnsuresScoutKeyIsString when a Scout engine requires string keys. The
optional ScoutEngineCheck requires spatie/laravel-health:
composer require spatie/laravel-health
use IllumaLaw\HybridSearch\HealthChecks\ScoutEngineCheck; use Spatie\Health\Facades\Health; Health::checks([ScoutEngineCheck::new()]);
The check supports Meilisearch, Typesense, and Algolia; local Scout drivers are skipped.
Test
composer test
composer analyse
vendor/bin/pint --test
MIT licensed. See LICENSE.
