This package integrates the Opensearch client to work seamlessly with your Laravel Eloquent Model.
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"
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
}
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();
https://opensearch.org/docs/latest/query-dsl/full-text/match/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\MatchOne::make('name', 'john doe');
https://opensearch.org/docs/latest/query-dsl/term/exists/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Exists::make('description');
https://opensearch.org/docs/latest/query-dsl/term/fuzzy/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Fuzzy::make('speaker', 'HALET');
https://opensearch.org/docs/latest/query-dsl/term/ids/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Ids::make([34229, 91296]);
https://opensearch.org/docs/latest/query-dsl/term/prefix/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Prefix::make('speaker', 'KING H');
https://opensearch.org/docs/latest/query-dsl/term/range/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Range::make('line_id', ['gte' => 10, 'lte' => 20]);
https://opensearch.org/docs/latest/query-dsl/term/regexp/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Regexp::make('play_name', '[a-zA-Z]amlet');
https://opensearch.org/docs/latest/query-dsl/term/wildcard/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Wildcard::make('speaker', 'H*Y');
https://opensearch.org/docs/latest/query-dsl/match-all/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\MatchAll::make();
https://opensearch.org/docs/latest/query-dsl/full-text/match-phrase-prefix/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\MatchPhrasePrefix::make('title', 'the rise');
https://opensearch.org/docs/latest/query-dsl/term/term/
\Codeart\OpensearchLaravel\Search\SearchQueries\Types\Term::make('id', 1234);
https://opensearch.org/docs/latest/aggregations/metric/average/
\Codeart\OpensearchLaravel\Aggregations\Types\Average::make('taxful_total_price');
https://opensearch.org/docs/latest/aggregations/metric/cardinality/
\Codeart\OpensearchLaravel\Aggregations\Types\Cardinality::make('products.product_id');
https://opensearch.org/docs/latest/aggregations/metric/maximum/
\Codeart\OpensearchLaravel\Aggregations\Types\Maximum::make('taxful_total_price');
https://opensearch.org/docs/latest/aggregations/metric/minimum/
\Codeart\OpensearchLaravel\Aggregations\Types\Minimum::make('taxful_total_price');
https://opensearch.org/docs/latest/aggregations/metric/percentile/
\Codeart\OpensearchLaravel\Aggregations\Types\Percentile::make('taxful_total_price');
https://opensearch.org/docs/latest/aggregations/metric/stats/
\Codeart\OpensearchLaravel\Aggregations\Types\Stats::make('taxful_total_price');
https://opensearch.org/docs/latest/aggregations/metric/sum/
\Codeart\OpensearchLaravel\Aggregations\Types\Sum::make('taxful_total_price');
https://opensearch.org/docs/latest/aggregations/bucket/terms/
\Codeart\OpensearchLaravel\Aggregations\Types\Terms::make('company.name', 100);
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.
We offer tools to help you work with Opensearch indices and documents.
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();
use App\Models\User;
User::opensearch()
->documents()
->createAll();
User::opensearch()
->documents()
->create($ids);
User::opensearch()
->documents()
->createOrUpdate($id);
User::opensearch()
->documents()
->delete($id);
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'));
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.
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();
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
}
This project is licensed under the MIT License - see the LICENSE file for details.