#1: Search relevancy improvements and other tweaks.

This commit is contained in:
Peter Deltchev 2016-01-17 02:33:58 -08:00
parent 7a7f4ee02a
commit 56edd5ec28
10 changed files with 143 additions and 55 deletions

View file

@ -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
], ],
] ]
]); ]);

View file

@ -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();
}
} }

View file

@ -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();
}
} }

View file

@ -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,

View file

@ -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;
}
} }

View file

@ -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();
} }
} }
} }

View file

@ -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']
] ]
], ],
] ]

View file

@ -8,6 +8,11 @@
/> />
<section class="search-results pfm-popup" id="search-results"> <section class="search-results pfm-popup" id="search-results">
<div ng-hide="searchInProgress">
<p class="empty-box">Type something to begin searching!</p>
</div>
<div ng-show="searchInProgress">
<div class="-column1"> <div class="-column1">
<h3 class="-section-header">Matching tracks</h3> <h3 class="-section-header">Matching tracks</h3>
<pfm-tracks-list tracks="tracks"></pfm-tracks-list> <pfm-tracks-list tracks="tracks"></pfm-tracks-list>
@ -16,7 +21,7 @@
<div class="-column2"> <div class="-column2">
<h3 class="-section-header">Matching users</h3> <h3 class="-section-header">Matching users</h3>
<pfm-users-list users="users"></pfm-users-list> <pfm-users-list users="users" class="-condensed"></pfm-users-list>
<h3 class="-section-header">Matching albums</h3> <h3 class="-section-header">Matching albums</h3>
<pfm-albums-list albums="albums"></pfm-albums-list> <pfm-albums-list albums="albums"></pfm-albums-list>
@ -24,5 +29,6 @@
<h3 class="-section-header">Matching playlists</h3> <h3 class="-section-header">Matching playlists</h3>
<pfm-playlists-list playlists="playlists"></pfm-playlists-list> <pfm-playlists-list playlists="playlists"></pfm-playlists-list>
</div> </div>
</div>
</section> </section>
</div> </div>

View file

@ -41,13 +41,16 @@ angular.module('ponyfm').directive 'pfmSearch', () ->
$scope.$watch 'searchQuery', _.debounce((searchQuery)-> $scope.$watch 'searchQuery', _.debounce((searchQuery)->
$scope.$apply ()-> $scope.$apply ()->
if searchQuery.length <3
clearResults() clearResults()
return if searchQuery.length <3 $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)

View file

@ -345,6 +345,23 @@ html .single-player .play-button {
html { html {
li { li {
&.empty { &.empty {
.empty-box;
}
.cache-loading {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
line-height: 100%;
font-size: 93%;
padding-left: 3px;
padding-right: 3px;
}
}
}
.empty-box {
.border-radius(0px); .border-radius(0px);
background: lighten(@pfm-purple, 30%); background: lighten(@pfm-purple, 30%);
border: 1px solid lighten(@pfm-purple, 10%); border: 1px solid lighten(@pfm-purple, 10%);
@ -359,19 +376,6 @@ html {
&:hover { &:hover {
background-color: lighten(@pfm-purple, 30%); background-color: lighten(@pfm-purple, 30%);
} }
}
.cache-loading {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
line-height: 100%;
font-size: 93%;
padding-left: 3px;
padding-right: 3px;
}
}
} }
.tracks-listing { .tracks-listing {
@ -487,3 +491,20 @@ html {
} }
} }
} }
.users-listing {
&.-condensed {
.image {
height: 30px;
width: 30px;
}
.info {
margin-left: 40px;
}
.published {
display: none;
}
}
}