Further decoupled recommendation engine: it now has its own thread

This commit is contained in:
emeric
2020-02-16 12:39:27 +01:00
parent 6239064396
commit a414a80bbb
12 changed files with 280 additions and 184 deletions
+1
View File
@@ -16,6 +16,7 @@ target_include_directories(lmsrecommendation PRIVATE
target_link_libraries(lmsrecommendation PRIVATE
lmsdatabase
lmssom
wt
)
install(TARGETS lmsrecommendation DESTINATION lib)
+72 -31
View File
@@ -23,46 +23,51 @@
#include "recommendation/FeaturesClassifierCreator.hpp"
#include "database/ScanSettings.hpp"
#include "database/Session.hpp"
#include "database/TrackList.hpp"
#include "utils/Logger.hpp"
namespace Recommendation {
std::unique_ptr<IEngine>
createEngine(Database::Session& session)
createEngine(Database::Db& db)
{
return std::make_unique<Engine>(session);
return std::make_unique<Engine>(db);
}
Engine::Engine(Database::Session& session)
Engine::Engine(Database::Db& db)
: _dbSession {db}
{
reload(session);
}
void
Engine::reload(Database::Session& session)
Engine::start()
{
using namespace Database;
assert(!_running);
_running = true;
const ScanSettings::RecommendationEngineType engineType {[&]()
requestReload();
_ioService.start();
}
void
Engine::stop()
{
assert(_running);
_running = false;
_ioService.stop();
}
void
Engine::requestReload()
{
LMS_LOG(RECOMMENDATION, DEBUG) << "Reload requested...";
_ioService.post([&]()
{
auto transaction {session.createSharedTransaction()};
return ScanSettings::get(session)->getRecommendationEngineType();
}()};
// TODO: just replace the classifier once it is ready
clearClassifiers();
switch (engineType)
{
case ScanSettings::RecommendationEngineType::Features:
// addClassifier(createFeaturesClassifier(), 0); // higher priority
// [[fallthrough]];
case ScanSettings::RecommendationEngineType::Clusters:
addClassifier(createClustersClassifier(session), 1); // lower priority
break;
}
reload();
});
}
std::vector<Database::IdType>
@@ -85,7 +90,7 @@ Engine::getSimilarTracksFromTrackList(Database::Session& session, Database::IdTy
if (trackIds.empty())
return {};
std::shared_lock lock {_mutex};
std::shared_lock lock {_classifiersMutex};
for (const auto& [priority, classifier] : _classifiers)
{
@@ -99,7 +104,7 @@ Engine::getSimilarTracksFromTrackList(Database::Session& session, Database::IdTy
std::vector<Database::IdType>
Engine::getSimilarTracks(Database::Session& dbSession, const std::unordered_set<Database::IdType>& trackIds, std::size_t maxCount)
{
std::shared_lock lock {_mutex};
std::shared_lock lock {_classifiersMutex};
for (const auto& [priority, classifier] : _classifiers)
{
@@ -113,7 +118,7 @@ Engine::getSimilarTracks(Database::Session& dbSession, const std::unordered_set<
std::vector<Database::IdType>
Engine::getSimilarReleases(Database::Session& dbSession, Database::IdType releaseId, std::size_t maxCount)
{
std::shared_lock lock {_mutex};
std::shared_lock lock {_classifiersMutex};
for (const auto& [priority, classifier] : _classifiers)
{
@@ -127,7 +132,7 @@ Engine::getSimilarReleases(Database::Session& dbSession, Database::IdType releas
std::vector<Database::IdType>
Engine::getSimilarArtists(Database::Session& dbSession, Database::IdType artistId, std::size_t maxCount)
{
std::shared_lock lock {_mutex};
std::shared_lock lock {_classifiersMutex};
for (const auto& [priority, classifier] : _classifiers)
{
@@ -138,17 +143,53 @@ Engine::getSimilarArtists(Database::Session& dbSession, Database::IdType artistI
return {};
}
void
Engine::reload()
{
using namespace Database;
LMS_LOG(RECOMMENDATION, DEBUG) << "Reloading recommendation engines...";
const ScanSettings::RecommendationEngineType engineType {[&]()
{
auto transaction {_dbSession.createSharedTransaction()};
return ScanSettings::get(_dbSession)->getRecommendationEngineType();
}()};
// TODO: just replace the classifier once it is ready
clearClassifiers();
switch (engineType)
{
case ScanSettings::RecommendationEngineType::Features:
// addClassifier(createFeaturesClassifier(), 0); // higher priority
// [[fallthrough]];
case ScanSettings::RecommendationEngineType::Clusters:
addClassifier(createClustersClassifier(_dbSession), 1); // lower priority
break;
}
LMS_LOG(RECOMMENDATION, DEBUG) << "Recommendation engines reloaded!";
_sigReloaded.emit();
}
void
Engine::clearClassifiers()
{
std::unique_lock lock {_mutex};
std::unique_lock lock {_classifiersMutex};
_classifiers.clear();
}
void
Engine::addClassifier(std::unique_ptr<IClassifier> classifier, unsigned priority)
{
std::unique_lock lock {_mutex};
std::unique_lock lock {_classifiersMutex};
_classifiers.emplace(priority, std::move(classifier));
}
+17 -9
View File
@@ -22,35 +22,43 @@
#include <map>
#include <shared_mutex>
#include <Wt/WIOService.h>
#include "database/Session.hpp"
#include "recommendation/IEngine.hpp"
#include "recommendation/IClassifier.hpp"
namespace Database
{
class Session;
}
namespace Recommendation
{
class Engine : public IEngine
{
public:
Engine(Database::Session& session);
Engine(Database::Db& db);
private:
void reload(Database::Session& session) override;
void start() override;
void stop() override;
void requestReload() override;
Wt::Signal<>& reloaded() override { return _sigReloaded; }
// Closest results first
std::vector<Database::IdType> getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount) override;
std::vector<Database::IdType> getSimilarTracks(Database::Session& session, const std::unordered_set<Database::IdType>& tracksId, std::size_t maxCount) override;
std::vector<Database::IdType> getSimilarReleases(Database::Session& session, Database::IdType releaseId, std::size_t maxCount) override;
std::vector<Database::IdType> getSimilarArtists(Database::Session& session, Database::IdType artistId, std::size_t maxCount) override;
void reload();
void clearClassifiers();
void addClassifier(std::unique_ptr<IClassifier> classifier, unsigned priority);
std::shared_mutex _mutex;
bool _running {};
Wt::WIOService _ioService;
Database::Session _dbSession;
Wt::Signal<> _sigReloaded;
std::shared_mutex _classifiersMutex;
std::map<unsigned, std::unique_ptr<IClassifier>> _classifiers;
};
@@ -19,13 +19,17 @@
#pragma once
#include <functional>
#include <vector>
#include <unordered_set>
#include <Wt/WSignal.h>
#include "database/Types.hpp"
namespace Database
{
class Db;
class Session;
}
@@ -36,7 +40,11 @@ namespace Recommendation
public:
virtual ~IEngine() = default;
virtual void reload(Database::Session& session) = 0;
virtual void start() = 0;
virtual void stop() = 0;
virtual void requestReload() = 0;
virtual Wt::Signal<>& reloaded() = 0;
// Closest results first
virtual std::vector<Database::IdType> getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount) = 0;
@@ -45,7 +53,7 @@ namespace Recommendation
virtual std::vector<Database::IdType> getSimilarArtists(Database::Session& session, Database::IdType artistId, std::size_t maxCount) = 0;
};
std::unique_ptr<IEngine> createEngine(Database::Session& session);
std::unique_ptr<IEngine> createEngine(Database::Db& db);
} // ns Recommendation