mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2025-04-01 00:35:30 +02: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
|
* @param int $resultsPerContentType
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function searchAllContent(string $query, int $resultsPerContentType = 10) {
|
public function searchAllContent(string $query) {
|
||||||
$results = $this->elasticsearch->msearch([
|
$results = $this->elasticsearch->msearch([
|
||||||
'index' => $this->index,
|
'index' => $this->index,
|
||||||
'body' => [
|
'body' => [
|
||||||
|
@ -60,9 +60,10 @@ class Search {
|
||||||
'track_type',
|
'track_type',
|
||||||
'show_songs^2',
|
'show_songs^2',
|
||||||
],
|
],
|
||||||
|
'tie_breaker' => 0.3,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'size' => $resultsPerContentType
|
'size' => 11
|
||||||
],
|
],
|
||||||
|
|
||||||
//===== Albums =====//
|
//===== Albums =====//
|
||||||
|
@ -76,9 +77,10 @@ class Search {
|
||||||
'artist',
|
'artist',
|
||||||
'tracks',
|
'tracks',
|
||||||
],
|
],
|
||||||
|
'tie_breaker' => 0.3,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'size' => $resultsPerContentType
|
'size' => 3
|
||||||
],
|
],
|
||||||
|
|
||||||
//===== Playlists =====//
|
//===== Playlists =====//
|
||||||
|
@ -92,9 +94,10 @@ class Search {
|
||||||
'curator',
|
'curator',
|
||||||
'tracks^2',
|
'tracks^2',
|
||||||
],
|
],
|
||||||
|
'tie_breaker' => 0.3,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'size' => $resultsPerContentType
|
'size' => 3
|
||||||
],
|
],
|
||||||
|
|
||||||
//===== Users =====//
|
//===== Users =====//
|
||||||
|
@ -104,12 +107,13 @@ class Search {
|
||||||
'multi_match' => [
|
'multi_match' => [
|
||||||
'query' => $query,
|
'query' => $query,
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'display_name^2',
|
'display_name',
|
||||||
'tracks',
|
'tracks',
|
||||||
],
|
],
|
||||||
|
'tie_breaker' => 0.3,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'size' => $resultsPerContentType
|
'size' => 3
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -420,4 +420,11 @@ class Album extends Model
|
||||||
'tracks' => $this->tracks->pluck('title'),
|
'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 $table = 'playlists';
|
||||||
protected $dates = ['deleted_at'];
|
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()
|
public static function summary()
|
||||||
{
|
{
|
||||||
|
@ -301,4 +314,13 @@ class Playlist extends Model
|
||||||
'tracks' => $this->tracks->pluck('title'),
|
'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;
|
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 [
|
return [
|
||||||
'title' => $this->title,
|
'title' => $this->title,
|
||||||
'artist' => $this->user->display_name,
|
'artist' => $this->user->display_name,
|
||||||
|
|
|
@ -279,4 +279,11 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
||||||
'tracks' => $this->tracks->pluck('title'),
|
'tracks' => $this->tracks->pluck('title'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function shouldBeIndexed():bool {
|
||||||
|
return $this->disabled_at === null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
namespace Poniverse\Ponyfm\Traits;
|
namespace Poniverse\Ponyfm\Traits;
|
||||||
|
|
||||||
use Elasticsearch;
|
use Elasticsearch;
|
||||||
|
use Elasticsearch\Common\Exceptions\Missing404Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class IndexedInElasticsearch
|
* Class IndexedInElasticsearch
|
||||||
|
@ -40,13 +41,19 @@ trait IndexedInElasticsearchTrait
|
||||||
*/
|
*/
|
||||||
abstract public function toElasticsearch();
|
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) {
|
static::saved(function ($model) {
|
||||||
$model->createOrUpdateElasticsearchEntry();
|
$model->ensureElasticsearchEntryIsUpToDate();
|
||||||
});
|
});
|
||||||
|
|
||||||
static::deleted(function ($model) {
|
static::deleted(function ($model) {
|
||||||
$model->deleteElasticsearchEntry();
|
$model->ensureElasticsearchEntryIsUpToDate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,17 +83,17 @@ trait IndexedInElasticsearchTrait
|
||||||
try {
|
try {
|
||||||
Elasticsearch::connection()->delete($this->getElasticsearchParameters(false));
|
Elasticsearch::connection()->delete($this->getElasticsearchParameters(false));
|
||||||
|
|
||||||
} catch (\Elasticsearch\Common\Exceptions\Missing404Exception $e) {
|
} catch (Missing404Exception $e) {
|
||||||
// If the track we're trying to delete isn't indexed in Elasticsearch,
|
// If the entity we're trying to delete isn't indexed in Elasticsearch,
|
||||||
// that's fine.
|
// that's fine.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function ensureElasticsearchEntryIsUpToDate() {
|
public function ensureElasticsearchEntryIsUpToDate() {
|
||||||
if (method_exists($this, 'trashed') && $this->trashed()) {
|
if ($this->shouldBeIndexed()) {
|
||||||
$this->deleteElasticsearchEntry();
|
|
||||||
} else {
|
|
||||||
$this->createOrUpdateElasticsearchEntry();
|
$this->createOrUpdateElasticsearchEntry();
|
||||||
|
} else {
|
||||||
|
$this->deleteElasticsearchEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,17 +40,17 @@ class SetupElasticsearch extends Migration
|
||||||
'_source' => ['enabled' => true],
|
'_source' => ['enabled' => true],
|
||||||
'dynamic' => 'strict',
|
'dynamic' => 'strict',
|
||||||
'properties' => [
|
'properties' => [
|
||||||
'title' => ['type' => 'string'],
|
'title' => ['type' => 'string', 'analyzer' => 'english'],
|
||||||
'artist' => ['type' => 'string', 'index' => 'not_analyzed'],
|
'artist' => ['type' => 'string'],
|
||||||
|
|
||||||
'published_at' => ['type' => 'date'],
|
'published_at' => ['type' => 'date'],
|
||||||
'genre' => ['type' => 'string', 'index' => 'not_analyzed'],
|
'genre' => ['type' => 'string', 'analyzer' => 'english'],
|
||||||
'track_type' => ['type' => 'string', 'index' => 'not_analyzed'],
|
'track_type' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||||
|
|
||||||
// This field is intended to be used as an array.
|
// This field is intended to be used as an array.
|
||||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
// 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],
|
'_source' => ['enabled' => true],
|
||||||
'dynamic' => 'strict',
|
'dynamic' => 'strict',
|
||||||
'properties' => [
|
'properties' => [
|
||||||
'title' => ['type' => 'string'],
|
'title' => ['type' => 'string', 'analyzer' => 'english'],
|
||||||
'artist' => ['type' => 'string', 'index' => 'not_analyzed'],
|
'artist' => ['type' => 'string'],
|
||||||
|
|
||||||
// This field is intended to be used as an array.
|
// This field is intended to be used as an array.
|
||||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
// 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],
|
'_source' => ['enabled' => true],
|
||||||
'dynamic' => 'strict',
|
'dynamic' => 'strict',
|
||||||
'properties' => [
|
'properties' => [
|
||||||
'title' => ['type' => 'string'],
|
'title' => ['type' => 'string', 'analyzer' => 'english'],
|
||||||
'curator' => ['type' => 'string', 'index' => 'not_analyzed'],
|
'curator' => ['type' => 'string'],
|
||||||
|
|
||||||
// This field is intended to be used as an array.
|
// This field is intended to be used as an array.
|
||||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
// 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',
|
'dynamic' => 'strict',
|
||||||
'properties' => [
|
'properties' => [
|
||||||
'username' => ['type' => 'string', 'index' => 'not_analyzed'],
|
'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.
|
// This field is intended to be used as an array.
|
||||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
// 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">
|
<section class="search-results pfm-popup" id="search-results">
|
||||||
<div class="-column1">
|
<div ng-hide="searchInProgress">
|
||||||
<h3 class="-section-header">Matching tracks</h3>
|
<p class="empty-box">Type something to begin searching!</p>
|
||||||
<pfm-tracks-list tracks="tracks"></pfm-tracks-list>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="-column2">
|
<div ng-show="searchInProgress">
|
||||||
<h3 class="-section-header">Matching users</h3>
|
<div class="-column1">
|
||||||
<pfm-users-list users="users"></pfm-users-list>
|
<h3 class="-section-header">Matching tracks</h3>
|
||||||
|
<pfm-tracks-list tracks="tracks"></pfm-tracks-list>
|
||||||
|
|
||||||
<h3 class="-section-header">Matching albums</h3>
|
</div>
|
||||||
<pfm-albums-list albums="albums"></pfm-albums-list>
|
|
||||||
|
|
||||||
<h3 class="-section-header">Matching playlists</h3>
|
<div class="-column2">
|
||||||
<pfm-playlists-list playlists="playlists"></pfm-playlists-list>
|
<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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -41,13 +41,16 @@ angular.module('ponyfm').directive 'pfmSearch', () ->
|
||||||
|
|
||||||
$scope.$watch 'searchQuery', _.debounce((searchQuery)->
|
$scope.$watch 'searchQuery', _.debounce((searchQuery)->
|
||||||
$scope.$apply ()->
|
$scope.$apply ()->
|
||||||
clearResults()
|
if searchQuery.length <3
|
||||||
return if searchQuery.length <3
|
clearResults()
|
||||||
|
$scope.searchInProgress = false
|
||||||
|
return
|
||||||
|
|
||||||
$scope.searchInProgress = true
|
$scope.searchInProgress = true
|
||||||
|
|
||||||
search.searchAllContent(searchQuery)
|
search.searchAllContent(searchQuery)
|
||||||
.then (results)->
|
.then (results)->
|
||||||
|
clearResults()
|
||||||
for track in results.tracks
|
for track in results.tracks
|
||||||
$scope.tracks.push(track)
|
$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 {
|
html {
|
||||||
li {
|
li {
|
||||||
&.empty {
|
&.empty {
|
||||||
.border-radius(0px);
|
.empty-box;
|
||||||
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%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cache-loading {
|
.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 {
|
.tracks-listing {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
|
@ -487,3 +491,20 @@ html {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.users-listing {
|
||||||
|
&.-condensed {
|
||||||
|
.image {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
margin-left: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.published {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue