PHPackages                             dam-bal/elasticsearch-query-builder - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. dam-bal/elasticsearch-query-builder

ActiveLibrary[Search &amp; Filtering](/categories/search)

dam-bal/elasticsearch-query-builder
===================================

Build and execute an Elasticsearch search query using a fluent PHP API

1.0.0(1y ago)010MITPHPPHP ^8.0

Since May 4Pushed 1y agoCompare

[ Source](https://github.com/dam-bal/elasticsearch-query-builder)[ Packagist](https://packagist.org/packages/dam-bal/elasticsearch-query-builder)[ Docs](https://github.com/spatie/elasticsearch-query-builder)[ GitHub Sponsors](https://github.com/spatie)[ RSS](/packages/dam-bal-elasticsearch-query-builder/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (5)Versions (7)Used By (0)

Build and execute ElasticSearch queries using a fluent PHP API
==============================================================

[](#build-and-execute-elasticsearch-queries-using-a-fluent-php-api)

[![Latest Version on Packagist](https://camo.githubusercontent.com/d24541dcaa5969ae6889781d88d0e573b15852b658cfcff7a18f508704c8755f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7370617469652f656c61737469637365617263682d71756572792d6275696c6465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/spatie/elasticsearch-query-builder)[![Tests](https://github.com/spatie/elasticsearch-query-builder/actions/workflows/run-tests.yml/badge.svg)](https://github.com/spatie/elasticsearch-query-builder/actions/workflows/run-tests.yml)[![Total Downloads](https://camo.githubusercontent.com/a7b97d416cdfa446d84d05143346075e3c8026a9a28e0718f555d5ce914b200f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7370617469652f656c61737469637365617263682d71756572792d6275696c6465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/spatie/elasticsearch-query-builder)

---

This package is a *lightweight* query builder for ElasticSearch. It was specifically built for our [elasticsearch-search-string-parser](https://github.com/spatie/elasticsearch-search-string-parser) so it covers most use-cases but might lack certain features. We're always open for PRs if you need anything specific!

```
use Spatie\ElasticsearchQueryBuilder\Aggregations\MaxAggregation;
use Spatie\ElasticsearchQueryBuilder\Builder;
use Spatie\ElasticsearchQueryBuilder\Queries\MatchQuery;

$client = Elastic\Elasticsearch\ClientBuilder::create()->build();

$companies = (new Builder($client))
    ->index('companies')
    ->addQuery(MatchQuery::create('name', 'spatie', fuzziness: 3))
    ->addAggregation(MaxAggregation::create('score'))
    ->search();
```

Support us
----------

[](#support-us)

[![](https://camo.githubusercontent.com/094984d8a09a51c2f9df93518fdb19b01bbf510aa057dc892354376ed05a99ed/68747470733a2f2f6769746875622d6164732e73332e65752d63656e7472616c2d312e616d617a6f6e6177732e636f6d2f656c61737469637365617263682d71756572792d6275696c6465722e6a70673f743d31)](https://spatie.be/github-ad-click/elasticsearch-query-builder)

We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require spatie/elasticsearch-query-builder
```

> **Note**If you're using `elasticsearch/elasticsearch` v7 you need to use [v1](https://github.com/spatie/elasticsearch-query-builder/tree/v1) of this package.

Basic usage
-----------

[](#basic-usage)

The only class you really need to interact with is the `Spatie\ElasticsearchQueryBuilder\Builder` class. It requires an `\Elastic\Elasticsearch\Client` passed in the constructor. Take a look at the [ElasticSearch SDK docs](https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/installation.html) to learn more about connecting to your ElasticSearch cluster.

The `Builder` class contains some methods to [add queries](#adding-queries), [aggregations](#adding-aggregations), [sorts](#adding-sorts), [fields](#retrieve-specific-fields) and some extras for [pagination](#pagination). You can read more about these methods below. Once you've fully built-up the query you can use `$builder->search()` to execute the query or `$builder->getPayload()` to get the raw payload for ElasticSearch.

```
use Spatie\ElasticsearchQueryBuilder\Queries\RangeQuery;
use Spatie\ElasticsearchQueryBuilder\Builder;

$client = Elastic\Elasticsearch\ClientBuilder::create()->build();

$builder = new Builder($client);

$builder->addQuery(RangeQuery::create('age')->gte(18));

$results = $builder->search(); // raw response from ElasticSearch
```

Adding queries
--------------

[](#adding-queries)

The `$builder->addQuery()` method can be used to add any of the available `Query` types to the builder. The available query types can be found below or in the `src/Queries` directory of this repo. Every `Query` has a static `create()` method to pass its most important parameters.

The following query types are available:

#### `ExistsQuery`

[](#existsquery)

```
\Spatie\ElasticsearchQueryBuilder\Queries\ExistsQuery::create('terms_and_conditions');
```

#### `MatchQuery`

[](#matchquery)

```
\Spatie\ElasticsearchQueryBuilder\Queries\MatchQuery::create('name', 'john doe', fuzziness: 2, boost: 5.0);
```

#### `MultiMatchQuery`

[](#multimatchquery)

```
\Spatie\ElasticsearchQueryBuilder\Queries\MultiMatchQuery::create('john', ['email', 'email'], fuzziness: 'auto');
```

#### `NestedQuery`

[](#nestedquery)

```
\Spatie\ElasticsearchQueryBuilder\Queries\NestedQuery::create(
    'user',
    new \Spatie\ElasticsearchQueryBuilder\Queries\MatchQuery('name', 'john')
);
```

##### `NestedQuery` `InnerHits`

[](#nestedquery-innerhits)

```
$nestedQuery = \Spatie\ElasticsearchQueryBuilder\Queries\NestedQuery::create(
    'comments',
    \Spatie\ElasticsearchQueryBuilder\Queries\TermsQuery::create('comments.published', true)
);

$nestedQuery->innerHits(
    \Spatie\ElasticsearchQueryBuilder\Queries\NestedQuery\InnerHits::create('top_three_liked_comments')
        ->size(3)
        ->addSort(
            \Spatie\ElasticsearchQueryBuilder\Sorts\Sort::create(
                'comments.likes',
                \Spatie\ElasticsearchQueryBuilder\Sorts\Sort::DESC
            )
        )
        ->fields(['comments.content', 'comments.author', 'comments.likes'])
);
```

#### `FunctionScore`

[](#functionscore)

```
\Spatie\ElasticsearchQueryBuilder\Queries\FunctionScore::create()
    ->addFunction(\Spatie\ElasticsearchQueryBuilder\Queries\FunctionScore\RandomScore::create(123, 'test_field'))
    ->addFunction(\Spatie\ElasticsearchQueryBuilder\Queries\FunctionScore\FieldValueFactor::create('test_field')->factor(2.0))
    ->addFunction(\Spatie\ElasticsearchQueryBuilder\Queries\FunctionScore\Weight::create(2.0));
```

#### `RangeQuery`

[](#rangequery)

```
\Spatie\ElasticsearchQueryBuilder\Queries\RangeQuery::create('age')
    ->gte(18)
    ->lte(1337);
```

#### `TermQuery`

[](#termquery)

```
\Spatie\ElasticsearchQueryBuilder\Queries\TermQuery::create('user.id', 'flx');
```

#### `TermsQuery`

[](#termsquery)

```
\Spatie\ElasticsearchQueryBuilder\Queries\TermsQuery::create('user.id', ['flx', 'fly']);
```

#### `WildcardQuery`

[](#wildcardquery)

```
\Spatie\ElasticsearchQueryBuilder\Queries\WildcardQuery::create('user.id', '*doe');
```

#### `BoolQuery`

[](#boolquery)

```
\Spatie\ElasticsearchQueryBuilder\Queries\BoolQuery::create()
    ->add($matchQuery, 'must_not')
    ->add($existsQuery, 'must_not');
```

### Chaining multiple queries

[](#chaining-multiple-queries)

Multiple `addQuery()` calls can be chained on one `Builder`. Under the hood they'll be added to a `BoolQuery` with occurrence type `must`. By passing a second argument to the `addQuery()` method you can select a different occurrence type:

```
$builder
    ->addQuery(
        MatchQuery::create('name', 'billie'),
        'must_not' // available types: must, must_not, should, filter
    )
    ->addQuery(
        MatchQuery::create('team', 'eillish')
    );
```

More information on the boolean query and its occurrence types can be found [in the ElasticSearch docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html).

Adding aggregations
-------------------

[](#adding-aggregations)

The `$builder->addAggregation()` method can be used to add any of the available `Aggregation`s to the builder. The available aggregation types can be found below or in the `src/Aggregations` directory of this repo. Every `Aggregation` has a static `create()` method to pass its most important parameters and sometimes some extra methods.

```
use Spatie\ElasticsearchQueryBuilder\Aggregations\TermsAggregation;
use Spatie\ElasticsearchQueryBuilder\Builder;

$results = (new Builder(Elastic\Elasticsearch\ClientBuilder::create()->build()))
    ->addAggregation(TermsAggregation::create('genres', 'genre'))
    ->search();

$genres = $results['aggregations']['genres']['buckets'];
```

The following query types are available:

#### `CardinalityAggregation`

[](#cardinalityaggregation)

```
\Spatie\ElasticsearchQueryBuilder\Aggregations\CardinalityAggregation::create('team_agg', 'team_name');
```

#### `FilterAggregation`

[](#filteraggregation)

```
\Spatie\ElasticsearchQueryBuilder\Aggregations\FilterAggregation::create(
    'tshirts',
    \Spatie\ElasticsearchQueryBuilder\Queries\TermQuery::create('type', 'tshirt'),
    \Spatie\ElasticsearchQueryBuilder\Aggregations\MaxAggregation::create('max_price', 'price')
);
```

#### `MaxAggregation`

[](#maxaggregation)

```
\Spatie\ElasticsearchQueryBuilder\Aggregations\MaxAggregation::create('max_price', 'price');
```

#### `MinAggregation`

[](#minaggregation)

```
\Spatie\ElasticsearchQueryBuilder\Aggregations\MinAggregation::create('min_price', 'price');
```

#### `SumAggregation`

[](#sumaggregation)

```
\Spatie\ElasticsearchQueryBuilder\Aggregations\SumAggregation::create('sum_price', 'price');
```

#### `NestedAggregation`

[](#nestedaggregation)

```
\Spatie\ElasticsearchQueryBuilder\Aggregations\NestedAggregation::create(
    'resellers',
    'resellers',
    \Spatie\ElasticsearchQueryBuilder\Aggregations\MinAggregation::create('min_price', 'resellers.price'),
    \Spatie\ElasticsearchQueryBuilder\Aggregations\MaxAggregation::create('max_price', 'resellers.price'),
);
```

#### `ReverseNestedAggregation`

[](#reversenestedaggregation)

```
\Spatie\ElasticsearchQueryBuilder\Aggregations\ReverseNestedAggregation::create(
    'name',
    ...$aggregations
);
```

#### `TermsAggregation`

[](#termsaggregation)

```
\Spatie\ElasticsearchQueryBuilder\Aggregations\TermsAggregation::create(
    'genres',
    'genre'
)
    ->size(10)
    ->order(['_count' => 'asc'])
    ->missing('N/A')
    ->aggregation(/* $subAggregation */);
```

#### `TopHitsAggregation`

[](#tophitsaggregation)

```
\Spatie\ElasticsearchQueryBuilder\Aggregations\TopHitsAggregation::create(
    'top_sales_hits',
    size: 10,
);
```

Adding sorts
------------

[](#adding-sorts)

The `Builder` (and some aggregations) has a `addSort()` method that takes a `Sort` instance to sort the results. You can read more about how sorting works in [the ElasticSearch docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html).

```
use Spatie\ElasticsearchQueryBuilder\Sorts\Sort;

$builder
    ->addSort(Sort::create('age', Sort::DESC))
    ->addSort(
        Sort::create('score', Sort::ASC)
            ->unmappedType('long')
            ->missing(0)
    );
```

### Nested sort

[](#nested-sort)

[https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#\_nested\_sorting\_examples](https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_nested_sorting_examples)

```
use Spatie\ElasticsearchQueryBuilder\Sorts\NestedSort;

$builder
    ->addSort(
        NestedSort::create('books', 'books.rating', NestedSort::ASC)
    );
```

#### Nested sort with filter

[](#nested-sort-with-filter)

```
use Spatie\ElasticsearchQueryBuilder\Sorts\NestedSort;
use Spatie\ElasticsearchQueryBuilder\Queries\BoolQuery;
use Spatie\ElasticsearchQueryBuilder\Queries\TermQuery;

$builder
    ->addSort(
        NestedSort::create(
            'books',
            'books.rating',
            NestedSort::ASC
        )->filter(BoolQuery::create()->add(TermQuery::create('books.category', 'comedy'))
    );
```

Retrieve specific fields
------------------------

[](#retrieve-specific-fields)

The `fields()` method can be used to request specific fields from the resulting documents without returning the entire `_source` entry. You can read more about the specifics of the fields parameter in [the ElasticSearch docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-fields.html).

```
$builder->fields('user.id', 'http.*.status');
```

Highlighting
------------

[](#highlighting)

The `highlight()` method can be used to add a highlight section to your query along the rules in [the ElasticSearch docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/highlighting.html).

```
$highlightSettings = [
    'pre_tags' => [''],
    'post_tags' => [''],
    'fields' => [
        '*' => (object) []
    ]
];

$builder->highlight($highlightSettings);
```

Post filter
-----------

[](#post-filter)

The `addPostFilterQuery()` method can be used to add a post\_filter BoolQuery to your query along the rules in [the ElasticSearch docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/filter-search-results.html#post-filter).

```
use Spatie\ElasticsearchQueryBuilder\Queries\TermsQuery;

$builder->addPostFilterQuery(TermsQuery::create('user.id', ['flx', 'fly']));
```

Pagination
----------

[](#pagination)

Finally the `Builder` also features a `size()` and `from()` method for the corresponding ElasticSearch search parameters. These can be used to build a paginated search. Take a look the following example to get a rough idea:

```
use Spatie\ElasticsearchQueryBuilder\Builder;

$pageSize = 100;
$pageNumber = $_GET['page'] ?? 1;

$pageResults = (new Builder(Elastic\Elasticsearch\ClientBuilder::create()))
    ->size($pageSize)
    ->from(($pageNumber - 1) * $pageSize)
    ->search();
```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Alex Vanderbist](https://github.com/alexvanderbist)
- [Ruben Van Assche](https://github.com/rubenvanassche)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance36

Infrequent updates — may be unmaintained

Popularity5

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

592d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3c59ff1d15fa2be7d29193bdfd6a57fa7d21aeca82e63545406cd13e88dbdaae?d=identicon)[dam-bal](/maintainers/dam-bal)

---

Top Contributors

[![AlexVanderbist](https://avatars.githubusercontent.com/u/6287961?v=4)](https://github.com/AlexVanderbist "AlexVanderbist (45 commits)")[![dam-bal](https://avatars.githubusercontent.com/u/94970129?v=4)](https://github.com/dam-bal "dam-bal (30 commits)")[![freekmurze](https://avatars.githubusercontent.com/u/483853?v=4)](https://github.com/freekmurze "freekmurze (20 commits)")[![rubenvanassche](https://avatars.githubusercontent.com/u/619804?v=4)](https://github.com/rubenvanassche "rubenvanassche (7 commits)")[![AdrianMrn](https://avatars.githubusercontent.com/u/12762044?v=4)](https://github.com/AdrianMrn "AdrianMrn (5 commits)")[![MilanLamote](https://avatars.githubusercontent.com/u/80511992?v=4)](https://github.com/MilanLamote "MilanLamote (5 commits)")[![nick-rashkevich](https://avatars.githubusercontent.com/u/86295744?v=4)](https://github.com/nick-rashkevich "nick-rashkevich (3 commits)")[![djubelius](https://avatars.githubusercontent.com/u/119296273?v=4)](https://github.com/djubelius "djubelius (1 commits)")[![imdhemy](https://avatars.githubusercontent.com/u/22864831?v=4)](https://github.com/imdhemy "imdhemy (1 commits)")[![adevneverdies](https://avatars.githubusercontent.com/u/1610989?v=4)](https://github.com/adevneverdies "adevneverdies (1 commits)")

---

Tags

spatiesearchelasticsearchelasticsearch-query-builder

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/dam-bal-elasticsearch-query-builder/health.svg)

```
[![Health](https://phpackages.com/badges/dam-bal-elasticsearch-query-builder/health.svg)](https://phpackages.com/packages/dam-bal-elasticsearch-query-builder)
```

###  Alternatives

[elasticsearch/elasticsearch

PHP Client for Elasticsearch

5.3k178.3M943](/packages/elasticsearch-elasticsearch)[spatie/elasticsearch-query-builder

Build and execute an Elasticsearch search query using a fluent PHP API

183614.7k5](/packages/spatie-elasticsearch-query-builder)[matchish/laravel-scout-elasticsearch

Search among multiple models with ElasticSearch and Laravel Scout

7431.6M2](/packages/matchish-laravel-scout-elasticsearch)[10up/elasticpress

Supercharge WordPress with Elasticsearch.

1.3k374.3k6](/packages/10up-elasticpress)[opensearch-project/opensearch-php

PHP Client for OpenSearch

15024.3M65](/packages/opensearch-project-opensearch-php)[mailerlite/laravel-elasticsearch

An easy way to use the official PHP ElasticSearch client in your Laravel applications.

934529.3k2](/packages/mailerlite-laravel-elasticsearch)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
