Started to restore clusters based recommendation engine
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
|
||||
add_library(lmsrecommendation SHARED
|
||||
impl/clusters/ClustersClassifier.cpp
|
||||
impl/Engine.cpp
|
||||
impl/ClassifierCreator.cpp
|
||||
)
|
||||
|
||||
@@ -17,22 +17,17 @@
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "recommendation/ClustersClassifierCreator.hpp"
|
||||
#include "recommendation/FeaturesClassifierCreator.hpp"
|
||||
#include "recommendation/Classifier.hpp"
|
||||
#include "recommendation/IClassifier.hpp"
|
||||
|
||||
namespace Recommendation
|
||||
{
|
||||
|
||||
std::unique_ptr<Classifier> createClustersClassifier()
|
||||
std::unique_ptr<IClassifier> createFeaturesClassifier()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<Classifier> createFeaturesClassifier()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -19,30 +19,49 @@
|
||||
|
||||
#include "Engine.hpp"
|
||||
|
||||
//#include "features/SimilarityFeaturesScannerAddon.hpp"
|
||||
//#include "cluster/SimilarityClusterSearcher.hpp"
|
||||
#include "recommendation/ClustersClassifierCreator.hpp"
|
||||
#include "recommendation/FeaturesClassifierCreator.hpp"
|
||||
|
||||
#include "database/ScanSettings.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/TrackList.hpp"
|
||||
|
||||
namespace Recommendation {
|
||||
|
||||
std::unique_ptr<IEngine>
|
||||
createEngine()
|
||||
createEngine(Database::Session& session)
|
||||
{
|
||||
return std::make_unique<Engine>();
|
||||
return std::make_unique<Engine>(session);
|
||||
}
|
||||
|
||||
Engine::Engine(Database::Session& session)
|
||||
{
|
||||
reloadSettings(session);
|
||||
}
|
||||
|
||||
void
|
||||
Engine::clearClassifiers()
|
||||
Engine::reloadSettings(Database::Session& session)
|
||||
{
|
||||
_classifiers.clear();
|
||||
}
|
||||
using namespace Database;
|
||||
|
||||
void
|
||||
Engine::addClassifier(std::unique_ptr<Classifier> classifier, unsigned priority)
|
||||
{
|
||||
_classifiers.emplace(priority, std::move(classifier));
|
||||
const ScanSettings::RecommendationEngineType engineType {[&]()
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
return ScanSettings::get(session)->getRecommendationEngineType();
|
||||
}()};
|
||||
|
||||
clearClassifiers();
|
||||
|
||||
switch (engineType)
|
||||
{
|
||||
case ScanSettings::RecommendationEngineType::Features:
|
||||
// _classifiers.emplace(0, createFeaturesClassifier()); // higher priority
|
||||
// [[fallthrough]];
|
||||
|
||||
case ScanSettings::RecommendationEngineType::Clusters:
|
||||
_classifiers.emplace(1, createClustersClassifier(session)); // lower priority
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Database::IdType>
|
||||
@@ -79,60 +98,52 @@ Engine::getSimilarTracksFromTrackList(Database::Session& /*session*/, Database::
|
||||
}
|
||||
|
||||
std::vector<Database::IdType>
|
||||
Engine::getSimilarTracks(Database::Session& /*dbSession*/, const std::unordered_set<Database::IdType>& /*trackIds*/, std::size_t /*maxCount*/)
|
||||
Engine::getSimilarTracks(Database::Session& dbSession, const std::unordered_set<Database::IdType>& trackIds, std::size_t maxCount)
|
||||
{
|
||||
#if 0
|
||||
auto engineType {getEngineType(dbSession)};
|
||||
auto somSearcher {_somAddon.getSearcher()};
|
||||
|
||||
if (engineType == Database::ScanSettings::SimilarityEngineType::Features
|
||||
&& somSearcher
|
||||
&& std::any_of(std::cbegin(trackIds), std::cend(trackIds), [&](Database::IdType trackId) { return somSearcher->isTrackClassified(trackId); } ))
|
||||
for (const auto& [priority, classifier] : _classifiers)
|
||||
{
|
||||
return somSearcher->getSimilarTracks(trackIds, maxCount);
|
||||
if (std::any_of(std::cbegin(trackIds), std::cend(trackIds), [&](Database::IdType trackId) { return classifier->isTrackClassified(trackId); } ))
|
||||
return classifier->getSimilarTracks(dbSession, trackIds, maxCount);
|
||||
}
|
||||
else
|
||||
return ClusterEngine::getSimilarTracks(dbSession, trackIds, maxCount);
|
||||
#endif
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<Database::IdType>
|
||||
Engine::getSimilarReleases(Database::Session& /*dbSession*/, Database::IdType /*releaseId*/, std::size_t /*maxCount*/)
|
||||
Engine::getSimilarReleases(Database::Session& dbSession, Database::IdType releaseId, std::size_t maxCount)
|
||||
{
|
||||
#if 0
|
||||
auto engineType {getEngineType(dbSession)};
|
||||
auto somSearcher {_somAddon.getSearcher()};
|
||||
|
||||
if (engineType == Database::ScanSettings::SimilarityEngineType::Features
|
||||
&& somSearcher
|
||||
&& somSearcher->isReleaseClassified(releaseId))
|
||||
for (const auto& [priority, classifier] : _classifiers)
|
||||
{
|
||||
return somSearcher->getSimilarReleases(releaseId, maxCount);
|
||||
if (classifier->isReleaseClassified(releaseId))
|
||||
return classifier->getSimilarReleases(dbSession, releaseId, maxCount);
|
||||
}
|
||||
else
|
||||
return ClusterEngine::getSimilarReleases(dbSession, releaseId, maxCount);
|
||||
#endif
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<Database::IdType>
|
||||
Engine::getSimilarArtists(Database::Session& /*dbSession*/, Database::IdType /*artistId*/, std::size_t /*maxCount*/)
|
||||
Engine::getSimilarArtists(Database::Session& dbSession, Database::IdType artistId, std::size_t maxCount)
|
||||
{
|
||||
#if 0
|
||||
auto engineType {getEngineType(dbSession)};
|
||||
auto somSearcher {_somAddon.getSearcher()};
|
||||
|
||||
if (engineType == Database::ScanSettings::SimilarityEngineType::Features
|
||||
&& somSearcher
|
||||
&& somSearcher->isArtistClassified(artistId))
|
||||
for (const auto& [priority, classifier] : _classifiers)
|
||||
{
|
||||
return somSearcher->getSimilarArtists(artistId, maxCount);
|
||||
if (classifier->isArtistClassified(artistId))
|
||||
return classifier->getSimilarArtists(dbSession, artistId, maxCount);
|
||||
}
|
||||
else
|
||||
return ClusterEngine::getSimilarArtists(dbSession, artistId, maxCount);
|
||||
#endif
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
Engine::clearClassifiers()
|
||||
{
|
||||
_classifiers.clear();
|
||||
}
|
||||
|
||||
void
|
||||
Engine::addClassifier(std::unique_ptr<IClassifier> classifier, unsigned priority)
|
||||
{
|
||||
_classifiers.emplace(priority, std::move(classifier));
|
||||
}
|
||||
|
||||
|
||||
} // ns Similarity
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <map>
|
||||
|
||||
#include "recommendation/IEngine.hpp"
|
||||
#include "recommendation/Classifier.hpp"
|
||||
#include "recommendation/IClassifier.hpp"
|
||||
|
||||
namespace Database
|
||||
{
|
||||
@@ -34,17 +34,22 @@ namespace Recommendation
|
||||
class Engine : public IEngine
|
||||
{
|
||||
public:
|
||||
Engine(Database::Session& session);
|
||||
|
||||
private:
|
||||
|
||||
void reloadSettings(Database::Session& session) override;
|
||||
|
||||
// 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;
|
||||
|
||||
private:
|
||||
void clearClassifiers();
|
||||
void addClassifier(std::unique_ptr<Classifier> classifier, unsigned priority);
|
||||
void addClassifier(std::unique_ptr<IClassifier> classifier, unsigned priority);
|
||||
|
||||
std::map<unsigned, std::unique_ptr<Classifier>> _classifiers;
|
||||
std::map<unsigned, std::unique_ptr<IClassifier>> _classifiers;
|
||||
};
|
||||
|
||||
} // ns Recommendation
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "database/Types.hpp"
|
||||
|
||||
namespace Database {
|
||||
class Session;
|
||||
}
|
||||
|
||||
namespace Similarity {
|
||||
|
||||
namespace ClusterSearcher
|
||||
{
|
||||
std::vector<Database::IdType> getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount);
|
||||
std::vector<Database::IdType> getSimilarTracks(Database::Session& session, const std::set<Database::IdType>& tracksId, std::size_t maxCount);
|
||||
std::vector<Database::IdType> getSimilarReleases(Database::Session& session, Database::IdType releaseId, std::size_t maxCount);
|
||||
std::vector<Database::IdType> getSimilarArtists(Database::Session& session, Database::IdType artistId, std::size_t maxCount);
|
||||
};
|
||||
|
||||
} // namespace Similarity
|
||||
+57
-9
@@ -17,7 +17,7 @@
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SimilarityClusterSearcher.hpp"
|
||||
#include "ClustersClassifier.hpp"
|
||||
|
||||
#include "database/Artist.hpp"
|
||||
#include "database/Cluster.hpp"
|
||||
@@ -26,11 +26,60 @@
|
||||
#include "database/Track.hpp"
|
||||
#include "database/TrackList.hpp"
|
||||
|
||||
namespace Similarity {
|
||||
namespace ClusterSearcher {
|
||||
namespace Recommendation {
|
||||
|
||||
std::unique_ptr<IClassifier> createClustersClassifier(Database::Session& session)
|
||||
{
|
||||
return std::make_unique<ClusterClassifier>(session);
|
||||
}
|
||||
|
||||
ClusterClassifier::ClusterClassifier(Database::Session& session)
|
||||
{
|
||||
classify(session);
|
||||
}
|
||||
|
||||
void
|
||||
ClusterClassifier::classify(Database::Session& session)
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
|
||||
{
|
||||
std::vector<Database::IdType> trackIds {Database::Track::getAllIdsWithClusters(session)};
|
||||
_classifiedTracks = std::unordered_set<Database::IdType>(std::cbegin(trackIds), std::cend(trackIds));
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<Database::IdType> releaseIds {Database::Release::getAllIdsWithClusters(session)};
|
||||
_classifiedReleases = std::unordered_set<Database::IdType>(std::cbegin(releaseIds), std::cend(releaseIds));
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<Database::IdType> artistIds {Database::Artist::getAllIdsWithClusters(session)};
|
||||
_classifiedArtists = std::unordered_set<Database::IdType>(std::cbegin(artistIds), std::cend(artistIds));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ClusterClassifier::isTrackClassified(Database::IdType trackId) const
|
||||
{
|
||||
return _classifiedTracks.find(trackId) != std::cend(_classifiedTracks);
|
||||
}
|
||||
|
||||
bool
|
||||
ClusterClassifier::isReleaseClassified(Database::IdType releaseId) const
|
||||
{
|
||||
return _classifiedReleases.find(releaseId) != std::cend(_classifiedReleases);
|
||||
}
|
||||
|
||||
bool
|
||||
ClusterClassifier::isArtistClassified(Database::IdType artistId) const
|
||||
{
|
||||
return _classifiedArtists.find(artistId) != std::cend(_classifiedArtists);
|
||||
}
|
||||
|
||||
|
||||
std::vector<Database::IdType>
|
||||
getSimilarTracks(Database::Session& dbSession, const std::set<Database::IdType>& trackIds, std::size_t maxCount)
|
||||
ClusterClassifier::getSimilarTracks(Database::Session& dbSession, const std::unordered_set<Database::IdType>& trackIds, std::size_t maxCount) const
|
||||
{
|
||||
auto transaction {dbSession.createSharedTransaction()};
|
||||
|
||||
@@ -43,7 +92,7 @@ getSimilarTracks(Database::Session& dbSession, const std::set<Database::IdType>&
|
||||
}
|
||||
|
||||
std::vector<Database::IdType>
|
||||
getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount)
|
||||
ClusterClassifier::getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount) const
|
||||
{
|
||||
std::vector<Database::IdType> res;
|
||||
|
||||
@@ -62,7 +111,7 @@ getSimilarTracksFromTrackList(Database::Session& session, Database::IdType track
|
||||
}
|
||||
|
||||
std::vector<Database::IdType>
|
||||
getSimilarReleases(Database::Session& dbSession, Database::IdType releaseId, std::size_t maxCount)
|
||||
ClusterClassifier::getSimilarReleases(Database::Session& dbSession, Database::IdType releaseId, std::size_t maxCount) const
|
||||
{
|
||||
std::vector<Database::IdType> res;
|
||||
|
||||
@@ -80,7 +129,7 @@ getSimilarReleases(Database::Session& dbSession, Database::IdType releaseId, std
|
||||
}
|
||||
|
||||
std::vector<Database::IdType>
|
||||
getSimilarArtists(Database::Session& dbSession, Database::IdType artistId, std::size_t maxCount)
|
||||
ClusterClassifier::getSimilarArtists(Database::Session& dbSession, Database::IdType artistId, std::size_t maxCount) const
|
||||
{
|
||||
std::vector<Database::IdType> res;
|
||||
|
||||
@@ -97,5 +146,4 @@ getSimilarArtists(Database::Session& dbSession, Database::IdType artistId, std::
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace ClusterSearcher
|
||||
} // namespace Similarity
|
||||
} // namespace Recommendation
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "recommendation/IClassifier.hpp"
|
||||
|
||||
|
||||
namespace Recommendation
|
||||
{
|
||||
|
||||
class ClusterClassifier : public IClassifier
|
||||
{
|
||||
public:
|
||||
ClusterClassifier(Database::Session& session);
|
||||
ClusterClassifier(const ClusterClassifier&) = delete;
|
||||
ClusterClassifier(ClusterClassifier&&) = delete;
|
||||
ClusterClassifier& operator=(const ClusterClassifier&) = delete;
|
||||
ClusterClassifier& operator=(ClusterClassifier&&) = delete;
|
||||
|
||||
private:
|
||||
|
||||
bool isTrackClassified(Database::IdType trackId) const override;
|
||||
bool isReleaseClassified(Database::IdType releaseId) const override;
|
||||
bool isArtistClassified(Database::IdType artistId) const override;
|
||||
|
||||
std::vector<Database::IdType> getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount) const override;
|
||||
std::vector<Database::IdType> getSimilarTracks(Database::Session& session, const std::unordered_set<Database::IdType>& tracksId, std::size_t maxCount) const override;
|
||||
std::vector<Database::IdType> getSimilarReleases(Database::Session& session, Database::IdType releaseId, std::size_t maxCount) const override;
|
||||
std::vector<Database::IdType> getSimilarArtists(Database::Session& session, Database::IdType artistId, std::size_t maxCount) const override;
|
||||
|
||||
void classify(Database::Session& session);
|
||||
|
||||
std::unordered_set<Database::IdType> _classifiedArtists;
|
||||
std::unordered_set<Database::IdType> _classifiedReleases;
|
||||
std::unordered_set<Database::IdType> _classifiedTracks;
|
||||
};
|
||||
|
||||
} // namespace Recommendation
|
||||
|
||||
@@ -21,15 +21,10 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Database
|
||||
{
|
||||
class Session;
|
||||
}
|
||||
|
||||
namespace Recommendation
|
||||
{
|
||||
class Classifier;
|
||||
class IClassifier;
|
||||
|
||||
std::unique_ptr<Classifier> createClustersClassifier();
|
||||
std::unique_ptr<IClassifier> createClustersClassifier(Database::Session& session);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,15 +21,10 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Database
|
||||
{
|
||||
class Session;
|
||||
}
|
||||
|
||||
namespace Recommendation
|
||||
{
|
||||
class Classifier;
|
||||
class IClassifier;
|
||||
|
||||
std::unique_ptr<Classifier> createFeaturesClassifier();
|
||||
std::unique_ptr<IClassifier> createFeaturesClassifier();
|
||||
}
|
||||
|
||||
|
||||
+5
-7
@@ -32,21 +32,19 @@ namespace Database
|
||||
namespace Recommendation
|
||||
{
|
||||
|
||||
class Classifier
|
||||
class IClassifier
|
||||
{
|
||||
public:
|
||||
virtual ~Classifier() = default;
|
||||
|
||||
virtual void classify() = 0;
|
||||
virtual ~IClassifier() = default;
|
||||
|
||||
virtual bool isTrackClassified(Database::IdType trackId) const = 0;
|
||||
virtual bool isReleaseClassified(Database::IdType releaseId) const = 0;
|
||||
virtual bool isArtistClassified(Database::IdType artistId) const = 0;
|
||||
|
||||
virtual std::vector<Database::IdType> getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount) = 0;
|
||||
virtual std::vector<Database::IdType> getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount) const = 0;
|
||||
virtual std::vector<Database::IdType> getSimilarTracks(Database::Session& session, const std::unordered_set<Database::IdType>& tracksId, std::size_t maxCount) const = 0;
|
||||
virtual std::vector<Database::IdType> getSimilarReleases(Database::IdType releaseId, std::size_t maxCount) const = 0;
|
||||
virtual std::vector<Database::IdType> getSimilarArtists(Database::IdType artistId, std::size_t maxCount) const = 0;
|
||||
virtual std::vector<Database::IdType> getSimilarReleases(Database::Session& session, Database::IdType releaseId, std::size_t maxCount) const = 0;
|
||||
virtual std::vector<Database::IdType> getSimilarArtists(Database::Session& session, Database::IdType artistId, std::size_t maxCount) const = 0;
|
||||
};
|
||||
|
||||
} // ns Recommendation
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <unordered_set>
|
||||
|
||||
#include "database/Types.hpp"
|
||||
#include "Classifier.hpp"
|
||||
|
||||
namespace Database
|
||||
{
|
||||
@@ -32,12 +31,13 @@ namespace Database
|
||||
|
||||
namespace Recommendation
|
||||
{
|
||||
class Classifier;
|
||||
class IEngine
|
||||
{
|
||||
public:
|
||||
virtual ~IEngine() = default;
|
||||
|
||||
virtual void reloadSettings(Database::Session& session) = 0;
|
||||
|
||||
// Closest results first
|
||||
virtual std::vector<Database::IdType> getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount) = 0;
|
||||
virtual std::vector<Database::IdType> getSimilarTracks(Database::Session& session, const std::unordered_set<Database::IdType>& tracksId, std::size_t maxCount) = 0;
|
||||
@@ -45,7 +45,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();
|
||||
std::unique_ptr<IEngine> createEngine(Database::Session& session);
|
||||
|
||||
} // ns Recommendation
|
||||
|
||||
|
||||
Reference in New Issue
Block a user