Skip to content

Commit f475bb8

Browse files
committed
IDBPR-2554 Add whereMoreLikeThis and addFunctionScore
1 parent bca5696 commit f475bb8

File tree

10 files changed

+282
-0
lines changed

10 files changed

+282
-0
lines changed

src/Concerns/DecoratesBoolQuery.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
namespace Ensi\LaravelElasticQuery\Concerns;
44

55
use Closure;
6+
use Ensi\LaravelElasticQuery\Contracts\FunctionScoreOptions;
67
use Ensi\LaravelElasticQuery\Contracts\MatchOptions;
8+
use Ensi\LaravelElasticQuery\Contracts\MoreLikeOptions;
79
use Ensi\LaravelElasticQuery\Contracts\MultiMatchOptions;
810
use Ensi\LaravelElasticQuery\Contracts\WildcardOptions;
911
use Ensi\LaravelElasticQuery\Filtering\BoolQueryBuilder;
12+
use Ensi\LaravelElasticQuery\Filtering\Criterias\FunctionScoreItem;
13+
use Ensi\LaravelElasticQuery\Filtering\Criterias\MoreLikeThis;
1014
use Illuminate\Contracts\Support\Arrayable;
1115
use Illuminate\Support\Traits\ForwardsCalls;
1216

@@ -141,4 +145,22 @@ public function addMustBool(callable $fn): static
141145

142146
return $this;
143147
}
148+
149+
public function whereMoreLikeThis(array $fields, MoreLikeThis $likeThis, ?MoreLikeOptions $options = null): static
150+
{
151+
$this->forwardCallTo($this->boolQuery(), __FUNCTION__, func_get_args());
152+
153+
return $this;
154+
}
155+
156+
/**
157+
* @param array<FunctionScoreItem> $functions
158+
* @param ?FunctionScoreOptions $options
159+
*/
160+
public function addFunctionScore(array $functions, ?FunctionScoreOptions $options = null): static
161+
{
162+
$this->forwardCallTo($this->boolQuery(), __FUNCTION__, func_get_args());
163+
164+
return $this;
165+
}
144166
}

