Installation:
composer require babenkoivan/elastic-adapter
Requires elasticsearch/elasticsearch (≥7.0) as a dependency.
Basic Configuration:
use Babenkoivan\ElasticAdapter\ElasticAdapter;
$adapter = new ElasticAdapter([
'hosts' => ['http://localhost:9200'],
'index' => 'your_index_name',
]);
First Use Case:
// Index a document
$adapter->index([
'id' => 'doc1',
'title' => 'Sample Document',
'content' => 'This is a test document.',
]);
// Search documents
$results = $adapter->search(['match' => ['title' => 'Sample']]);
ElasticAdapter class: Core functionality for CRUD operations.ElasticSearchBuilder: For complex queries (see usage examples).ElasticAdapterException: Handle errors gracefully.CRUD Operations:
// Create/Update
$adapter->index($document, $id); // $id optional (auto-generated if omitted)
// Read
$document = $adapter->get('doc1');
// Update (partial)
$adapter->update('doc1', ['status' => 'published']);
// Delete
$adapter->delete('doc1');
Search Patterns:
// Basic match query
$results = $adapter->search(['match' => ['title' => 'Laravel']]);
// Bool query with filters
$results = $adapter->search([
'bool' => [
'must' => ['match' => ['content' => 'tutorial']],
'filter' => ['term' => ['status' => 'published']],
],
]);
// Pagination
$results = $adapter->search($query, ['from' => 0, 'size' => 10]);
Bulk Operations:
$adapter->bulk([
['index' => ['_id' => '1']],
['title' => 'Bulk Doc 1'],
['index' => ['_id' => '2']],
['title' => 'Bulk Doc 2'],
]);
Service Provider Binding:
// config/app.php
'providers' => [
\Babenkoivan\ElasticAdapter\ElasticAdapterServiceProvider::class,
],
// config/elastic.php
'default' => 'elasticsearch',
'connections' => [
'elasticsearch' => [
'hosts' => ['http://localhost:9200'],
'index' => 'app_documents',
],
],
Facade Usage:
use Illuminate\Support\Facades\Elastic;
Elastic::index(['title' => 'Hello', 'content' => 'World']);
Eloquent Model Integration (Custom):
use Babenkoivan\ElasticAdapter\Eloquent\Scopes\ElasticScope;
class Post extends Model
{
public function scopeSearch($query, $searchTerm)
{
return $query->addGlobalScope(new ElasticScope(function ($model, $builder) use ($searchTerm) {
$results = Elastic::search(['match' => ['title' => $searchTerm]]);
return $builder->whereIn('id', array_pluck($results['hits'], 'id'));
}));
}
}
Event Listeners:
// Sync Eloquent model to Elasticsearch on save
Post::saved(function ($post) {
Elastic::index($post->toArray(), $post->id);
});
Index Mapping Conflicts:
tags), Elasticsearch may auto-detect mappings. To avoid surprises, define explicit mappings upfront:
$adapter->putMapping([
'properties' => [
'title' => ['type' => 'text', 'analyzer' => 'english'],
'tags' => ['type' => 'keyword'],
],
]);
Idempotent Operations:
index() will overwrite documents if the _id exists. Use create() (if supported) or check existence first:
if (!$adapter->exists('doc1')) {
$adapter->index($document, 'doc1');
}
Connection Timeouts:
$adapter = new ElasticAdapter([
'hosts' => ['http://localhost:9200'],
'timeout' => 30, // seconds
]);
Bulk Operation Limits:
$chunkSize = 500;
foreach (array_chunk($documents, $chunkSize) as $chunk) {
$adapter->bulk($chunk);
}
Enable Logging:
$adapter = new ElasticAdapter([
'hosts' => ['http://localhost:9200'],
'logger' => new \Monolog\Logger('elasticsearch'),
]);
Or use Laravel’s log:
'logger' => \Illuminate\Support\Facades\Log::class,
Raw Response Inspection:
$response = $adapter->search($query, [], true); // $raw = true
dd($response);
Common Errors:
Elasticsearch\Common\Exceptions\Missing404Exception: Document/index not found. Verify IDs/indices.Elasticsearch\Common\Exceptions\BadRequest400Exception: Invalid query syntax. Use Elasticsearch Query DSL Analyzer to debug.Use ElasticSearchBuilder for Complex Queries:
$query = (new ElasticSearchBuilder())
->match('title', 'Laravel')
->boolShould([
['term' => ['status' => 'published']],
['range' => ['price' => ['gte' => 10]]],
])
->getQuery();
$results = $adapter->search($query);
Leverage Laravel’s Caching: Cache frequent search results:
$cacheKey = "elastic_results_{$searchTerm}";
$results = Cache::remember($cacheKey, now()->addHours(1), function () use ($adapter, $searchTerm) {
return $adapter->search(['match' => ['title' => $searchTerm]]);
});
Async Indexing: Use Laravel Queues for non-critical indexing:
Post::saved(function ($post) {
dispatch(new IndexPostInElastic($post));
});
Schema Validation: Validate documents before indexing:
use Illuminate\Validation\Validator;
$validator = Validator::make($document, [
'title' => 'required|string|max:255',
'content' => 'required|string',
]);
if ($validator->fails()) {
throw new \InvalidArgumentException($validator->errors()->first());
}
Alias Management: Use aliases for zero-downtime reindexing:
$adapter->createAlias('alias_name', 'old_index');
$adapter->createAlias('alias_name', 'new_index', ['is_write_index' => true]);
How can I help you explore Laravel packages today?