ongr/elasticsearch-dsl
Object-oriented Elasticsearch query builder for PHP. Build searches, filters, aggregations and more with a DSL, then export to arrays for elasticsearch-php or ONGR ElasticsearchBundle. Supports Elasticsearch 5/6/7 via versioned releases.
Installation:
composer require ongr/elasticsearch-dsl elasticsearch/elasticsearch
elasticsearch/elasticsearch as a dependency.Basic Setup:
use ONGR\ElasticsearchDSL\Search;
use ONGR\ElasticsearchDSL\Query\MatchAllQuery;
use Elasticsearch\ClientBuilder;
$client = ClientBuilder::create()->build();
$search = new Search();
$search->addQuery(new MatchAllQuery());
$params = [
'index' => 'your_index_name',
'body' => $search->toArray(),
];
$response = $client->search($params);
First Use Case:
$search = new Search();
$search->addQuery(new MatchAllQuery());
$search = new Search();
$search->addQuery(new TermQuery('title', 'Laravel'));
ONGR\ElasticsearchDSL\Query namespace for query types (e.g., TermQuery, BoolQuery, FunctionScoreQuery).ONGR\ElasticsearchDSL\Aggregation namespace for aggregations like StatsAggregation, NestedAggregation, etc.Building Queries:
$search = new Search();
$search->addQuery(new TermQuery('field_name', 'value'));
$boolQuery = new BoolQuery();
$boolQuery->addMust(new TermQuery('field1', 'value1'));
$boolQuery->addShould(new TermQuery('field2', 'value2'));
$search->addQuery($boolQuery);
$functionScoreQuery = new FunctionScoreQuery(new MatchAllQuery());
$functionScoreQuery->addWeightFunction(2.0, new TermQuery('popular', true));
$search->addQuery($functionScoreQuery);
Aggregations:
$search = new Search();
$search->addAggregation(new StatsAggregation('stats_agg', 'numeric_field'));
$nestedAgg = new NestedAggregation('nested_agg', 'nested_field');
$nestedAgg->addAggregation(new AvgAggregation('avg_agg', 'nested_field.value'));
$search->addAggregation($nestedAgg);
Pagination and Sorting:
$search = new Search();
$search->setFrom(0)->setSize(10);
$search->addSort(Sort::create()->field('created_at')->order(Sort::ORDER_DESC));
Laravel Integration:
ongr/elasticsearch-bundle for seamless integration with Laravel’s service container and configuration.$this->app->bind('elasticsearch.dsl', function () {
return new Search();
});
Custom Parameters:
$search = new Search();
$search->setParameter('track_total_hits', true);
$search->setParameter('typed_keys', false);
Reusing Queries:
class ElasticsearchQueryBuilder
{
public function buildPopularProductsQuery()
{
$functionScoreQuery = new FunctionScoreQuery(new MatchAllQuery());
$functionScoreQuery->addWeightFunction(2.0, new TermQuery('is_popular', true));
return $functionScoreQuery;
}
}
Handling Aggregation Results:
$response = $client->search($params);
$aggregations = $response['aggregations'];
$stats = $aggregations['stats_agg']['avg'];
Version Compatibility:
ongr/elasticsearch-dsl (e.g., Elasticsearch 7.x requires DSL 7.x).Nested Objects:
path parameter to correctly reference nested fields. Forgetting this will result in errors:
$nestedAgg = new NestedAggregation('nested_agg', 'nested_field'); // Correct
// vs
$nestedAgg = new NestedAggregation('nested_agg'); // Incorrect (missing path)
Boolean Query Logic:
BoolQuery in this DSL automatically wraps added queries in a bool query. If you need explicit control, use BoolQuery directly:
$boolQuery = new BoolQuery();
$boolQuery->addMust(new TermQuery('field', 'value')); // Explicit bool query
Aggregation Field References:
Performance:
explain: true in queries to debug scoring issues:
$search->setParameter('explain', true);
Inspect Raw Query:
toArray() to debug the generated query before sending it to Elasticsearch:
$queryArray = $search->toArray();
dd($queryArray); // Debug the query structure
Error Handling:
try {
$response = $client->search($params);
} catch (\Exception $e) {
Log::error('Elasticsearch error: ' . $e->getMessage());
throw $e;
}
Logging:
$client = ClientBuilder::create()
->setLogger(new \Psr\Log\NullLogger()) // Replace with your logger
->build();
Custom Query Classes:
class CustomRangeQuery extends RangeQuery
{
public function setCustomRange($min, $max)
{
$this->addParameter('gte', $min);
$this->addParameter('lte', $max);
}
}
Query Builders:
class ProductQueryBuilder
{
public static function create()
{
return new static();
}
public function inStock()
{
$this->query->addMust(new TermQuery('stock', true));
return $this;
}
public function priceRange($min, $max)
{
$rangeQuery = new RangeQuery('price');
$rangeQuery->addParameter('gte', $min);
$rangeQuery->addParameter('lte', $max);
$this->query->addMust($rangeQuery);
return $this;
}
public function build()
{
return $this->query;
}
}
Aggregation Pipelines:
$bucketScript = new BucketScriptAggregation('avg_price_per_category', 'avg_price');
$bucketScript->setScript('params.category_avg / params.category_count');
$bucketScript->addMetric(new AvgAggregation('avg_price', 'price'));
$bucketScript->addMetric(new CardinalityAggregation('category_count', 'category'));
$search->addAggregation($bucketScript);
Dynamic Field Mapping:
$field = $dynamicField ? 'dynamic_field' : 'static_field';
$search->addAggregation(new StatsAggregation('stats', $field));
Elasticsearch Client Configuration:
$client = ClientBuilder::create()
->setHosts(['http://localhost:9200'])
->setBasicAuthentication('username', 'password')
->build();
Search Parameters:
track_total_hits or typed_keys:
$
How can I help you explore Laravel packages today?