PHPackages                             bonu/php-elasticsearch-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. bonu/php-elasticsearch-builder

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

bonu/php-elasticsearch-builder
==============================

Elasticsearch query builder for PHP

v0.7.0(4mo ago)66254↓50%2MITPHPPHP ^8.4CI passing

Since Nov 30Pushed 2mo agoCompare

[ Source](https://github.com/bonu-dev/php-elasticsearch-builder)[ Packagist](https://packagist.org/packages/bonu/php-elasticsearch-builder)[ RSS](/packages/bonu-php-elasticsearch-builder/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (5)Versions (19)Used By (0)

PHP Query Builder for Elasticsearch
===================================

[](#php-query-builder-for-elasticsearch)

[![PHPUnit](https://github.com/bonu-dev/php-elasticsearch-builder/actions/workflows/phpunit.yaml/badge.svg?branch=main)](https://github.com/bonu-dev/php-elasticsearch-builder/actions/workflows/phpunit.yaml)[![Latest Stable Version](https://camo.githubusercontent.com/ca3b371ef2ca86c8a8b4bc74500d2d38c01dfaf42946ee012adc91077d673cc7/68747470733a2f2f706f7365722e707567782e6f72672f626f6e752f7068702d656c61737469637365617263682d6275696c6465722f76)](https://packagist.org/packages/bonu/php-elasticsearch-builder)[![License](https://camo.githubusercontent.com/801be089c13ac085e3f99a2e45baa623962c51d125ac22aa1a216f223d6e8622/68747470733a2f2f706f7365722e707567782e6f72672f626f6e752f7068702d656c61737469637365617263682d6275696c6465722f6c6963656e7365)](https://packagist.org/packages/bonu/php-elasticsearch-builder)[![PHP Version](https://camo.githubusercontent.com/9b0b004c4cc678b49a6c929c783d2a1c2bbe699126fef95b07e2a94c598a3fa7/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f626f6e752f7068702d656c61737469637365617263682d6275696c6465722e737667)](https://packagist.org/packages/bonu/php-elasticsearch-builder)

---

**A clean, fluent, immutable, and type-safe query builder for Elasticsearch** - built from the ground up to work seamlessly with the [official Elasticsearch PHP client](https://github.com/elastic/elasticsearch-php).

No extra dependencies. No magic. Just expressive, readable, and maintainable Elasticsearch queries in PHP.

```
use Elastic\Elasticsearch\ClientBuilder;
use Bonu\ElasticsearchBuilder\QueryBuilder;
use Bonu\ElasticsearchBuilder\Query\TermQuery;
use Bonu\ElasticsearchBuilder\Query\BoolQuery;
use Bonu\ElasticsearchBuilder\Query\MatchQuery;

$builder = new QueryBuilder('products')
    ->query(new TermQuery('ean', 'foo_bar_123')->boost(12))
    ->query(new BoolQuery()
        ->should(new MatchQuery('name', 'foo'))
        ->should(new MatchQuery('description', 'bar'))
        ->boost(5)
    )
    ->size(20);

$client = ClientBuilder::create()->build();
$products = $client->search($builder->build());
```

Features
--------

[](#features)

- Fully fluent &amp; chainable API
- Zero dependencies beyond the official Elasticsearch PHP SDK
- Easy creation of reusable composite queries
- 100% type-hinted and IDE-friendly

Requirements
------------

[](#requirements)

- PHP ≥ 8.4

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

[](#installation)

```
composer require bonu/php-elasticsearch-builder
```

Using query builder
-------------------

[](#using-query-builder)

The `Bonu\ElasticsearchBuilder\QueryBuilder` class provides a fluent interface for building Elasticsearch queries. Constructor of this class accepts a single argument - name of the index to query, which may be used for searching in specific index.

Out of box it supports:

- Chaining queries using `query()` method
- Chaining aggregations using `aggregation()` method
- Configuring pagination of results using `from()` and `size()` methods

Queries
-------

[](#queries)

Caution

Queries are immutable.

This package comes with a set of ready-to-use queries which is documented below.

It is also possible to create reusable composite queries using abstract `Bonu\ElasticsearchBuilder\Query\CompositeQuery` class.

Example of composite query:

```
use Bonu\ElasticsearchBuilder\Query\BoolQuery;
use Bonu\ElasticsearchBuilder\Query\TermQuery;
use Bonu\ElasticsearchBuilder\Query\CompositeQuery;

class PubliclyVisibleProductsQuery extends CompositeQuery
{
    /**
     * @inheritDoc
     */
    public function query(): QueryInterface
    {
        return new BoolQuery()
            ->must(new TermQuery('is_active', true))
            ->mustNot(new TermQuery('is_out_of_stock', false));
    }
}

$builder = new QueryBuilder('products')
    ->query(new PubliclyVisibleProductsQuery());
```

### TermQuery

[](#termquery)

```
use Bonu\ElasticsearchBuilder\Query\TermQuery;

new TermQuery('field', 'value')->boost(10)
```

### MatchQuery

[](#matchquery)

```
use Bonu\ElasticsearchBuilder\Query\MatchQuery;

// Default operator is OR
new MatchQuery('field', 'some text')
    ->boost(2)
    ->analyzer('standard')

// With AND operator
new MatchQuery('field', 'some text', MatchQuery::OPERATOR_AND)
```

### MatchPhraseQuery

[](#matchphrasequery)

```
use Bonu\ElasticsearchBuilder\Query\MatchPhraseQuery;

// Optional third argument is slop
new MatchPhraseQuery('field', 'exact phrase', 2)
    ->boost(1.5)
    ->analyzer('standard')
```

### BoolQuery

[](#boolquery)

```
use Bonu\ElasticsearchBuilder\Query\BoolQuery;
use Bonu\ElasticsearchBuilder\Query\TermQuery;
use Bonu\ElasticsearchBuilder\Query\MatchQuery;

new BoolQuery()
    ->must(new TermQuery('status', 'active'))
    ->filter(new TermQuery('stock', 1))
    ->should(new MatchQuery('title', 'awesome product'))
    ->mustNot(new TermQuery('blocked', true))
    ->boost(3)
```

### NestedQuery

[](#nestedquery)

```
use Bonu\ElasticsearchBuilder\Query\NestedQuery;
use Bonu\ElasticsearchBuilder\Query\MatchQuery;

// Query nested field path, inner query must be provided via ->query()
new NestedQuery('variants')
    ->query(new MatchQuery('variants.name', 'red'))
```

### RangeQuery

[](#rangequery)

Range queries can be used for filtering by multiple data types. For this reason, each data type has its own query class to fully support type-hinting.

```
use Bonu\ElasticsearchBuilder\Query\NumericRangeQuery;
use Bonu\ElasticsearchBuilder\Query\DatetimeRangeQuery;

new NumericRangeQuery('price', gte: 100)
    ->boost(10);

new DatetimeRangeQuery('created_at', lt: date('Y-m-d'), format: 'yyyy-MM-dd', timeZone: 'Europe/Prague')
    ->boost(20);
```

Aggregations
------------

[](#aggregations)

Caution

Aggregations are immutable.

Similar to queries, it is also possible to create reusable composite aggregations using abstract `Bonu\ElasticsearchBuilder\Aggregation\CompositeAggregation` class.

Example of composite aggregation:

```
use Bonu\ElasticsearchBuilder\Aggregation\TermsAggregation;
use Bonu\ElasticsearchBuilder\Aggregation\NestedAggregation;
use Bonu\ElasticsearchBuilder\Aggregation\CompositeAggregation;

class CategoryBrandAggregation extends CompositeAggregation
{
    /**
     * @param string|\Stringable $name
     */
    public function __construct(
        private readonly string | Stringable $name,
    ) {}

    /**
     * @inheritDoc
     */
    public function aggregation(): AggregationInterface
    {
        return new NestedAggregation($this->name, 'products')
            ->aggregation(new TermsAggregation('by_brand', 'products.brand_id'));
    }
}
```

### ContainerAggregation

[](#containeraggregation)

Container aggregation is used to group sub-aggregations. It requires either global or at least one filter (query) to be set, but not both.

```
use Bonu\ElasticsearchBuilder\Query\TermQuery;
use Bonu\ElasticsearchBuilder\Aggregation\TermsAggregation;
use Bonu\ElasticsearchBuilder\Aggregation\ContainerAggregation;

// Container with a filter
new ContainerAggregation('my_container')
    ->query(new TermQuery('status', 'active'))
    ->aggregation(new TermsAggregation('by_brand', 'brand.keyword'));

// Global container
new ContainerAggregation('global_container')
    ->asGlobal()
    ->aggregation(new TermsAggregation('all_brands', 'brand.keyword'));
```

### TermsAggregation

[](#termsaggregation)

```
use Bonu\ElasticsearchBuilder\Aggregation\TermsAggregation;
use Bonu\ElasticsearchBuilder\Query\TermQuery;

// Top 10 brands, filtered to active products
new TermsAggregation('by_brand', 'brand.keyword')
    ->size(10)
    ->query(new TermQuery('status', 'active'));

// Make the aggregation global (ignores the top-level query)
new TermsAggregation('all_categories', 'category.keyword')
    ->asGlobal();
```

### StatsAggregation

[](#statsaggregation)

```
use Bonu\ElasticsearchBuilder\Aggregation\StatsAggregation;
use Bonu\ElasticsearchBuilder\Query\TermQuery;

// Basic stats for the price field, filtered by currency
new StatsAggregation('price_stats', 'price')
    ->query(new TermQuery('currency', 'USD'));

// Make the aggregation global (ignores the top-level query)
new StatsAggregation('global_price_stats', 'price')
    ->asGlobal();
```

### NestedAggregation

[](#nestedaggregation)

```
use Bonu\ElasticsearchBuilder\Aggregation\NestedAggregation;

new NestedAggregation('categories', 'products')
    ->aggregation(new StatsAggregation('product_price', 'products.price'))
```

### MultiTermsAggregation

[](#multitermsaggregation)

```
use Bonu\ElasticsearchBuilder\Aggregation\MultiTermsAggregation;

new MultiTermsAggregation('foo', ['product', 'category'])
    ->size(10)
    ->query(new TermQuery('status', 'active'));
```

### HistogramAggregation

[](#histogramaggregation)

```
use Bonu\ElasticsearchBuilder\Aggregation\HistogramAggregation;

// Prices in $10 intervals
new HistogramAggregation('price_histogram', 'price', 10);

// With custom interval and min_doc_count
new HistogramAggregation('price_histogram', 'price', 50, 1);
```

Sorts
-----

[](#sorts)

### FieldSort

[](#fieldsort)

```
use Bonu\ElasticsearchBuilder\Sort\FieldSort;
use Bonu\ElasticsearchBuilder\Sort\SortDirectionEnum;

new FieldSort('my_field', SortDirectionEnum::ASC)
```

### ScoreSort

[](#scoresort)

```
use Bonu\ElasticsearchBuilder\Sort\ScoreSort;
use Bonu\ElasticsearchBuilder\Sort\SortDirectionEnum;

new ScoreSort(SortDirectionEnum::DESC)
```

License
-------

[](#license)

This package is licensed under the MIT License.

###  Health Score

45

—

FairBetter than 93% of packages

Maintenance79

Regular maintenance activity

Popularity28

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 55.3% 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 ~2 days

Total

14

Last Release

139d ago

PHP version history (2 changes)v0.0.1PHP ^8.4

v0.0.1-alpha3PHP &gt;=8.4 &lt;8.6

### Community

Maintainers

![](https://www.gravatar.com/avatar/79c6aec44dcd4096b5f37f6949c22a1c2e43169bce25947838c2f39364e9741f?d=identicon)[MatusBoa](/maintainers/MatusBoa)

---

Top Contributors

[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (26 commits)")[![MatusBoa](https://avatars.githubusercontent.com/u/8343385?v=4)](https://github.com/MatusBoa "MatusBoa (21 commits)")

---

Tags

builderelasticsearchphpquery

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/bonu-php-elasticsearch-builder/health.svg)

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

###  Alternatives

[ruflin/elastica

Elasticsearch Client

2.3k50.4M203](/packages/ruflin-elastica)[opensearch-project/opensearch-php

PHP Client for OpenSearch

15224.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)[massive/search-bundle

Massive Search Bundle

721.4M13](/packages/massive-search-bundle)[shyim/opensearch-php-dsl

OpenSearch/Elasticsearch DSL library

175.9M9](/packages/shyim-opensearch-php-dsl)[outl1ne/nova-multiselect-filter

Multiselect filter for Laravel Nova.

45802.7k3](/packages/outl1ne-nova-multiselect-filter)

PHPackages © 2026

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