From 0b7449e488933ec68a0fe63ac15bdee37aff215a Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Tue, 3 Jun 2014 16:08:20 +0100 Subject: [PATCH] Make Fuzzy Search usable --- .../database/fuzzyindex/FuzzyIndex.cpp | 6 + .../database/fuzzyindex/FuzzyIndex.h | 4 +- src/libtomahawk/resolvers/JSResolver.cpp | 7 + .../resolvers/JSResolverHelper.cpp | 144 +++++++++++++++--- src/libtomahawk/resolvers/JSResolverHelper.h | 9 +- 5 files changed, 149 insertions(+), 21 deletions(-) diff --git a/src/libtomahawk/database/fuzzyindex/FuzzyIndex.cpp b/src/libtomahawk/database/fuzzyindex/FuzzyIndex.cpp index 977ff806e..0dbef4fd9 100644 --- a/src/libtomahawk/database/fuzzyindex/FuzzyIndex.cpp +++ b/src/libtomahawk/database/fuzzyindex/FuzzyIndex.cpp @@ -213,6 +213,12 @@ FuzzyIndex::deleteIndex() TomahawkUtils::removeDirectory( m_lucenePath ); } +void +FuzzyIndex::updateIndex() +{ + // NO-OP +} + void FuzzyIndex::loadLuceneIndex() diff --git a/src/libtomahawk/database/fuzzyindex/FuzzyIndex.h b/src/libtomahawk/database/fuzzyindex/FuzzyIndex.h index d7351d59f..e01f07b8b 100644 --- a/src/libtomahawk/database/fuzzyindex/FuzzyIndex.h +++ b/src/libtomahawk/database/fuzzyindex/FuzzyIndex.h @@ -68,20 +68,20 @@ public: */ void deleteIndex(); - virtual void updateIndex() = 0; + virtual void updateIndex(); signals: void indexReady(); public slots: void loadLuceneIndex(); + bool wipeIndex(); QMap< int, float > search( const Tomahawk::query_ptr& query ); QMap< int, float > searchAlbum( const Tomahawk::query_ptr& query ); private slots: void updateIndexSlot(); - bool wipeIndex(); private: QMutex m_mutex; diff --git a/src/libtomahawk/resolvers/JSResolver.cpp b/src/libtomahawk/resolvers/JSResolver.cpp index 28c2861ed..1a8cb5144 100644 --- a/src/libtomahawk/resolvers/JSResolver.cpp +++ b/src/libtomahawk/resolvers/JSResolver.cpp @@ -188,6 +188,13 @@ JSResolver::init() { Q_D( JSResolver ); + QString lucenePath = d->accountId + ".lucene"; + QDir luceneDir( TomahawkUtils::appDataDir().absoluteFilePath( lucenePath ) ); + if ( luceneDir.exists() ) + { + d->fuzzyIndex.reset( new FuzzyIndex( this, lucenePath, false ) ); + } + QFile scriptFile( filePath() ); if( !scriptFile.open( QIODevice::ReadOnly ) ) { diff --git a/src/libtomahawk/resolvers/JSResolverHelper.cpp b/src/libtomahawk/resolvers/JSResolverHelper.cpp index 8f4ad5f99..b09ca07ec 100644 --- a/src/libtomahawk/resolvers/JSResolverHelper.cpp +++ b/src/libtomahawk/resolvers/JSResolverHelper.cpp @@ -494,49 +494,158 @@ JSResolverHelper::hasFuzzyIndex() } +bool +JSResolverHelper::indexDataFromVariant( const QVariantMap &map, struct Tomahawk::IndexData& indexData ) +{ + // We do not use artistId at the moment + indexData.artistId = 0; + + if ( map.contains( "album" ) ) + { + indexData.album = map["album"].toString(); + } + else + { + indexData.album = QString(); + } + + // Check that we have the three required attributes + if ( !map.contains( "id" ) || !map["id"].canConvert( QVariant::Int ) + || !map.contains( "track" ) || !map.contains( "artist" ) ) + { + return false; + } + + bool ok; + indexData.id = map["id"].toInt( &ok ); + if ( !ok ) + { + return false; + } + + indexData.artist = map["artist"].toString().trimmed(); + if ( indexData.artist.isEmpty() ) + { + return false; + } + + indexData.track = map["track"].toString().trimmed(); + if ( indexData.track.isEmpty() ) + { + return false; + } + + return true; +} + + void JSResolverHelper::createFuzzyIndex( const QVariantList& list ) { - // TODO + if ( m_resolver->d_func()->fuzzyIndex.isNull() ) + { + m_resolver->d_func()->fuzzyIndex.reset( new FuzzyIndex( m_resolver, m_resolver->d_func()->accountId + ".lucene" , true ) ); + } + else + { + m_resolver->d_func()->fuzzyIndex->wipeIndex(); + } + + addToFuzzyIndex( list ); } void JSResolverHelper::addToFuzzyIndex( const QVariantList& list ) { - // TODO + if ( m_resolver->d_func()->fuzzyIndex.isNull() ) + { + tLog() << Q_FUNC_INFO << "Cannot add entries to non-existing index."; + return; + } + + m_resolver->d_func()->fuzzyIndex->beginIndexing(); + + foreach ( const QVariant& variant, list ) + { + // Convert each entry to IndexData + if ( variant.canConvert( QVariant::Map ) ) { + QVariantMap map = variant.toMap(); + + // Convert each entry and do multiple checks that we have valid data. + struct IndexData indexData; + + if ( indexDataFromVariant( map, indexData ) ) + { + m_resolver->d_func()->fuzzyIndex->appendFields( indexData ); + } + } + } + + m_resolver->d_func()->fuzzyIndex->endIndexing(); } -QMap +bool +cmpTuple ( QVariant x, QVariant y ) +{ + return x.toList().at( 1 ).toFloat() < y.toList().at( 1 ).toFloat(); +} + + +QVariantList +JSResolverHelper::searchInFuzzyIndex( const query_ptr& query ) +{ + if ( m_resolver->d_func()->fuzzyIndex ) + { + QMap map = m_resolver->d_func()->fuzzyIndex->search( query ); + + // Convert map to sorted QVariantList + QVariantList list; + foreach ( int id, map.keys() ) { + QVariantList innerList; + innerList.append( QVariant( id ) ); + innerList.append( QVariant( map[id] ) ); + // Wrap into QVariant or the list will be flattend + list.append( QVariant( innerList )); + } + std::sort( list.begin(), list.end(), cmpTuple ); + + return list; + } + return QVariantList(); +} + + +QVariantList JSResolverHelper::searchFuzzyIndex( const QString& query ) { - if ( m_resolver->d_func()->fuzzyIndex ) - { - return m_resolver->d_func()->fuzzyIndex->search( Query::get( query, QString() ) ); - } - return QMap(); + return searchInFuzzyIndex( Query::get( query, QString() ) ); } -QMap +QVariantList JSResolverHelper::resolveFromFuzzyIndex( const QString& artist, const QString& album, const QString& track ) { - if ( m_resolver->d_func()->fuzzyIndex ) - { - // Important: Do not autoresolve! - query_ptr query = Query::get( artist, album, track, QString(), false ); - return m_resolver->d_func()->fuzzyIndex->search( query ); + // Important: Do not autoresolve! + query_ptr query = Query::get( artist, track, album, QString(), false ); + if ( query.isNull() ) { + tLog() << Q_FUNC_INFO << "Could not create a query for" << artist << "-" << track; + return QVariantList(); } - return QMap(); + return searchInFuzzyIndex( query ); } void JSResolverHelper::deleteFuzzyIndex() { - m_resolver->d_func()->fuzzyIndex->deleteIndex(); - m_resolver->d_func()->fuzzyIndex->deleteLater(); + if ( m_resolver->d_func()->fuzzyIndex ) + { + m_resolver->d_func()->fuzzyIndex->deleteIndex(); + m_resolver->d_func()->fuzzyIndex->deleteLater(); + m_resolver->d_func()->fuzzyIndex.reset(); + } } @@ -564,6 +673,7 @@ JSResolverHelper::returnStreamUrl( const QString& streamUrl, const QMap @@ -32,6 +33,7 @@ #include #include + class JSResolver; Q_DECLARE_METATYPE( boost::function< void( QSharedPointer< QIODevice >& ) > ) @@ -54,8 +56,8 @@ public: Q_INVOKABLE bool hasFuzzyIndex(); Q_INVOKABLE void createFuzzyIndex( const QVariantList& list ); Q_INVOKABLE void addToFuzzyIndex( const QVariantList& list ); - Q_INVOKABLE QMap searchFuzzyIndex( const QString& query ); - Q_INVOKABLE QMap resolveFromFuzzyIndex( const QString& artist, const QString& album, const QString& tracks ); + Q_INVOKABLE QVariantList searchFuzzyIndex( const QString& query ); + Q_INVOKABLE QVariantList resolveFromFuzzyIndex( const QString& artist, const QString& album, const QString& tracks ); Q_INVOKABLE void deleteFuzzyIndex(); void customIODeviceFactory( const Tomahawk::result_ptr&, const QString& url, @@ -93,6 +95,9 @@ private: void returnStreamUrl( const QString& streamUrl, const QMap& headers, boost::function< void( const QString&, QSharedPointer< QIODevice >& ) > callback ); + bool indexDataFromVariant( const QVariantMap& map, struct Tomahawk::IndexData& indexData ); + QVariantList searchInFuzzyIndex( const Tomahawk::query_ptr& query ); + QVariantMap m_resolverConfig; JSResolver* m_resolver; QString m_scriptPath, m_urlCallback, m_urlTranslator;