Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f3e724e
feat: Add PercentilesAggregation class with tests and documentation
summerKK Aug 2, 2025
e8f7bb1
feat: add MatchAllQuery with comprehensive tests
summerKK Aug 4, 2025
13671d4
feat: add IdsQuery with comprehensive tests
summerKK Aug 4, 2025
6fd0419
feat: add FuzzyQuery with comprehensive tests
summerKK Aug 4, 2025
33d95ca
feat: add AvgAggregation with comprehensive tests
summerKK Aug 4, 2025
44019d1
Fix styling
summerKK Aug 4, 2025
acab4fe
test: add comprehensive tests for ExistsQuery and PrefixQuery
summerKK Aug 4, 2025
c80845d
fix: Refactor missing parameter checks in aggregations and sorts to a…
summerKK Aug 2, 2025
0845bf1
Update CHANGELOG
freekmurze Aug 4, 2025
902ea1d
fix: update missing parameter type in AvgAggregationTest
summerKK Aug 4, 2025
4a689d8
feat: add RegexpQuery with comprehensive tests
summerKK Aug 4, 2025
fdd90bd
feat: add HistogramAggregation with comprehensive tests
summerKK Aug 4, 2025
d005426
feat: add MatchNoneQuery with comprehensive tests
summerKK Aug 4, 2025
d87384e
test: add comprehensive tests for RangeQuery
summerKK Aug 4, 2025
bc77315
test: add comprehensive tests for TermQuery
summerKK Aug 4, 2025
a7da7dc
test: add comprehensive tests for WildcardQuery
summerKK Aug 4, 2025
9ac735f
docs: update README to include new query and aggregation types
summerKK Aug 4, 2025
eff94be
Fix styling
summerKK Aug 4, 2025
2f2a656
Merge remote-tracking branch 'spatie/elasticsearch-query-builder/main…
summerKK Aug 6, 2025
24af0c4
feat: enhance Elasticsearch query and aggregation syntax support
summerKK Aug 6, 2025
05ae5c0
Fix styling
summerKK Aug 6, 2025
8d2b637
docs: update README with enhanced query and aggregation examples
summerKK Aug 6, 2025
e970553
fix: fix some error test in PercentilesAggregationTest
summerKK Aug 9, 2025
413d100
fix: Fix the document and point it to the correct link.
summerKK Sep 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ The following query types are available:
\Spatie\ElasticsearchQueryBuilder\Queries\ExistsQuery::create('terms_and_conditions');
```

#### `FuzzyQuery`

[https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-fuzzy-query](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-fuzzy-query)

```php
\Spatie\ElasticsearchQueryBuilder\Queries\FuzzyQuery::create('name', 'john', fuzziness: 2, boost: 1.5, rewrite: 'constant_score_blended');
```

#### `GeoshapeQuery`

[https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-query.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-query.html);
Expand All @@ -91,6 +99,26 @@ The following query types are available:
);
```

#### `IdsQuery`

[https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-ids-query](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-ids-query)

```php
\Spatie\ElasticsearchQueryBuilder\Queries\IdsQuery::create(['user123', 'post456']);
```

#### `MatchAllQuery`

[https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-match-all-query](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-match-all-query)

#### `MatchNoneQuery`

