mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-22 04:58:01 +01:00
#1: Search relevancy improvements and other tweaks.
This commit is contained in:
parent
7a7f4ee02a
commit
56edd5ec28
10 changed files with 143 additions and 55 deletions
|
@ -43,7 +43,7 @@ class Search {
|
|||
* @param int $resultsPerContentType
|
||||
* @return array
|
||||
*/
|
||||
public function searchAllContent(string $query, int $resultsPerContentType = 10) {
|
||||
public function searchAllContent(string $query) {
|
||||
$results = $this->elasticsearch->msearch([
|
||||
'index' => $this->index,
|
||||
'body' => [
|
||||
|
@ -60,9 +60,10 @@ class Search {
|
|||
'track_type',
|
||||
'show_songs^2',
|
||||
],
|
||||
'tie_breaker' => 0.3,
|
||||
],
|
||||
],
|
||||
'size' => $resultsPerContentType
|
||||
'size' => 11
|
||||
],
|
||||
|
||||
//===== Albums =====//
|
||||
|
@ -76,9 +77,10 @@ class Search {
|
|||
'artist',
|
||||
'tracks',
|
||||
],
|
||||
'tie_breaker' => 0.3,
|
||||
],
|
||||
],
|
||||
'size' => $resultsPerContentType
|
||||
'size' => 3
|
||||
],
|
||||
|
||||
//===== Playlists =====//
|
||||
|
@ -92,9 +94,10 @@ class Search {
|
|||
'curator',
|
||||
'tracks^2',
|
||||
],
|
||||
'tie_breaker' => 0.3,
|
||||
],
|
||||
],
|
||||
'size' => $resultsPerContentType
|
||||
'size' => 3
|
||||
],
|
||||
|
||||
//===== Users =====//
|
||||
|
@ -104,12 +107,13 @@ class Search {
|
|||
'multi_match' => [
|
||||
'query' => $query,
|
||||
'fields' => [
|
||||
'display_name^2',
|
||||
'display_name',
|
||||
'tracks',
|
||||
],
|
||||
'tie_breaker' => 0.3,
|
||||
],
|
||||
],
|
||||
'size' => $resultsPerContentType
|
||||
'size' => 3
|
||||
],
|
||||
]
|
||||
]);
|
||||
|
|
|
@ -420,4 +420,11 @@ class Album extends Model
|
|||
'tracks' => $this->tracks->pluck('title'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function shouldBeIndexed():bool {
|
||||
return $this->track_count > 0 && !$this->trashed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,19 @@ class Playlist extends Model
|
|||
|
||||
protected $table = 'playlists';
|
||||
protected $dates = ['deleted_at'];
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'user_id' => 'integer',
|
||||
'title' => 'string',
|
||||
'description' => 'string',
|
||||
'is_public' => 'boolean',
|
||||
'track_count' => 'integer',
|
||||
'view_count' => 'integer',
|
||||
'download_count' => 'integer',
|
||||
'favourte_count' => 'integer',
|
||||
'follow_count' => 'integer',
|
||||
'comment_count' => 'integer',
|
||||
];
|
||||
|
||||
public static function summary()
|
||||
{
|
||||
|
@ -301,4 +314,13 @@ class Playlist extends Model
|
|||
'tracks' => $this->tracks->pluck('title'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function shouldBeIndexed():bool {
|
||||
return $this->is_public &&
|
||||
$this->track_count > 0 &&
|
||||
!$this->trashed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -831,9 +831,20 @@ class Track extends Model
|
|||
return 'track-' . $this->id . '-' . $key;
|
||||
}
|
||||
|
||||
//============= Elasticsearch stuff ==================//
|
||||
|
||||
public function toElasticsearch() {
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function shouldBeIndexed():bool {
|
||||
return $this->is_listed &&
|
||||
$this->published_at !== null &&
|
||||
!$this->trashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function toElasticsearch():array {
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'artist' => $this->user->display_name,
|
||||
|
|
|
@ -279,4 +279,11 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||
'tracks' => $this->tracks->pluck('title'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function shouldBeIndexed():bool {
|
||||
return $this->disabled_at === null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
namespace Poniverse\Ponyfm\Traits;
|
||||
|
||||
use Elasticsearch;
|
||||
use Elasticsearch\Common\Exceptions\Missing404Exception;
|
||||
|
||||
/**
|
||||
* Class IndexedInElasticsearch
|
||||
|
@ -40,13 +41,19 @@ trait IndexedInElasticsearchTrait
|
|||
*/
|
||||
abstract public function toElasticsearch();
|
||||
|
||||
public static function bootIndexedInElasticsearch() {
|
||||
/**
|
||||
* @return bool whether this particular object should be indexed or not
|
||||
*/
|
||||
abstract public function shouldBeIndexed():bool;
|
||||
|
||||
|
||||
public static function bootIndexedInElasticsearchTrait() {
|
||||
static::saved(function ($model) {
|
||||
$model->createOrUpdateElasticsearchEntry();
|
||||
$model->ensureElasticsearchEntryIsUpToDate();
|
||||
});
|
||||
|
||||
static::deleted(function ($model) {
|
||||
$model->deleteElasticsearchEntry();
|
||||
$model->ensureElasticsearchEntryIsUpToDate();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -76,17 +83,17 @@ trait IndexedInElasticsearchTrait
|
|||
try {
|
||||
Elasticsearch::connection()->delete($this->getElasticsearchParameters(false));
|
||||
|
||||
} catch (\Elasticsearch\Common\Exceptions\Missing404Exception $e) {
|
||||
// If the track we're trying to delete isn't indexed in Elasticsearch,
|
||||
} catch (Missing404Exception $e) {
|
||||
// If the entity we're trying to delete isn't indexed in Elasticsearch,
|
||||
// that's fine.
|
||||
}
|
||||
}
|
||||
|
||||
public function ensureElasticsearchEntryIsUpToDate() {
|
||||
if (method_exists($this, 'trashed') && $this->trashed()) {
|
||||
$this->deleteElasticsearchEntry();
|
||||
} else {
|
||||
if ($this->shouldBeIndexed()) {
|
||||
$this->createOrUpdateElasticsearchEntry();
|
||||
} else {
|
||||
$this->deleteElasticsearchEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,17 +40,17 @@ class SetupElasticsearch extends Migration
|
|||
'_source' => ['enabled' => true],
|
||||
'dynamic' => 'strict',
|
||||
'properties' => [
|
||||
'title' => ['type' => 'string'],
|
||||
'artist' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||
'title' => ['type' => 'string', 'analyzer' => 'english'],
|
||||
'artist' => ['type' => 'string'],
|
||||
|
||||
'published_at' => ['type' => 'date'],
|
||||
'genre' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||
'genre' => ['type' => 'string', 'analyzer' => 'english'],
|
||||
'track_type' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||
|
||||
// This field is intended to be used as an array.
|
||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
||||
'show_songs' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||
'show_songs' => ['type' => 'string'],
|
||||
]
|
||||
],
|
||||
|
||||
|
@ -58,13 +58,13 @@ class SetupElasticsearch extends Migration
|
|||
'_source' => ['enabled' => true],
|
||||
'dynamic' => 'strict',
|
||||
'properties' => [
|
||||
'title' => ['type' => 'string'],
|
||||
'artist' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||
'title' => ['type' => 'string', 'analyzer' => 'english'],
|
||||
'artist' => ['type' => 'string'],
|
||||
|
||||
// This field is intended to be used as an array.
|
||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
||||
'tracks' => ['type' => 'string']
|
||||
'tracks' => ['type' => 'string', 'analyzer' => 'english']
|
||||
]
|
||||
],
|
||||
|
||||
|
@ -72,13 +72,13 @@ class SetupElasticsearch extends Migration
|
|||
'_source' => ['enabled' => true],
|
||||
'dynamic' => 'strict',
|
||||
'properties' => [
|
||||
'title' => ['type' => 'string'],
|
||||
'curator' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||
'title' => ['type' => 'string', 'analyzer' => 'english'],
|
||||
'curator' => ['type' => 'string'],
|
||||
|
||||
// This field is intended to be used as an array.
|
||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
||||
'tracks' => ['type' => 'string']
|
||||
'tracks' => ['type' => 'string', 'analyzer' => 'english']
|
||||
]
|
||||
],
|
||||
|
||||
|
@ -87,12 +87,12 @@ class SetupElasticsearch extends Migration
|
|||
'dynamic' => 'strict',
|
||||
'properties' => [
|
||||
'username' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||
'display_name' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||
'display_name' => ['type' => 'string'],
|
||||
|
||||
// This field is intended to be used as an array.
|
||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
||||
'tracks' => ['type' => 'string']
|
||||
'tracks' => ['type' => 'string', 'analyzer' => 'english']
|
||||
]
|
||||
],
|
||||
]
|
||||
|
|
|
@ -8,21 +8,27 @@
|
|||
/>
|
||||
|
||||
<section class="search-results pfm-popup" id="search-results">
|
||||
<div class="-column1">
|
||||
<h3 class="-section-header">Matching tracks</h3>
|
||||
<pfm-tracks-list tracks="tracks"></pfm-tracks-list>
|
||||
|
||||
<div ng-hide="searchInProgress">
|
||||
<p class="empty-box">Type something to begin searching!</p>
|
||||
</div>
|
||||
|
||||
<div class="-column2">
|
||||
<h3 class="-section-header">Matching users</h3>
|
||||
<pfm-users-list users="users"></pfm-users-list>
|
||||
<div ng-show="searchInProgress">
|
||||
<div class="-column1">
|
||||
<h3 class="-section-header">Matching tracks</h3>
|
||||
<pfm-tracks-list tracks="tracks"></pfm-tracks-list>
|
||||
|
||||
<h3 class="-section-header">Matching albums</h3>
|
||||
<pfm-albums-list albums="albums"></pfm-albums-list>
|
||||
</div>
|
||||
|
||||
<h3 class="-section-header">Matching playlists</h3>
|
||||
<pfm-playlists-list playlists="playlists"></pfm-playlists-list>
|
||||
<div class="-column2">
|
||||
<h3 class="-section-header">Matching users</h3>
|
||||
<pfm-users-list users="users" class="-condensed"></pfm-users-list>
|
||||
|
||||
<h3 class="-section-header">Matching albums</h3>
|
||||
<pfm-albums-list albums="albums"></pfm-albums-list>
|
||||
|
||||
<h3 class="-section-header">Matching playlists</h3>
|
||||
<pfm-playlists-list playlists="playlists"></pfm-playlists-list>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
@ -41,13 +41,16 @@ angular.module('ponyfm').directive 'pfmSearch', () ->
|
|||
|
||||
$scope.$watch 'searchQuery', _.debounce((searchQuery)->
|
||||
$scope.$apply ()->
|
||||
clearResults()
|
||||
return if searchQuery.length <3
|
||||
if searchQuery.length <3
|
||||
clearResults()
|
||||
$scope.searchInProgress = false
|
||||
return
|
||||
|
||||
$scope.searchInProgress = true
|
||||
|
||||
search.searchAllContent(searchQuery)
|
||||
.then (results)->
|
||||
clearResults()
|
||||
for track in results.tracks
|
||||
$scope.tracks.push(track)
|
||||
|
||||
|
|
49
resources/assets/styles/content.less
vendored
49
resources/assets/styles/content.less
vendored
|
@ -345,20 +345,7 @@ html .single-player .play-button {
|
|||
html {
|
||||
li {
|
||||
&.empty {
|
||||
.border-radius(0px);
|
||||
background: lighten(@pfm-purple, 30%);
|
||||
border: 1px solid lighten(@pfm-purple, 10%);
|
||||
color: lighten(@pfm-purple, 3%);
|
||||
float: none !important;
|
||||
width: auto !important;
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
font-size: 9pt;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten(@pfm-purple, 30%);
|
||||
}
|
||||
.empty-box;
|
||||
}
|
||||
|
||||
.cache-loading {
|
||||
|
@ -374,6 +361,23 @@ html {
|
|||
}
|
||||
}
|
||||
|
||||
.empty-box {
|
||||
.border-radius(0px);
|
||||
background: lighten(@pfm-purple, 30%);
|
||||
border: 1px solid lighten(@pfm-purple, 10%);
|
||||
color: lighten(@pfm-purple, 3%);
|
||||
float: none !important;
|
||||
width: auto !important;
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
font-size: 9pt;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten(@pfm-purple, 30%);
|
||||
}
|
||||
}
|
||||
|
||||
.tracks-listing {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
|
@ -487,3 +491,20 @@ html {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.users-listing {
|
||||
&.-condensed {
|
||||
.image {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
.published {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue