added weighting properly, also different for titles vs posts
This commit is contained in:
parent
f180d66815
commit
88b3e57d8f
|
|
@ -4,6 +4,8 @@ namespace Blomstra\Search\Api\Controllers;
|
||||||
|
|
||||||
use Blomstra\Search\Elasticsearch\MatchPhraseQuery;
|
use Blomstra\Search\Elasticsearch\MatchPhraseQuery;
|
||||||
use Blomstra\Search\Elasticsearch\MatchQuery;
|
use Blomstra\Search\Elasticsearch\MatchQuery;
|
||||||
|
use Blomstra\Search\Elasticsearch\SimpleSearchQuery;
|
||||||
|
use Blomstra\Search\Elasticsearch\WildcardQuery;
|
||||||
use Blomstra\Search\Save\Document as ElasticDocument;
|
use Blomstra\Search\Save\Document as ElasticDocument;
|
||||||
use Blomstra\Search\Elasticsearch\TermsQuery;
|
use Blomstra\Search\Elasticsearch\TermsQuery;
|
||||||
use Elasticsearch\Client;
|
use Elasticsearch\Client;
|
||||||
|
|
@ -57,7 +59,9 @@ class SearchController extends ListDiscussionsController
|
||||||
if (! empty($search)) {
|
if (! empty($search)) {
|
||||||
$filterQuery
|
$filterQuery
|
||||||
->add($this->sentenceMatch($search))
|
->add($this->sentenceMatch($search))
|
||||||
->add($this->wordMatch($search));
|
->add($this->wordMatch($search))
|
||||||
|
// ->add($this->partialMatch($search))
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
$builder = (new Builder($this->elastic))
|
$builder = (new Builder($this->elastic))
|
||||||
|
|
@ -98,10 +102,12 @@ class SearchController extends ListDiscussionsController
|
||||||
if ($type === 'posts') {
|
if ($type === 'posts') {
|
||||||
return [
|
return [
|
||||||
'most_relevant_post_id' => $id,
|
'most_relevant_post_id' => $id,
|
||||||
|
'weight' => Arr::get($hit, 'sort.0')
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
return [
|
return [
|
||||||
'discussion_id' => $id,
|
'discussion_id' => $id,
|
||||||
|
'weight' => Arr::get($hit, 'sort.0')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -115,12 +121,15 @@ class SearchController extends ListDiscussionsController
|
||||||
->each(function (Discussion $discussion) use ($results) {
|
->each(function (Discussion $discussion) use ($results) {
|
||||||
if (in_array($discussion->id, $results->pluck('discussion_id')->toArray())) {
|
if (in_array($discussion->id, $results->pluck('discussion_id')->toArray())) {
|
||||||
$discussion->most_relevant_post_id = $discussion->first_post_id;
|
$discussion->most_relevant_post_id = $discussion->first_post_id;
|
||||||
|
$discussion->weight = $results->firstWhere('discussion_id', $discussion->id)['weight'] ?? 0;
|
||||||
} else {
|
} else {
|
||||||
$post = $discussion->posts()->whereIn('id', $results->pluck('most_relevant_post_id'))->first();
|
$post = $discussion->posts()->whereIn('id', $results->pluck('most_relevant_post_id'))->first();
|
||||||
$discussion->most_relevant_post_id = $post?->id ?? $discussion->first_post_id;
|
$discussion->most_relevant_post_id = $post?->id ?? $discussion->first_post_id;
|
||||||
|
$discussion->weight = $results->firstWhere('most_relevant_post_id', $post?->id)['weight'] ?? 0;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
->keyBy('id')
|
->keyBy('id')
|
||||||
|
->sortByDesc('weight')
|
||||||
->unique();
|
->unique();
|
||||||
|
|
||||||
$this->loadRelations($discussions, $include);
|
$this->loadRelations($discussions, $include);
|
||||||
|
|
@ -193,12 +202,63 @@ class SearchController extends ListDiscussionsController
|
||||||
|
|
||||||
protected function sentenceMatch(string $q): Query
|
protected function sentenceMatch(string $q): Query
|
||||||
{
|
{
|
||||||
return new MatchPhraseQuery('content', $q);
|
return BoolQuery::create()
|
||||||
|
// Discussion titles
|
||||||
|
->add(
|
||||||
|
BoolQuery::create()
|
||||||
|
->add(TermQuery::create('type', 'discussions'), 'filter')
|
||||||
|
->add((new MatchPhraseQuery('content', $q))->boost(1)),
|
||||||
|
'should'
|
||||||
|
)
|
||||||
|
// Post bodies
|
||||||
|
->add(
|
||||||
|
BoolQuery::create()
|
||||||
|
->add(TermQuery::create('type', 'posts'), 'filter')
|
||||||
|
->add((new MatchPhraseQuery('content', $q))->boost(.9)),
|
||||||
|
'should'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function wordMatch(string $q)
|
protected function wordMatch(string $q)
|
||||||
{
|
{
|
||||||
return (new MatchQuery('content', $q))->boost(.3);
|
return BoolQuery::create()
|
||||||
|
// Discussion titles
|
||||||
|
->add(
|
||||||
|
BoolQuery::create()
|
||||||
|
->add(TermQuery::create('type', 'discussions'), 'filter')
|
||||||
|
->add((new MatchQuery('content', $q))->boost(.6)),
|
||||||
|
'should'
|
||||||
|
)
|
||||||
|
// Post bodies
|
||||||
|
->add(
|
||||||
|
BoolQuery::create()
|
||||||
|
->add(TermQuery::create('type', 'posts'), 'filter')
|
||||||
|
->add((new MatchQuery('content', $q))->boost(.5)),
|
||||||
|
'should'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function partialMatch(string $q)
|
||||||
|
{
|
||||||
|
$wildcard = (new WildcardQuery('content', "*$q*"))
|
||||||
|
->caseSensitivity(false)
|
||||||
|
->rewrite('constant_score');
|
||||||
|
|
||||||
|
return BoolQuery::create()
|
||||||
|
// Discussion titles
|
||||||
|
->add(
|
||||||
|
BoolQuery::create()
|
||||||
|
->add(TermQuery::create('type', 'discussions'), 'filter')
|
||||||
|
->add($wildcard->boost(.3)),
|
||||||
|
'should'
|
||||||
|
)
|
||||||
|
// Post bodies
|
||||||
|
->add(
|
||||||
|
BoolQuery::create()
|
||||||
|
->add(TermQuery::create('type', 'posts'), 'filter')
|
||||||
|
->add($wildcard->boost(.5)),
|
||||||
|
'should'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Blomstra\Search\Elasticsearch;
|
||||||
|
|
||||||
|
use Spatie\ElasticsearchQueryBuilder\Queries\Query;
|
||||||
|
|
||||||
|
class SimpleSearchQuery implements Query
|
||||||
|
{
|
||||||
|
protected float $boost = 1;
|
||||||
|
|
||||||
|
public static function create(array $field, string $value)
|
||||||
|
{
|
||||||
|
return new self($field, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function boost(float $boost = 1)
|
||||||
|
{
|
||||||
|
$this->boost = $boost;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
protected array $fields,
|
||||||
|
protected string $value
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'simple_query_string' => [
|
||||||
|
'query' => $this->value,
|
||||||
|
'fields' => $this->fields,
|
||||||
|
'boost' => $this->boost
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Blomstra\Search\Elasticsearch;
|
||||||
|
|
||||||
|
class WildcardQuery extends \Spatie\ElasticsearchQueryBuilder\Queries\WildcardQuery
|
||||||
|
{
|
||||||
|
protected float $boost = 1;
|
||||||
|
protected bool $sensitivity = true;
|
||||||
|
protected ?string $rewrite = null;
|
||||||
|
|
||||||
|
public function boost(float $boost = 1)
|
||||||
|
{
|
||||||
|
$this->boost = $boost;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function caseSensitivity(bool $sensitivity = true)
|
||||||
|
{
|
||||||
|
$this->sensitivity = $sensitivity;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewrite(string $rewrite = null)
|
||||||
|
{
|
||||||
|
$this->rewrite = $rewrite;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray(): array
|
||||||
|
{
|
||||||
|
$query = parent::toArray();
|
||||||
|
|
||||||
|
$query['wildcard'][$this->field]['boost'] = $this->boost;
|
||||||
|
$query['wildcard'][$this->field]['case_insensitive'] = ! $this->sensitivity;
|
||||||
|
|
||||||
|
if ($this->rewrite) {
|
||||||
|
$query['wildcard'][$this->field]['rewrite'] = $this->rewrite;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue