codeartmk / opensearch-laravel
This package integrates the Opensearch client to work seamlessly with your Laravel Eloquent Model.
Installs: 810
Dependents: 0
Suggesters: 0
Security: 0
Stars: 12
Watchers: 1
Forks: 2
Open Issues: 0
pkg:composer/codeartmk/opensearch-laravel
Requires
- php: >=8.1
- opensearch-project/opensearch-php: ^2.2
Requires (Dev)
- orchestra/testbench: ^8.0
- phpunit/phpunit: ^10.5
This package is auto-updated.
Last update: 2025-10-12 11:00:05 UTC
README
Overview
This package integrates the Opensearch client to work seamlessly with your Laravel Eloquent Model.
Installation
To install the Laravel OpenSearch Plugin, use Composer:
composer require codeartmk/opensearch-laravel
and then export the configuration with
php artisan vendor:publish --provider="Codeart\OpensearchLaravel\OpenSearchServiceProvider" --tag="config"
Basic usage
Setting up the model
Your models will need to implement the Codeart\OpensearchLaravel\OpenSearchable interface, and include the trait
Codeart\OpensearchLaravel\Traits\HasOpenSearchDocuments.
use Codeart\OpensearchLaravel\OpenSearchable; use Codeart\OpensearchLaravel\Traits\HasOpenSearchDocuments; class User extends Authenticatable implements OpenSearchable { use HasApiTokens, HasFactory, Notifiable, HasOpenSearchDocuments; //rest of the model }
You can override the 3 functions openSearchMapping, openSearchArray, and openSearchIndexName to customize your
mapping, the information stored and the index name.
For mapping options look at OpenSearch mapping documentation.
use Codeart\OpensearchLaravel\OpenSearchable; use Codeart\OpensearchLaravel\Traits\HasOpenSearchDocuments; class User extends Authenticatable implements OpenSearchable { use HasApiTokens, HasFactory, Notifiable, HasOpenSearchDocuments; public function openSearchMapping(): array { return [ "mapping" => [ "properties" => [ "id" => [ "type" => "integer" ], "first_name" => [ "type" => "text" ], "last_name" => [ "type" => "text" ], "name" => [ "type" => "text" ], "email" => [ "type" => "keyword" ], //... ] ] ]; } public function openSearchArray(): array { return [ "id" => $this->id, "first_name" => $this->first_name, "last_name" => $this->last_name, "name" => $this->first_name + " " + $this->last_name, "email" => $this->email, //... ]; } public function openSearchIndexName(): string { return "users"; } //rest of the model }
Building queries and aggregations
Once the model is ready you can start building your queries and aggregation through the opensearch method on the class:
use App\Models\User; User::opensearch() ->builder() ->search([ Query::make([ BoolQuery::make([ Must::make([ MatchOne::make("first_name", "John"), BoolQuery::make([ Should::make([ MatchOne::make('email', 'johndoe@example.com'), MatchOne::make('last_name', 'johndoe@example.com'), ]), 'minimum_should_match' => 1 ]) ]), ]) ]), Sort::make([ 'id' => 'desc', ]) ]) ->aggregations([ Aggregation::make( name: "user_names", aggregationType: Terms::make(field: 'name', size: 10000), aggregation: Aggregation::make( name: 'bucket_truncate', aggregationType: BucketSort::make('_key') ) ), ]) ->get();
Supported Query DSL queries:
Match
https://opensearch.org/docs/latest/query-dsl/full-text/match/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\MatchOne::make('name', 'john doe');
Exists
https://opensearch.org/docs/latest/query-dsl/term/exists/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Exists::make('description');
Fuzzy
https://opensearch.org/docs/latest/query-dsl/term/fuzzy/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Fuzzy::make('speaker', 'HALET');
IDs
https://opensearch.org/docs/latest/query-dsl/term/ids/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Ids::make([34229, 91296]);
Prefix
https://opensearch.org/docs/latest/query-dsl/term/prefix/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Prefix::make('speaker', 'KING H');
Range
https://opensearch.org/docs/latest/query-dsl/term/range/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Range::make('line_id', ['gte' => 10, 'lte' => 20]);
Regexp
https://opensearch.org/docs/latest/query-dsl/term/regexp/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Regexp::make('play_name', '[a-zA-Z]amlet');
Wildcard
https://opensearch.org/docs/latest/query-dsl/term/wildcard/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Wildcard::make('speaker', 'H*Y');
Match All
https://opensearch.org/docs/latest/query-dsl/match-all/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\MatchAll::make();
Match Phrase Prefix
https://opensearch.org/docs/latest/query-dsl/full-text/match-phrase-prefix/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\MatchPhrasePrefix::make('title', 'the rise');
Term
https://opensearch.org/docs/latest/query-dsl/term/term/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Term::make('id', 1234);
Supported Aggregations
Average
https://opensearch.org/docs/latest/aggregations/metric/average/
\Codeart\OpensearchLaravel\Aggregations\Types\Average::make('taxful_total_price');
Cardinality
https://opensearch.org/docs/latest/aggregations/metric/cardinality/
\Codeart\OpensearchLaravel\Aggregations\Types\Cardinality::make('products.product_id');
Maximum
https://opensearch.org/docs/latest/aggregations/metric/maximum/
\Codeart\OpensearchLaravel\Aggregations\Types\Maximum::make('taxful_total_price');
Minimum
https://opensearch.org/docs/latest/aggregations/metric/minimum/
\Codeart\OpensearchLaravel\Aggregations\Types\Minimum::make('taxful_total_price');
Percentile
https://opensearch.org/docs/latest/aggregations/metric/percentile/
\Codeart\OpensearchLaravel\Aggregations\Types\Percentile::make('taxful_total_price');
Stats
https://opensearch.org/docs/latest/aggregations/metric/stats/
\Codeart\OpensearchLaravel\Aggregations\Types\Stats::make('taxful_total_price');
Sum
https://opensearch.org/docs/latest/aggregations/metric/sum/
\Codeart\OpensearchLaravel\Aggregations\Types\Sum::make('taxful_total_price');
Terms
https://opensearch.org/docs/latest/aggregations/bucket/terms/
\Codeart\OpensearchLaravel\Aggregations\Types\Terms::make('company.name', 100);
Bucket Sort
https://opensearch.org/docs/latest/aggregations/pipeline-agg/#bucket_sort
\Codeart\OpensearchLaravel\Aggregations\Types\BucketSort::make('company_id')
We plan to support more in the feature.
Working with indices and documents
We offer tools to help you work with Opensearch indices and documents.
Indices
We have the methods create, exists, and delete currently.
The optional $configuration parameter in the create method allows you to customize your
settings
for your index.
use App\Models\User; User::opensearch() ->indices() ->create($configuration = []); User::opensearch() ->indices() ->delete(); User::opensearch() ->indices() ->exists();
Documents
use App\Models\User; User::opensearch() ->documents() ->createAll(); User::opensearch() ->documents() ->create($ids); User::opensearch() ->documents() ->createOrUpdate($id); User::opensearch() ->documents() ->delete($id);
Lazy Loading Relationship
The methods createAll, create, and createOrUpdate all accept a function as a second parameter to allow you to lazy
load your relationship when creating documents.
use App\Models\User; User::opensearch() ->documents() ->create($ids, fn($query) => $query->with('relationship'));
Extending the functionality
If we've missed a search query you need or an aggregation you need, you can easily implement your own and integrate it to work our core functionality.
Search Query
Create a custom class and implement the SearchQueryType and OpenSearchQuery interfaces.
If you were to implement the Query String query
it would look like the following:
use Codeart\OpensearchLaravel\Interfaces\OpenSearchQuery; use Codeart\OpensearchLaravel\Search\SearchQueries\Types\SearchQueryType; class MyCustomQuery implements OpenSearchQuery, SearchQueryType { public function __construct( private readonly string $query ) {} public static function make(string $query) { return self($query); } public function toOpenSearchQuery() : array{ return [ 'query_string' => [ 'query' => $query ] ]; } }
and then just call it.
use App\Models\User; use MyNamespace\MyCustomQuery; User::opensearch() ->builder() ->search([ Query::make([ MyCustomQuery::make('the wind AND (rises OR rising)') ]), ]) ->get();
Aggregations
You can achieve the same for aggregations but instead of SearchQueryType you need to implement the
AggregationType inteface.
use Codeart\OpensearchLaravel\Interfaces\OpenSearchQuery; use Codeart\OpensearchLaravel\Aggregations\Types\AggregationType; class MyCustomAggregation implements OpenSearchQuery, AggregationType { //aggregation logic }
Contact Us
License
This project is licensed under the MIT License - see the LICENSE file for details.