src/Contracts/BoostMode.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuery\Contracts;
4+
5+
class BoostMode
6+
{
7+
public const MULTIPLY = 'multiply';
8+
public const REPLACE = 'replace';
9+
public const SUM = 'sum';
10+
public const AVG = 'avg';
11+
public const MAX = 'max';
12+
public const MIN = 'min';
13+
14+
public static function cases(): array
15+
{
16+
return [
17+
self::MULTIPLY,
18+
self::SUM,
19+
self::AVG,
20+
self::REPLACE,
21+
self::MAX,
22+
self::MIN,
23+
];
24+
}
25+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuery\Contracts;
4+
5+
use Illuminate\Contracts\Support\Arrayable;
6+
use Webmozart\Assert\Assert;
7+
8+
class FunctionScoreOptions implements Arrayable
9+
{
10+
public function __construct(private array $options = [])
11+
{
12+
}
13+
14+
public static function make(
15+
?string $scoreMode = null,
16+
?string $boostMode = null,
17+
): static {
18+
Assert::oneOf($scoreMode, ScoreMode::cases());
19+
Assert::oneOf($boostMode, BoostMode::cases());
20+
21+
return new static(array_filter([
22+
'score_mode' => $scoreMode,
23+
'boost_mode' => $boostMode,
24+
]));
25+
}
26+
27+
public function toArray(): array
28+
{
29+
return $this->options;
30+
}
31+
}

src/Contracts/MoreLikeOptions.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuery\Contracts;
4+
5+
use Illuminate\Contracts\Support\Arrayable;
6+
7+
class MoreLikeOptions implements Arrayable
8+
{
9+
public function __construct(private array $options = [])
10+
{
11+
}
12+
13+
public static function make(
14+
?int $minTermFreq = null,
15+
?int $maxQueryTerms = null,
16+
?string $minimumShouldMatch = null,
17+
): static {
18+
19+
return new static(array_filter([
20+
'min_term_freq' => $minTermFreq,
21+
'max_query_terms' => $maxQueryTerms,
22+
'minimum_should_match' => $minimumShouldMatch,
23+
]));
24+
}
25+
26+
public function toArray(): array
27+
{
28+
return $this->options;
29+
}
30+
}

src/Contracts/ScoreMode.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuery\Contracts;
4+
5+
class ScoreMode
6+
{
7+
public const MULTIPLY = 'multiply';
8+
public const SUM = 'sum';
9+
public const AVG = 'avg';
10+
public const FIRST = 'first';
11+
public const MAX = 'max';
12+
public const MIN = 'min';
13+
14+
public static function cases(): array
15+
{
16+
return [
17+
self::MULTIPLY,
18+
self::SUM,
19+
self::AVG,
20+
self::FIRST,
21+
self::MAX,
22+
self::MIN,
23+
];
24+
}
25+
}

src/Filtering/BoolQueryBuilder.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@
66
use Ensi\LaravelElasticQuery\Concerns\SupportsPath;
77
use Ensi\LaravelElasticQuery\Contracts\BoolQuery;
88
use Ensi\LaravelElasticQuery\Contracts\Criteria;
9+
use Ensi\LaravelElasticQuery\Contracts\FunctionScoreOptions;
910
use Ensi\LaravelElasticQuery\Contracts\MatchOptions;
11+
use Ensi\LaravelElasticQuery\Contracts\MoreLikeOptions;
1012
use Ensi\LaravelElasticQuery\Contracts\MultiMatchOptions;
1113
use Ensi\LaravelElasticQuery\Contracts\WildcardOptions;
14+
use Ensi\LaravelElasticQuery\Filtering\Criterias\FunctionScoreItem;
15+
use Ensi\LaravelElasticQuery\Filtering\Criterias\MoreLikeThis;
1216
use Ensi\LaravelElasticQuery\Filtering\Criterias\Exists;
17+
use Ensi\LaravelElasticQuery\Filtering\Criterias\FunctionScore;
18+
use Ensi\LaravelElasticQuery\Filtering\Criterias\MoreLike;
1319
use Ensi\LaravelElasticQuery\Filtering\Criterias\MultiMatch;
1420
use Ensi\LaravelElasticQuery\Filtering\Criterias\Nested;
1521
use Ensi\LaravelElasticQuery\Filtering\Criterias\OneMatch;
@@ -245,6 +251,24 @@ protected function makeWildcard(string $field, string $query, ?WildcardOptions $
245251
return new Wildcard($this->absolutePath($field), $query, $options ?: new WildcardOptions());
246252
}
247253

254+
public function whereMoreLikeThis(array $fields, MoreLikeThis $likeThis, ?MoreLikeOptions $options = null): static
255+
{
256+
$this->must->add(new MoreLike($fields, $likeThis, $options));
257+
258+
return $this;
259+
}
260+
261+
/**
262+
* @param array<FunctionScoreItem> $functions
263+
* @param ?FunctionScoreOptions $options
264+
*/
265+
public function addFunctionScore(array $functions, ?FunctionScoreOptions $options = null): static
266+
{
267+
$this->should->add(new FunctionScore($functions, $options));
268+
269+
return $this;
270+
}
271+
248272
public function addMustBool(callable $fn): static
249273
{
250274
$this->must->add(static::make(builder: $fn));
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuery\Filtering\Criterias;
4+
5+
use Ensi\LaravelElasticQuery\Contracts\Criteria;
6+
use Ensi\LaravelElasticQuery\Contracts\FunctionScoreOptions;
7+
use Ensi\LaravelElasticQuery\Filtering\Criterias\FunctionScoreItem;
8+
use stdClass;
9+
use Webmozart\Assert\Assert;
10+
11+
class FunctionScore implements Criteria
12+
{
13+
/**
14+
* @param array<FunctionScoreItem> $functions
15+
* @param FunctionScoreOptions|null $options
16+
*/
17+
public function __construct(
18+
private array $functions,
19+
private ?FunctionScoreOptions $options = null,
20+
) {
21+
array_map(fn ($function) => Assert::isInstanceOfAny($function, [FunctionScoreItem::class]), $functions);
22+
}
23+
24+
public function toDSL(): array
25+
{
26+
$body = [
27+
'query' => ['match_all' => new stdClass()],
28+
'functions' => array_map(fn (FunctionScoreItem $function) => $function->toDSL(), $this->functions),
29+
];
30+
31+
if ($this->options) {
32+
$body = array_merge($this->options->toArray(), $body);
33+
}
34+
35+
return ['function_score' => $body];
36+
}
37+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuery\Filtering\Criterias;
4+
5+
use Ensi\LaravelElasticQuery\Contracts\Criteria;
6+
7+
class FunctionScoreItem implements Criteria
8+
{
9+
public function __construct(
10+
private int $weight,
11+
private Criteria $filter,
12+
) {
13+
}
14+
15+
public function toDSL(): array
16+
{
17+
return [
18+
'weight' => $this->weight,
19+
'filter' => $this->filter->toDSL(),
20+
];
21+
}
22+
}

src/Filtering/Criterias/MoreLike.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuery\Filtering\Criterias;
4+
5+
use Ensi\LaravelElasticQuery\Contracts\Criteria;
6+
use Ensi\LaravelElasticQuery\Contracts\MoreLikeOptions;
7+
use Ensi\LaravelElasticQuery\Filtering\Criterias\MoreLikeThis;
8+
use Webmozart\Assert\Assert;
9+
10+
class MoreLike implements Criteria
11+
{
12+
public function __construct(
13+
private array $fields,
14+
private MoreLikeThis $likeThis,
15+
private ?MoreLikeOptions $options = null,
16+
) {
17+
Assert::minCount($fields, 1);
18+
array_map(Assert::stringNotEmpty(...), $fields);
19+
}
20+
21+
public function toDSL(): array
22+
{
23+
$body = [
24+
'fields' => $this->fields,
25+
'like' => $this->likeThis->toDSL(),
26+
];
27+
28+
if ($this->options) {
29+
$body = array_merge($this->options->toArray(), $body);
30+
}
31+
32+
return ['more_like_this' => $body];
33+
}
34+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuery\Filtering\Criterias;
4+
5+
use Ensi\LaravelElasticQuery\Contracts\Criteria;
6+
7+
class MoreLikeThis implements Criteria
8+
{
9+
private array $this = [];
10+
11+
public function addId(string $id, ?string $index = null): static
12+
{
13+
$this->this[] = array_filter([
14+
'_id' => $id,
15+
'_index' => $index,
16+
]);
17+
18+
return $this;
19+
}
20+
21+
public function addString(string $token): static
22+
{
23+
$this->this[] = $token;
24+
25+
return $this;
26+
}
27+
28+
public function toDSL(): array
29+
{
30+
return $this->this;
31+
}
32+
}

0 commit comments

Comments
 (0)