PHPackages                             seyvillas/elastic-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. seyvillas/elastic-query-builder

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

seyvillas/elastic-query-builder
===============================

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

v3.0.5(1y ago)01.1kMITPHPPHP ^8.2

Since Jun 11Pushed 1y agoCompare

[ Source](https://github.com/seyvillas/elastic-query-builder)[ Packagist](https://packagist.org/packages/seyvillas/elastic-query-builder)[ Docs](https://github.com/seyvillas/elastic-query-builder)[ GitHub Sponsors](https://github.com/spatie)[ RSS](/packages/seyvillas-elastic-query-builder/feed)WikiDiscussions main Synced today

READMEChangelog (6)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/seyvillas/elastic-query-builder)[![Total Downloads](https://camo.githubusercontent.com/e110ef01c9cbf9df8eefd4cceeaa4cd085192ab53304378d3de9dccc00778ecd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73657976696c6c61732f656c61737469632d71756572792d6275696c6465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/seyvillas/elastic-query-builder)

---

This package is a *lightweight* query builder for ElasticSearch. It's based on the `spatie\elasticsearch-query-builder` package.

```
use SeyVillas\ElasticQueryBuilder\Aggregations\MaxAggregation;
use SeyVillas\ElasticQueryBuilder\Builder;
use SeyVillas\ElasticQueryBuilder\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();
```

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

[](#installation)

You can install the package via composer:

```
composer require seyvillas/elastic-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 `SeyVillas\ElasticQueryBuilder\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 SeyVillas\ElasticQueryBuilder\Queries\RangeQuery;
use SeyVillas\ElasticQueryBuilder\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)

```
\SeyVillas\ElasticQueryBuilder\Queries\ExistsQuery::create('terms_and_conditions');
```

#### `MatchQuery`

[](#matchquery)

```
\SeyVillas\ElasticQueryBuilder\Queries\MatchQuery::create('name', 'john doe', fuzziness: 2);
```

#### `MultiMatchQuery`

[](#multimatchquery)

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

#### `NestedQuery`

[](#nestedquery)

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

#### `RangeQuery`

[](#rangequery)

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

#### `TermQuery`

[](#termquery)

```
\SeyVillas\ElasticQueryBuilder\Queries\TermQuery::create('user.id', 'flx');
```

#### `WildcardQuery`

[](#wildcardquery)

\[[https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html\](](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html](). elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html)

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

#### `GeoQuery`

[](#geoquery)

```
use SeyVillas\ElasticQueryBuilder\Geo\Point;

$builder
    ->addQuery(
        $distanceQuery = GeoDistanceQuery::create('location', Point::create($point->latitude, $point->longitude)),
    'filter'
);
```

#### `BoolQuery`

[](#boolquery)

```
\SeyVillas\ElasticQueryBuilder\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 SeyVillas\ElasticQueryBuilder\Aggregations\TermsAggregation;
use SeyVillas\ElasticQueryBuilder\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)

```
\SeyVillas\ElasticQueryBuilder\Aggregations\CardinalityAggregation::create('team_agg', 'team_name');
```

#### `FilterAggregation`

[](#filteraggregation)

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

#### `MaxAggregation`

[](#maxaggregation)

```
\SeyVillas\ElasticQueryBuilder\Aggregations\MaxAggregation::create('max_price', 'price');
```

#### `MinAggregation`

[](#minaggregation)

```
\SeyVillas\ElasticQueryBuilder\Aggregations\MinAggregation::create('min_price', 'price');
```

#### `AvgAggregation`

[](#avgaggregation)

```
\SeyVillas\ElasticQueryBuilder\Aggregations\AvgAggregation::create('avg_price', 'price');
```

#### `SumAggregation`

[](#sumaggregation)

```
\SeyVillas\ElasticQueryBuilder\Aggregations\SumAggregation::create('sum_price', 'price');
```

#### `NestedAggregation`

[](#nestedaggregation)

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

#### `ReverseNestedAggregation`

[](#reversenestedaggregation)

```
\SeyVillas\ElasticQueryBuilder\Aggregations\ReverseNestedAggregation::create(
    'name',
    ...$aggregations
);
```

#### `TermsAggregation`

[](#termsaggregation)

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

#### `TopHitsAggregation`

[](#tophitsaggregation)

```
\SeyVillas\ElasticQueryBuilder\Aggregations\TopHitsAggregation::create(
    'top_sales_hits',
    size: 10,
);
```

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

[](#adding-sorts)

The `Builder` (and some aggregations) has a `addSort()` method that takes a `ISort` 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).

### `Standard Sort`

[](#standard-sort)

```
use SeyVillas\ElasticQueryBuilder\Sorts\Sort;

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

### `GeoSort`

[](#geosort)

```
use SeyVillas\ElasticQueryBuilder\Geo\Point;
use SeyVillas\ElasticQueryBuilder\Sorts\GeoSort;

$builder
    ->addSort(
        GeoSort::create('location', Point::create($point->latitude, $point->longitude))
    );
```

### `Random`

[](#random)

There's also possibility to use **Random** sort:

```
use SeyVillas\ElasticQueryBuilder\Sorts\Random;

$builder
    ->addSort(Random::create());
```

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');
```

Specify excludes/includes in the `_source`
------------------------------------------

[](#specify-excludesincludes-in-the-_source)

The `addExclude($name)` or `addInclude($name)` methods can be used for specifying excludes or includes on the `_source`. More in [the ElasticSearch docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html#include-exclude).

```
$builder->addExclude('document key');
```

or you can use also `*`:

```
$builder->addExclude('translations.*');
```

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 SeyVillas\ElasticQueryBuilder\Builder;

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

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

Scripts
-------

[](#scripts)

It's also possible to add scripts as an array to the query. For example, here's a simple script that retrieves the first item from the images array and returns it in the $response\['fields'\] array:

```
$builder
    ->addScript(
        'images',
        [
            'source' => "params['_source']['images'][0]",
            'lang' => 'painless'
        ]
    );
```

This script checks if the images array exists and contains at least one item. If both conditions are met, it returns the first item from the images array; otherwise, it returns null.

```
$builder
->addScript(
    'images',
    [
        'source' => "
            if (params['_source']['images'] != null && !params['_source']['images'].isEmpty()) {
                return params['_source']['images'][0];
            } else {
                return null;
            }
        ",
        'lang' => 'painless'
    ]
);
```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

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

Credits
-------

[](#credits)

- [Miroslav Koula](https://github.com/elcheco)
- [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

33

—

LowBetter than 72% of packages

Maintenance35

Infrequent updates — may be unmaintained

Popularity16

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 63.2% of commits — single point of failure

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

Every ~29 days

Recently: every ~36 days

Total

6

Last Release

603d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6ae8ae34c125f7d527c2fcdbfab854bae463ae576f52173b0f9765ee7869de60?d=identicon)[seyvillas](/maintainers/seyvillas)

---

Top Contributors

[![AlexVanderbist](https://avatars.githubusercontent.com/u/6287961?v=4)](https://github.com/AlexVanderbist "AlexVanderbist (36 commits)")[![freekmurze](https://avatars.githubusercontent.com/u/483853?v=4)](https://github.com/freekmurze "freekmurze (7 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)")[![adevneverdies](https://avatars.githubusercontent.com/u/1610989?v=4)](https://github.com/adevneverdies "adevneverdies (1 commits)")[![imdhemy](https://avatars.githubusercontent.com/u/22864831?v=4)](https://github.com/imdhemy "imdhemy (1 commits)")

---

Tags

searchelasticsearchseyvillaselastics-query-builder

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/seyvillas-elastic-query-builder/health.svg)

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

###  Alternatives

[elasticsearch/elasticsearch

PHP Client for Elasticsearch

5.3k187.3M1.1k](/packages/elasticsearch-elasticsearch)[matchish/laravel-scout-elasticsearch

Search among multiple models with ElasticSearch and Laravel Scout

7491.7M3](/packages/matchish-laravel-scout-elasticsearch)[opensearch-project/opensearch-php

PHP Client for OpenSearch

15528.5M116](/packages/opensearch-project-opensearch-php)[10up/elasticpress

Supercharge WordPress with Elasticsearch.

1.3k395.7k17](/packages/10up-elasticpress)[mailerlite/laravel-elasticsearch

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

936603.4k2](/packages/mailerlite-laravel-elasticsearch)[jolicode/elastically

Opinionated Elastica based framework to bootstrap PHP and Elasticsearch implementations.

2591.8M1](/packages/jolicode-elastically)

PHPackages © 2026

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