Skip to content

Commit

Permalink
Merge pull request #207 from Jeroen-G/rework-rescore-to-query-properties
Browse files Browse the repository at this point in the history
Rework rescoring to be query property
  • Loading branch information
Jeroen-G committed Sep 21, 2023
2 parents fc68836 + 93db134 commit 13f4656
Show file tree
Hide file tree
Showing 11 changed files with 288 additions and 64 deletions.
71 changes: 34 additions & 37 deletions src/Domain/Query/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,23 @@
namespace JeroenG\Explorer\Domain\Query;

use JeroenG\Explorer\Domain\Aggregations\AggregationSyntaxInterface;
use JeroenG\Explorer\Domain\Query\QueryProperties\Combinable;
use JeroenG\Explorer\Domain\Query\QueryProperties\QueryProperty;
use JeroenG\Explorer\Domain\Query\QueryProperties\SourceFilter;
use JeroenG\Explorer\Domain\Query\QueryProperties\Rescorers;
use JeroenG\Explorer\Domain\Query\QueryProperties\Rescoring;
use JeroenG\Explorer\Domain\Query\QueryProperties\Sorting;
use JeroenG\Explorer\Domain\Syntax\Sort;
use JeroenG\Explorer\Domain\Syntax\SyntaxInterface;
use Webmozart\Assert\Assert;

class Query implements SyntaxInterface
{
private ?int $offset = null;

private ?int $limit = null;

/** @var Rescoring[] */
private array $rescoring = [];

private array $fields = [];

/** @var Sort[] */
private array $sort = [];

/** @var QueryProperty[] */
private array $queryProperties = [];

Expand Down Expand Up @@ -53,31 +51,20 @@ public function build(): array
$query['size'] = $this->limit;
}

if ($this->hasSort()) {
$query['sort'] = $this->buildSort();
}

if ($this->hasFields()) {
$query['fields'] = $this->fields;
}

if ($this->hasRescoring()) {
$query['rescore'] = $this->buildRescoring();
}

if ($this->hasAggregations()) {
$query['aggs'] = array_map(
fn (AggregationSyntaxInterface $value) => $value->build(),
$this->aggregations
);
}

$allQueryProperties = array_map(
static fn (QueryProperty $queryProperties) => $queryProperties->build(),
$this->queryProperties
);
$queryProperties = $this->buildQueryProperties();

return array_merge($query, ...$allQueryProperties);
return array_merge($query, ...$queryProperties);
}

public function setOffset(?int $offset): void
Expand All @@ -97,7 +84,14 @@ public function setFields(array $fields): void

public function setSort(array $sort): void
{
$this->sort = $sort;
$this->queryProperties = array_filter(
$this->queryProperties,
static fn (QueryProperty $queryProperty) => !($queryProperty instanceof Sorting)
);

if (count($sort) > 0) {
$this->queryProperties[] = Sorting::for(...$sort);
}
}

public function setQuery(SyntaxInterface $query): void
Expand All @@ -112,7 +106,7 @@ public function addQueryProperties(QueryProperty ...$properties): void

public function addRescoring(Rescoring $rescoring): void
{
$this->rescoring[] = $rescoring;
$this->queryProperties[] = Rescorers::for($rescoring);
}

public function addAggregation(string $name, AggregationSyntaxInterface $aggregationItem): void
Expand All @@ -135,28 +129,31 @@ private function hasSize(): bool
return !is_null($this->limit);
}

private function hasSort(): bool
{
return !empty($this->sort);
}

private function hasFields(): bool
{
return !empty($this->fields);
}

private function buildSort(): array
private function buildQueryProperties(): array
{
return array_map(static fn ($item) => $item->build(), $this->sort);
}
/** @var array<class-string, array<Combinable&QueryProperty>> $allCombinables */
$allCombinables = [];
$allQueryProperties = [];

private function hasRescoring(): bool
{
return !empty($this->rescoring);
}
foreach ($this->queryProperties as $queryProperty) {
if ($queryProperty instanceof Combinable) {
$allCombinables[get_class($queryProperty)] = $allCombinables[get_class($queryProperty)] ?? [];
$allCombinables[get_class($queryProperty)][] = $queryProperty;
} else {
$allQueryProperties[] = $queryProperty;
}
}

private function buildRescoring(): array
{
return array_map(fn (Rescoring $rescore) => $rescore->build(), $this->rescoring);
/** @var array<Combinable&QueryProperty> $sameCombinables */
foreach ($allCombinables as $sameCombinables) {
$allQueryProperties[] = $sameCombinables[0]->combine(...array_slice($sameCombinables, 1));
}

return array_map(static fn (QueryProperty $queryProperty) => $queryProperty->build(), $allQueryProperties);
}
}
13 changes: 13 additions & 0 deletions src/Domain/Query/QueryProperties/Combinable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace JeroenG\Explorer\Domain\Query\QueryProperties;

interface Combinable
{
/**
* @param static ...$self
*/
public function combine(...$self): QueryProperty;
}
34 changes: 34 additions & 0 deletions src/Domain/Query/QueryProperties/Rescorers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace JeroenG\Explorer\Domain\Query\QueryProperties;

