Skip to content

Commit 204a150

Browse files
authored
Merge pull request #85 from ensi-platform/idbpr-2554
IDBPR-2554 Add whereMoreLikeThis and addFunctionScore
2 parents bca5696 + 9ed6647 commit 204a150

File tree

12 files changed

+368
-0
lines changed

12 files changed

+368
-0
lines changed

src/Concerns/DecoratesBoolQuery.php

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

55
use Closure;
6+
use Ensi\LaravelElasticQuery\Contracts\DSLAware;
7+
use Ensi\LaravelElasticQuery\Contracts\FunctionScoreItem;
8+
use Ensi\LaravelElasticQuery\Contracts\FunctionScoreOptions;
69
use Ensi\LaravelElasticQuery\Contracts\MatchOptions;
10+
use Ensi\LaravelElasticQuery\Contracts\MoreLikeOptions;
11+
use Ensi\LaravelElasticQuery\Contracts\MoreLikeThis;
712
use Ensi\LaravelElasticQuery\Contracts\MultiMatchOptions;
813
use Ensi\LaravelElasticQuery\Contracts\WildcardOptions;
914
use Ensi\LaravelElasticQuery\Filtering\BoolQueryBuilder;
@@ -141,4 +146,23 @@ public function addMustBool(callable $fn): static
141146

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

src/Contracts/BoolQuery.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,13 @@ public function whereWildcard(string $field, string $query, ?WildcardOptions $op
4242
public function orWhereWildcard(string $field, string $query, ?WildcardOptions $options = null): static;
4343

4444
public function addMustBool(callable $fn): static;
45+
46+
public function whereMoreLikeThis(array $fields, MoreLikeThis $likeThis, ?MoreLikeOptions $options = null): static;
47+
48+
/**
49+
* @param array<FunctionScoreItem> $functions
50+
* @param ?DSLAware $query
51+
* @param ?FunctionScoreOptions $options
52+
*/
53+
public function addFunctionScore(array $functions, ?DSLAware $query = null, ?FunctionScoreOptions $options = null): static;
4554
}

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+
}

src/Contracts/FunctionScoreItem.php

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\Contracts;
4+
5+
use Illuminate\Contracts\Support\Arrayable;
6+
7+
class FunctionScoreItem implements Arrayable
8+
{
9+
public function __construct(
10+
private int $weight,
11+
private Criteria $filter,
12+
) {
13+
}
14+
15+
public function toArray(): array
16+
{
17+
return [
18+
'weight' => $this->weight,
19+
'filter' => $this->filter->toDSL(),
20+
];
21+
}
22+
}
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::nullOrOneOf($scoreMode, ScoreMode::cases());
19+
Assert::nullOrOneOf($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: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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 $maxQueryTerms = null,
15+
?int $minTermFreq = null,
16+
?int $minDocFreq = null,
17+
?int $maxDocFreq = null,
18+
?int $minWordLength = null,
19+
?int $maxWordLength = null,
20+
?array $stopWords = null,
21+
?string $analyzer = null,
22+
?string $minimumShouldMatch = null,
23+
): static {
24+
25+
return new static(array_filter([
26+
'max_query_terms' => $maxQueryTerms,
27+
'min_term_freq' => $minTermFreq,
28+
'min_doc_freq' => $minDocFreq,
29+
'max_doc_freq' => $maxDocFreq,
30+
'min_word_length' => $minWordLength,
31+
'max_word_length' => $maxWordLength,
32+
'stop_words' => $stopWords,
33+
'analyzer' => $analyzer,
34+
'minimum_should_match' => $minimumShouldMatch,
35+
]));
36+
}
37+
38+
public function toArray(): array
39+
{
40+
return $this->options;
41+
}
42+
}

src/Contracts/MoreLikeThis.php

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\Contracts;
4+
5+
use Illuminate\Contracts\Support\Arrayable;
6+
7+
class MoreLikeThis implements Arrayable
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 toArray(): array
29+
{
30+
return $this->this;
31+
}
32+
}

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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,17 @@
66
use Ensi\LaravelElasticQuery\Concerns\SupportsPath;
77
use Ensi\LaravelElasticQuery\Contracts\BoolQuery;
88
use Ensi\LaravelElasticQuery\Contracts\Criteria;
9+
use Ensi\LaravelElasticQuery\Contracts\DSLAware;
10+
use Ensi\LaravelElasticQuery\Contracts\FunctionScoreItem;
11+
use Ensi\LaravelElasticQuery\Contracts\FunctionScoreOptions;
912
use Ensi\LaravelElasticQuery\Contracts\MatchOptions;
13+
use Ensi\LaravelElasticQuery\Contracts\MoreLikeOptions;
14+
use Ensi\LaravelElasticQuery\Contracts\MoreLikeThis;
1015
use Ensi\LaravelElasticQuery\Contracts\MultiMatchOptions;
1116
use Ensi\LaravelElasticQuery\Contracts\WildcardOptions;
1217
use Ensi\LaravelElasticQuery\Filtering\Criterias\Exists;
18+
use Ensi\LaravelElasticQuery\Filtering\Criterias\FunctionScore;
19+
use Ensi\LaravelElasticQuery\Filtering\Criterias\MoreLike;
1320
use Ensi\LaravelElasticQuery\Filtering\Criterias\MultiMatch;
1421
use Ensi\LaravelElasticQuery\Filtering\Criterias\Nested;
1522
use Ensi\LaravelElasticQuery\Filtering\Criterias\OneMatch;
@@ -245,6 +252,25 @@ protected function makeWildcard(string $field, string $query, ?WildcardOptions $
245252
return new Wildcard($this->absolutePath($field), $query, $options ?: new WildcardOptions());
246253
}
247254

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

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\Contracts\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->toArray(),
26+
];
27+
28+
if ($this->options) {
29+
$body = array_merge($this->options->toArray(), $body);
30+
}
31+
32+
return ['more_like_this' => $body];
33+
}
34+
}

0 commit comments

Comments
 (0)