codeartmk / opensearch-laravel
This package integrates the Opensearch client to work seamlessly with your Laravel Eloquent Model.
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: 2024-11-12 09:04:38 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.