[https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-match-all-query#query-dsl-match-none-query](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-match-all-query#query-dsl-match-none-query)

```php
\Spatie\ElasticsearchQueryBuilder\Queries\MatchAllQuery::create(boost: 1.2);
```

#### `MatchQuery`

[https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html)
Expand All @@ -115,6 +143,10 @@ The following query types are available:
\Spatie\ElasticsearchQueryBuilder\Queries\MultiMatchQuery::create('john', ['email', 'email'], fuzziness: 'auto');
```

```php
\Spatie\ElasticsearchQueryBuilder\Queries\MatchNoneQuery::create();
```

#### `NestedQuery`

[https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html)
Expand Down Expand Up @@ -159,6 +191,14 @@ $nestedQuery->innerHits(
->lte(1337);
```

#### `RegexpQuery`

[https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-regexp-query](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-regexp-query)

```php
\Spatie\ElasticsearchQueryBuilder\Queries\RegexpQuery::create('name', 'joh.*', flags: 'ALL', maxDeterminizedStates: 10000, rewrite: 'constant_score');
```

#### `TermQuery`

[https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html)
Expand Down Expand Up @@ -272,6 +312,14 @@ The following query types are available:
\Spatie\ElasticsearchQueryBuilder\Aggregations\CardinalityAggregation::create('team_agg', 'team_name');
```

#### `AvgAggregation`

[https://www.elastic.co/docs/reference/aggregations/search-aggregations-metrics-avg-aggregation](https://www.elastic.co/docs/reference/aggregations/search-aggregations-metrics-avg-aggregation)

```php
\Spatie\ElasticsearchQueryBuilder\Aggregations\AvgAggregation::create('avg_price', 'price');
```

#### `FilterAggregation`

[https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html)
Expand All @@ -284,6 +332,17 @@ The following query types are available:
);
```

#### `HistogramAggregation`

[https://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-histogram-aggregation](https://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-histogram-aggregation)

```php
\Spatie\ElasticsearchQueryBuilder\Aggregations\HistogramAggregation::create('price_histogram', 'price', 50)
->minDocCount(1)
->hardBounds(0, 1000)
->missing(0);
```

#### `MaxAggregation`

[https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-max-aggregation.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-max-aggregation.html)
Expand Down Expand Up @@ -321,6 +380,17 @@ The following query types are available:
);
```

#### `PercentilesAggregation`

[https://www.elastic.co/docs/reference/aggregations/search-aggregations-metrics-percentile-aggregation](https://www.elastic.co/docs/reference/aggregations/search-aggregations-metrics-percentile-aggregation)

```php
\Spatie\ElasticsearchQueryBuilder\Aggregations\PercentilesAggregation::create('load_time_outlier', 'load_time', [95, 99, 99.9])
->keyed(false)
->tdigest(200, 'high_accuracy')
->missing(10);
```

#### `ReverseNestedAggregation`

[https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-reverse-nested-aggregation.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-reverse-nested-aggregation.html)
Expand Down
38 changes: 38 additions & 0 deletions src/Aggregations/AvgAggregation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Spatie\ElasticsearchQueryBuilder\Aggregations;

use Spatie\ElasticsearchQueryBuilder\Aggregations\Concerns\WithMissing;

class AvgAggregation extends Aggregation
{
use WithMissing;

protected string $field;

public static function create(string $name, string $field): self
{
return new self($name, $field);
}

public function __construct(string $name, string $field)
{
$this->name = $name;
$this->field = $field;
}

public function payload(): array
{
$parameters = [
'field' => $this->field,
];

if ($this->missing !== null) {
$parameters['missing'] = $this->missing;
}

return [
'avg' => $parameters,
];
}
}
105 changes: 105 additions & 0 deletions src/Aggregations/HistogramAggregation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

namespace Spatie\ElasticsearchQueryBuilder\Aggregations;

use Spatie\ElasticsearchQueryBuilder\AggregationCollection;
use Spatie\ElasticsearchQueryBuilder\Aggregations\Concerns\WithAggregations;
use Spatie\ElasticsearchQueryBuilder\Aggregations\Concerns\WithMissing;

class HistogramAggregation extends Aggregation
{
use WithMissing;
use WithAggregations;

protected string $field;
protected float $interval;
protected ?int $minDocCount = null;
protected ?array $extendedBounds = null;
protected ?array $hardBounds = null;
protected ?float $offset = null;

public static function create(string $name, string $field, float $interval): self
{
return new self($name, $field, $interval);
}

public function __construct(string $name, string $field, float $interval)
{
$this->name = $name;
$this->field = $field;
$this->interval = $interval;
$this->aggregations = new AggregationCollection();
}

public function minDocCount(int $minDocCount): self
{
$this->minDocCount = $minDocCount;

return $this;
}

public function extendedBounds(float $min, float $max): self
{
$this->extendedBounds = [
'min' => $min,
'max' => $max,
];

return $this;
}

public function hardBounds(float $min, float $max): self
{
$this->hardBounds = [
'min' => $min,
'max' => $max,
];

return $this;
}

public function offset(float $offset): self
{
$this->offset = $offset;

return $this;
}

public function payload(): array
{
$parameters = [
'field' => $this->field,
'interval' => $this->interval,
];

if ($this->minDocCount !== null) {
$parameters['min_doc_count'] = $this->minDocCount;
}

if ($this->extendedBounds !== null) {
$parameters['extended_bounds'] = $this->extendedBounds;
}

if ($this->hardBounds !== null) {
$parameters['hard_bounds'] = $this->hardBounds;
}

if ($this->offset !== null) {
$parameters['offset'] = $this->offset;
}

if ($this->missing !== null) {
$parameters['missing'] = $this->missing;
}

$aggregation = [
'histogram' => $parameters,
];

if (! $this->aggregations->isEmpty()) {
$aggregation['aggs'] = $this->aggregations->toArray();
}

return $aggregation;
}
}
104 changes: 104 additions & 0 deletions src/Aggregations/PercentilesAggregation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace Spatie\ElasticsearchQueryBuilder\Aggregations;

use Spatie\ElasticsearchQueryBuilder\Aggregations\Concerns\WithMissing;

class PercentilesAggregation extends Aggregation
{
use WithMissing;

protected string $field;

protected array $percents;

protected ?bool $keyed = null;

protected ?int $compression = null;

protected ?string $executionHint = null;

protected ?int $numberOfSignificantValueDigits = null;

public static function create(string $name, string $field, array $percents): self
{
return new self($name, $field, $percents);
}

public function __construct(string $name, string $field, array $percents)
{
$this->name = $name;
$this->field = $field;
$this->percents = $percents;
}

public function keyed(bool $keyed = true): self
{
$this->keyed = $keyed;

return $this;
}

public function compression(int $compression): self
{
$this->compression = $compression;

return $this;
}

public function tdigest(int $compression, ?string $executionHint = null): self
{
$this->compression = $compression;
$this->executionHint = $executionHint;

return $this;
}

public function hdr(int $numberOfSignificantValueDigits): self
{
$this->numberOfSignificantValueDigits = $numberOfSignificantValueDigits;

return $this;
}

public function payload(): array
{
$parameters = [
'field' => $this->field,
'percents' => $this->percents,
];

// Add keyed parameter
if ($this->keyed !== null) {
$parameters['keyed'] = $this->keyed;
}

// Add TDigest configuration
if ($this->compression !== null || $this->executionHint !== null) {
$tdigest = [];
if ($this->compression !== null) {
$tdigest['compression'] = $this->compression;
}
if ($this->executionHint !== null) {
$tdigest['execution_hint'] = $this->executionHint;
}
$parameters['tdigest'] = $tdigest;
}

// Add HDR configuration
if ($this->numberOfSignificantValueDigits !== null) {
$parameters['hdr'] = [
'number_of_significant_value_digits' => $this->numberOfSignificantValueDigits,
];
}

// Add missing value handling
if ($this->missing !== null) {
$parameters['missing'] = $this->missing;
}

return [
'percentiles' => $parameters,
];
}
}
Loading
Loading