diff --git a/app/Jobs/EsDocument.php b/app/Jobs/EsDocument.php index 86e99955bf4..97349612d0c 100644 --- a/app/Jobs/EsDocument.php +++ b/app/Jobs/EsDocument.php @@ -17,7 +17,7 @@ class EsDocument implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable; - private array $modelMeta; + protected array $modelMeta; /** * Create a new job instance. diff --git a/app/Jobs/EsDocumentUnique.php b/app/Jobs/EsDocumentUnique.php new file mode 100644 index 00000000000..7695310b70b --- /dev/null +++ b/app/Jobs/EsDocumentUnique.php @@ -0,0 +1,25 @@ +. Licensed under the GNU Affero General Public License v3.0. +// See the LICENCE file in the repository root for full licence text. + +declare(strict_types=1); + +namespace App\Jobs; + +use Illuminate\Contracts\Queue\ShouldBeUnique; + +class EsDocumentUnique extends EsDocument implements ShouldBeUnique +{ + public int $uniqueFor = 600; + + public function __construct($model) + { + parent::__construct($model); + } + + public function uniqueId(): string + { + return "{$this->modelMeta['class']}-{$this->modelMeta['id']}"; + } +} diff --git a/app/Libraries/Search/BeatmapsetSearch.php b/app/Libraries/Search/BeatmapsetSearch.php index f88edc7f930..7727acfcd98 100644 --- a/app/Libraries/Search/BeatmapsetSearch.php +++ b/app/Libraries/Search/BeatmapsetSearch.php @@ -60,6 +60,12 @@ public function getQuery() ->should(['term' => ['_id' => ['value' => $this->params->queryString, 'boost' => 100]]]) ->should(QueryHelper::queryString($this->params->queryString, $partialMatchFields, 'or', 1 / count($terms))) ->should(QueryHelper::queryString($this->params->queryString, [], 'and')) + ->should([ + 'nested' => [ + 'path' => 'beatmaps', + 'query' => QueryHelper::queryString($this->params->queryString, ['beatmaps.top_tags'], 'or', 0.5 / count($terms)), + ], + ]) ); } diff --git a/app/Models/Beatmap.php b/app/Models/Beatmap.php index 9bda60e088d..b848e88e83c 100644 --- a/app/Models/Beatmap.php +++ b/app/Models/Beatmap.php @@ -6,7 +6,7 @@ namespace App\Models; use App\Exceptions\InvariantException; -use App\Jobs\EsDocument; +use App\Jobs\EsDocumentUnique; use App\Libraries\Transactions\AfterCommit; use App\Traits\Memoizes; use DB; @@ -223,7 +223,7 @@ public function afterCommit() $beatmapset = $this->beatmapset; if ($beatmapset !== null) { - dispatch(new EsDocument($beatmapset)); + dispatch(new EsDocumentUnique($beatmapset)); } } diff --git a/app/Models/Beatmapset.php b/app/Models/Beatmapset.php index 354155d33e7..ec1c135d9a6 100644 --- a/app/Models/Beatmapset.php +++ b/app/Models/Beatmapset.php @@ -10,7 +10,7 @@ use App\Exceptions\ImageProcessorServiceException; use App\Exceptions\InvariantException; use App\Jobs\CheckBeatmapsetCovers; -use App\Jobs\EsDocument; +use App\Jobs\EsDocumentUnique; use App\Jobs\Notifications\BeatmapsetDiscussionLock; use App\Jobs\Notifications\BeatmapsetDiscussionUnlock; use App\Jobs\Notifications\BeatmapsetDisqualify; @@ -1502,7 +1502,7 @@ public function refreshCache(bool $resetEligibleMainRulesets = false): void public function afterCommit() { - dispatch(new EsDocument($this)); + dispatch(new EsDocumentUnique($this)); } public function notificationCover() diff --git a/app/Models/Traits/Es/BeatmapsetSearch.php b/app/Models/Traits/Es/BeatmapsetSearch.php index d484ad129a1..3d872500da8 100644 --- a/app/Models/Traits/Es/BeatmapsetSearch.php +++ b/app/Models/Traits/Es/BeatmapsetSearch.php @@ -78,12 +78,17 @@ private function esBeatmapsValues() foreach ($this->beatmaps as $beatmap) { $beatmapValues = []; foreach ($mappings as $field => $mapping) { - $beatmapValues[$field] = $beatmap->$field; + $value = match ($field) { + 'top_tags' => $this->esBeatmapTags($beatmap), + // TODO: remove adding $beatmap->user_id once everything else also populated beatmap_owners by default. + // Duplicate user_id in the array should be fine for now since the field isn't scored for querying. + 'user_id' => $beatmap->beatmapOwners->pluck('user_id')->add($beatmap->user_id), + default => $beatmap->$field, + }; + + $beatmapValues[$field] = $value; } - // TODO: remove adding $beatmap->user_id once everything else also populated beatmap_owners by default. - // Duplicate user_id in the array should be fine for now since the field isn't scored for querying. - $beatmapValues['user_id'] = $beatmap->beatmapOwners->pluck('user_id')->add($beatmap->user_id); $values[] = $beatmapValues; if ($beatmap->playmode === Beatmap::MODES['osu']) { @@ -92,15 +97,10 @@ private function esBeatmapsValues() continue; } - $convert = clone $beatmap; - $convert->playmode = $modeInt; - $convert->convert = true; - $convertValues = []; - foreach ($mappings as $field => $mapping) { - $convertValues[$field] = $convert->$field; - } + $convertValues = $beatmapValues; + $convertValues['playmode'] = $modeInt; + $convertValues['convert'] = true; - $convertValues['user_id'] = $beatmapValues['user_id']; // just add a copy for converts too. $values[] = $convertValues; } } @@ -109,6 +109,18 @@ private function esBeatmapsValues() return $values; } + private function esBeatmapTags(Beatmap $beatmap): array + { + $tags = app('tags'); + + return array_filter( + array_map( + fn ($tagId) => $tags->get($tagId['tag_id'])?->name, + $beatmap->topTagIds() + ) + ); + } + private function esDifficultiesValues() { $mappings = static::esMappings()['difficulties']['properties']; diff --git a/config/schemas/beatmapsets.json b/config/schemas/beatmapsets.json index 1d938ae1086..d53485166b6 100644 --- a/config/schemas/beatmapsets.json +++ b/config/schemas/beatmapsets.json @@ -84,6 +84,9 @@ "playmode": { "type": "byte" }, + "top_tags": { + "type": "text" + }, "total_length": { "type": "long" },