final class Rescorers implements QueryProperty, Combinable
{
private function __construct(
private array $rescoringQueries = [],
) {}

public static function for(Rescoring ...$rescoring): self
{
return new self($rescoring);
}

public function build(): array
{
return [
'rescore' => array_map(static fn (Rescoring $rescoring) => $rescoring->build(), $this->rescoringQueries),
];
}

public function combine(...$self): self
{
$all = $this->rescoringQueries;
foreach($self as $rescorer) {
array_push($all, ...$rescorer->rescoringQueries);
}

return new self($all);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

declare(strict_types=1);

namespace JeroenG\Explorer\Domain\Query;
namespace JeroenG\Explorer\Domain\Query\QueryProperties;

use JeroenG\Explorer\Domain\Syntax\SyntaxInterface;

class Rescoring implements SyntaxInterface
class Rescoring
{
public const SCORE_MODE_TOTAL = 'total';

Expand All @@ -28,6 +28,13 @@ class Rescoring implements SyntaxInterface

private SyntaxInterface $query;

public static function create(SyntaxInterface $query): self
{
$rescore = new self();
$rescore->query = $query;
return $rescore;
}

public function build(): array
{
return [
Expand Down
42 changes: 42 additions & 0 deletions src/Domain/Query/QueryProperties/Sorting.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace JeroenG\Explorer\Domain\Query\QueryProperties;

use JeroenG\Explorer\Domain\Syntax\Sort;

final class Sorting implements QueryProperty, Combinable
{
/** @param Sort[] $sorts */
private function __construct(private array $sorts = [])
{
}

public static function for(Sort ...$sort): self
{
return new self($sort);
}

public function combine(...$self): QueryProperty
{
$all = $this->sorts;

/** @var Sorting[] $self */
foreach($self as $sorting) {
array_push($all, ...$sorting->sorts);
}

return new self($all);
}

public function build(): array
{
return [
'sort' => array_map(
static fn (Sort $sort) => $sort->build(),
$this->sorts,
),
];
}
}
2 changes: 1 addition & 1 deletion src/Domain/Syntax/Sort.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Webmozart\Assert\Assert;

class Sort implements SyntaxInterface
class Sort
{
public const ASCENDING = 'asc';

Expand Down
72 changes: 72 additions & 0 deletions tests/Unit/Domain/Query/QueryProperties/RescorersTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace JeroenG\Explorer\Tests\Unit\Domain\Query\QueryProperties;

use JeroenG\Explorer\Domain\Query\QueryProperties\Rescorers;
use JeroenG\Explorer\Domain\Query\QueryProperties\Rescoring;
use JeroenG\Explorer\Domain\Syntax\MatchAll;
use JeroenG\Explorer\Domain\Syntax\Term;
use PHPUnit\Framework\TestCase;

final class RescorersTest extends TestCase
{
public function test_it_builds(): void
{
$sort = Rescorers::for(
Rescoring::create(new Term(':fld:', ':val:')),
);

self::assertSame(['rescore' => [self::rescoreQueryPart(':fld:', ':val:')]], $sort->build());
}

public function test_it_combines(): void
{
$a = Rescorers::for(
Rescoring::create(new Term(':fld1:', ':val1:')),
Rescoring::create(new Term(':fld2:', ':val2:')),
);
$b = Rescorers::for(
Rescoring::create(new Term(':fld3:', ':val3:')),
Rescoring::create(new Term(':fld4:', ':val4:')),
);
$c = Rescorers::for(
Rescoring::create(new Term(':fld5:', ':val5:')),
);
$d = Rescorers::for();

$result = $a->combine($b, $c, $d);

self::assertNotSame($a->build(), $result->build());
self::assertSame([
'rescore' => [
self::rescoreQueryPart(':fld1:', ':val1:'),
self::rescoreQueryPart(':fld2:', ':val2:'),
self::rescoreQueryPart(':fld3:', ':val3:'),
self::rescoreQueryPart(':fld4:', ':val4:'),
self::rescoreQueryPart(':fld5:', ':val5:'),
],
], $result->build());
}

private static function rescoreQueryPart(string $fld, string $val): array
{
return [
'window_size' => 10,
'query' => [
'score_mode' => 'total',
'rescore_query' => [
'term' => [
$fld => [
'value' => $val,
'boost' => 1.0,
]
]
],
'query_weight' => 1.0,
'rescore_query_weight' => 1.0,
]
];
}
}
50 changes: 50 additions & 0 deletions tests/Unit/Domain/Query/QueryProperties/SortingTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace JeroenG\Explorer\Tests\Unit\Domain\Query\QueryProperties;

use JeroenG\Explorer\Domain\Query\QueryProperties\Sorting;
use JeroenG\Explorer\Domain\Syntax\Sort;
use PHPUnit\Framework\TestCase;

final class SortingTest extends TestCase
{
public function test_it_builds_sorting(): void
{
$sort = Sorting::for(
new Sort(':fld:', Sort::DESCENDING),
);

self::assertSame([ 'sort' => [ [ ':fld:' => 'desc' ]]],$sort->build());
}

public function test_it_combines(): void
{
$a = Sorting::for(
new Sort(':fld1:', Sort::DESCENDING),
new Sort(':fld2:', Sort::DESCENDING),
);
$b = Sorting::for(
new Sort(':fld3:', Sort::DESCENDING),
new Sort(':fld4:', Sort::DESCENDING),
);
$c = Sorting::for(
new Sort(':fld5:', Sort::DESCENDING),
);
$d = Sorting::for();

$result = $a->combine($b, $c, $d);

self::assertNotSame($a->build(), $result->build());
self::assertSame([
'sort' => [
[ ':fld1:' => 'desc' ],
[ ':fld2:' => 'desc' ],
[ ':fld3:' => 'desc' ],
[ ':fld4:' => 'desc' ],
[ ':fld5:' => 'desc' ],
],
], $result->build());
}
}
Loading

0 comments on commit 13f4656

Please sign in to comment.