Installation
composer require directorytree/opensearch-client
Publish the config file (if needed):
php artisan vendor:publish --provider="DirectoryTree\OpenSearchClient\OpenSearchServiceProvider"
Configuration
Edit .env with your OpenSearch cluster details:
OPENSEARCH_HOST=http://localhost:9200
OPENSEARCH_USERNAME=admin
OPENSEARCH_PASSWORD=admin
First Use Case Inject the client into a controller or service:
use DirectoryTree\OpenSearchClient\Facades\OpenSearch;
public function index()
{
$response = OpenSearch::get('products/_search', [
'query' => ['match_all' => new \stdClass()]
]);
return $response->getBody();
}
Key Files to Review
config/opensearch.php (default settings)vendor/directorytree/opensearch-client/src/Facades/OpenSearch.php (facade usage)vendor/directorytree/opensearch-client/src/OpenSearchManager.php (core logic)Search Operations
// Basic search
$result = OpenSearch::search('products', [
'query' => ['match' => ['name' => 'laptop']]
]);
// Paginated results
$result = OpenSearch::search('products', [
'from' => 0,
'size' => 10,
'query' => ['match_all' => new \stdClass()]
]);
Index Management
// Create index
OpenSearch::indices()->create(['index' => 'products']);
// Update mappings
OpenSearch::indices()->putMapping([
'index' => 'products',
'body' => ['properties' => ['name' => ['type' => 'text']]]
]);
Document CRUD
// Index a document
OpenSearch::index('products', '1', ['name' => 'Laptop', 'price' => 999]);
// Update a document
OpenSearch::update('products', '1', ['doc' => ['price' => 899]]);
// Delete a document
OpenSearch::delete('products', '1');
Bulk Operations
$operations = [
['index' => ['_index' => 'products', '_id' => '1']],
['name' => 'Laptop'],
['index' => ['_index' => 'products', '_id' => '2']],
['name' => 'Phone']
];
OpenSearch::bulk($operations);
scout for search-as-you-type:
use DirectoryTree\OpenSearchClient\Facades\OpenSearch;
use Laravel\Scout\Builder;
Builder::macro('opensearch', function ($query) {
return OpenSearch::search('products', [
'query' => ['match' => ['name' => $query]]
]);
});
use DirectoryTree\OpenSearchClient\Facades\OpenSearch;
use Illuminate\Support\Facades\Queue;
Queue::push(function () {
OpenSearch::bulk($largeDatasetOperations);
});
OpenSearch::middleware(function ($response) {
if ($response->getStatusCode() >= 400) {
throw new \Exception('OpenSearch error: ' . $response->getBody());
}
return $response;
});
Authentication Issues
OPENSEARCH_USERNAME/OPENSEARCH_PASSWORD are set if using security.OPENSEARCH_HOST with the full endpoint (e.g., https://search-domain.us-east-1.es.amazonaws.com).SSL/TLS Errors
config/opensearch.php:
'ssl' => [
'ca' => storage_path('certs/root-ca.pem'),
'verify_peer' => true,
],
Rate Limiting
use DirectoryTree\OpenSearchClient\Facades\OpenSearch;
$maxRetries = 3;
for ($i = 0; $i < $maxRetries; $i++) {
try {
$response = OpenSearch::get('products/_search');
break;
} catch (\Exception $e) {
if ($i === $maxRetries - 1) throw $e;
sleep(1);
}
}
Index Not Found
if (!OpenSearch::indices()->exists(['index' => 'products'])) {
OpenSearch::indices()->create(['index' => 'products']);
}
Enable Logging
Add to config/opensearch.php:
'logger' => [
'enabled' => true,
'channel' => 'single',
],
Then configure channels in config/logging.php to log to a file or monitor.
Raw Responses Inspect raw responses for debugging:
$response = OpenSearch::get('products/_search');
\Log::debug($response->getBody());
Custom Clients
Bind additional clients in AppServiceProvider:
public function register()
{
$this->app->singleton('opensearch.secondary', function () {
return OpenSearch::createClient([
'hosts' => ['https://secondary-cluster:9200'],
'auth' => ['admin', 'password']
]);
});
}
Query Builders Create reusable query builders:
class ProductSearchBuilder
{
public static function build($query)
{
return [
'query' => [
'bool' => [
'must' => [
['match' => ['name' => $query]],
['range' => ['price' => ['gte' => 100]]]
]
]
]
];
}
}
Event Listeners Listen for OpenSearch events (e.g., index creation):
OpenSearch::listen('index.created', function ($index) {
\Log::info("Index {$index} created.");
});
config/opensearch.php:
'timeout' => 30, // seconds
'connect_timeout' => 5,
How can I help you explore Laravel packages today?