From e49d8670752f78315f479fab1fd86eedc3b06910 Mon Sep 17 00:00:00 2001 From: JunjieBai Date: Tue, 28 Nov 2023 17:15:31 +0800 Subject: [PATCH] perf(app-database-service):add keywords field and use it to find applications more accurately. --- libsearch/appdata/app-info-table.cpp | 27 ++++++++++++------- libsearch/appdata/app-info-table.h | 2 +- .../appdata/application-property-helper.cpp | 14 +++++++++- libsearch/appdata/application-property.h | 5 +++- .../app-db-manager.cpp | 19 +++++++++---- ukui-search-app-data-service/app-db-manager.h | 8 ++++-- 6 files changed, 56 insertions(+), 19 deletions(-) diff --git a/libsearch/appdata/app-info-table.cpp b/libsearch/appdata/app-info-table.cpp index 741e6c7..9a1efa5 100644 --- a/libsearch/appdata/app-info-table.cpp +++ b/libsearch/appdata/app-info-table.cpp @@ -474,17 +474,16 @@ bool AppInfoTable::query(ApplicationInfoMap &infoMap, ApplicationProperties prop return true; } -bool AppInfoTable::query(ApplicationInfoMap &infoMap, ApplicationProperties properties, const QStringList &keywords, ApplicationPropertyMap restrictions) +bool AppInfoTable::query(ApplicationInfoMap &infoMap, const ApplicationProperties& properties, const QStringList &keywords, const ApplicationPropertyMap& restrictions) { QString field; for(const ApplicationProperty::Property &pro : properties) { field.append(ApplicationPropertyHelper(pro).dataBaseField() + ","); } if(!properties.contains(ApplicationProperty::Property::DesktopFilePath)) { - field.append(ApplicationPropertyHelper(ApplicationProperty::Property::DesktopFilePath).dataBaseField()); - } else if(!field.isEmpty()) { - field.remove(field.length() - 1, 1); + field.append(ApplicationPropertyHelper(ApplicationProperty::Property::DesktopFilePath).dataBaseField() + ","); } + field.append(ApplicationPropertyHelper(ApplicationProperty::Property::LocalKeywords).dataBaseField()); QString condition; for (const ApplicationProperty::Property prop: restrictions.keys()) { @@ -492,18 +491,28 @@ bool AppInfoTable::query(ApplicationInfoMap &infoMap, ApplicationProperties prop } QString keywordCondition; + QString findWithLocalKeywords = "((select count(*) from (" + "WITH RECURSIVE split(str, rest) AS " + "(" + "SELECT substr(LOCAL_KEYWORDS || ';', 1, instr(LOCAL_KEYWORDS || ';', ';') - 1)," + "substr(LOCAL_KEYWORDS || ';', instr(LOCAL_KEYWORDS || ';', ';') + 1) " + "UNION ALL " + "SELECT substr(rest, 1, instr(rest, ';') - 1), substr(rest, instr(rest, ';') + 1) " + "FROM split WHERE str <> ''" + ")" + "SELECT str FROM split WHERE lower(str)=?)) <> 0)"; for(const QString& keyword : keywords) { if(keyword.size() < 2) { - keywordCondition.append("(ifnull(LOCAL_NAME, '') like ? or ifnull(NAME_EN, '') like ? or ifnull(NAME_ZH, '') like ? or ifnull(FIRST_LETTER_OF_PINYIN, '') like ?) AND"); + keywordCondition.append(QString("(ifnull(LOCAL_NAME, '') like ? or ifnull(NAME_EN, '') like ? or ifnull(NAME_ZH, '') like ? or ifnull(FIRST_LETTER_OF_PINYIN, '') like ? or %0) AND").arg(findWithLocalKeywords)); } else { - keywordCondition.append("(ifnull(LOCAL_NAME, '') like ? or ifnull(NAME_EN, '') like ? or ifnull(NAME_ZH, '') like ? or ifnull(FIRST_LETTER_OF_PINYIN, '') like ? or ifnull(PINYIN_NAME, '') like ?) AND"); + keywordCondition.append(QString("(ifnull(LOCAL_NAME, '') like ? or ifnull(NAME_EN, '') like ? or ifnull(NAME_ZH, '') like ? or ifnull(FIRST_LETTER_OF_PINYIN, '') like ? or ifnull(PINYIN_NAME, '') like ? or %0) AND").arg(findWithLocalKeywords)); } } if(!keywordCondition.isEmpty()) { keywordCondition.remove(keywordCondition.length() - 3, 3); } - QString sql = QString("SELECT %0 FROM APPINFO WHERE %1 %2 ORDER BY LENGTH(LOCAL_NAME)").arg(field).arg(condition).arg(keywordCondition); + QString sql = QString("SELECT %0 FROM APPINFO WHERE %1 %2 ORDER BY LENGTH(LOCAL_NAME)").arg(field, condition, keywordCondition); QSqlQuery query(*d->m_database); query.setForwardOnly(true); query.prepare(sql); @@ -515,12 +524,12 @@ bool AppInfoTable::query(ApplicationInfoMap &infoMap, ApplicationProperties prop } for(const QString &keyword : keywords) { - int i = 5; + int i = 6; if(keyword.size() < 2) { i--; } for (int bindCount = 0; bindCount < i; bindCount++) { - query.bindValue(count, "%" + keyword + "%"); + query.bindValue(count, (bindCount - i + 1) ? "%" + keyword + "%" : keyword.toLower()); count++; } } diff --git a/libsearch/appdata/app-info-table.h b/libsearch/appdata/app-info-table.h index 9fc819e..b32bcc5 100644 --- a/libsearch/appdata/app-info-table.h +++ b/libsearch/appdata/app-info-table.h @@ -43,7 +43,7 @@ public: bool query(ApplicationPropertyMap &propertyMap, const QString &desktopFile, ApplicationProperties properties); bool query(ApplicationInfoMap &infoMap, ApplicationProperties properties); bool query(ApplicationInfoMap &infoMap, ApplicationProperties properties, ApplicationPropertyMap restrictions); - bool query(ApplicationInfoMap &infoMap, ApplicationProperties properties, const QStringList &keywords, ApplicationPropertyMap restrictions); + bool query(ApplicationInfoMap &infoMap, const ApplicationProperties& properties, const QStringList &keywords, const ApplicationPropertyMap& restrictions); /** * @brief AppInfoTable::setAppFavoritesState diff --git a/libsearch/appdata/application-property-helper.cpp b/libsearch/appdata/application-property-helper.cpp index 553dd12..be10cf9 100644 --- a/libsearch/appdata/application-property-helper.cpp +++ b/libsearch/appdata/application-property-helper.cpp @@ -43,7 +43,7 @@ ApplicationPropertyHelper::ApplicationPropertyHelper(ApplicationProperty::Proper d->m_valueType = QMetaType::QString; break; case ApplicationProperty::NameZh: - d->m_databaseField = "NAME_EN"; + d->m_databaseField = "NAME_ZH"; d->m_valueType = QMetaType::QString; break; case ApplicationProperty::PinyinName: @@ -110,6 +110,18 @@ ApplicationPropertyHelper::ApplicationPropertyHelper(ApplicationProperty::Proper d->m_databaseField = "AUTO_START"; d->m_valueType = QMetaType::Int; break; + case ApplicationProperty::StartUpWMClass: + d->m_databaseField = "START_UP_WMCLASS"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::Keywords: + d->m_databaseField = "KEYWORDS"; + d->m_valueType = QMetaType::QString; + break; + case ApplicationProperty::LocalKeywords: + d->m_databaseField = "LOCAL_KEYWORDS"; + d->m_valueType = QMetaType::QString; + break; default: break; } diff --git a/libsearch/appdata/application-property.h b/libsearch/appdata/application-property.h index c475e24..d580f90 100644 --- a/libsearch/appdata/application-property.h +++ b/libsearch/appdata/application-property.h @@ -54,7 +54,10 @@ enum Property { Top, //置顶顺序(0 未置顶) Lock, //是否锁定(不允许显示或打开) DontDisplay, //是否不需要显示(设置了Nodisplay等字段) - AutoStart //是否自启动(位于自启动目录/etc/xdg/autostart下) + AutoStart, //是否自启动(位于自启动目录/etc/xdg/autostart下) + StartUpWMClass, //应用的className + Keywords, //关键词 + LocalKeywords //关键词(本地化) }; } //namespace ApplicationProperty typedef QVector ApplicationProperties; diff --git a/ukui-search-app-data-service/app-db-manager.cpp b/ukui-search-app-data-service/app-db-manager.cpp index c4b861f..9b571a6 100644 --- a/ukui-search-app-data-service/app-db-manager.cpp +++ b/ukui-search-app-data-service/app-db-manager.cpp @@ -217,7 +217,7 @@ void AppDBManager::buildAppInfoDB() { qDebug() << "I'm going to build app info database."; QSqlQuery sql(m_database); - QString cmd = QString("CREATE TABLE IF NOT EXISTS appInfo(%1, %2, %3, %4, %5, %6, %7, %8,%9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23)") + QString cmd = QString("CREATE TABLE IF NOT EXISTS appInfo(%1, %2, %3, %4, %5, %6, %7, %8,%9, %10, %11, %12, %13, %14, %15, %16, %17, %18, %19, %20, %21, %22, %23, %24, %25)") // .arg("ID INT")//自增id .arg("DESKTOP_FILE_PATH TEXT PRIMARY KEY NOT NULL")//desktop文件路径 .arg("MODIFYED_TIME TEXT")//YYYYMMDDHHmmSS 修改日期 @@ -241,7 +241,9 @@ void AppDBManager::buildAppInfoDB() .arg("LOCK INT")//应用是否锁定(管控),0未锁定,1锁定 .arg("DONT_DISPLAY INT")//应用隐藏(NoDisplay, NotShowIn) .arg("AUTO_START INT")//自启应用 - .arg("START_UP_WMCLASS TEXT");//classname + .arg("START_UP_WMCLASS TEXT")//classname + .arg("KEYWORDS TEXT")//应用的关键词 + .arg("LOCAL_KEYWORDS TEXT");//应用本地关键词,跟随系统语言 if (!sql.exec(cmd)) { qWarning() << m_database.lastError() << cmd; return; @@ -417,10 +419,11 @@ bool AppDBManager::handleLocaleDataUpdate(const QString &desktopFilePath) QSqlQuery query(m_database); - query.prepare("UPDATE appInfo SET LOCAL_NAME=:localName, FIRST_LETTER_ALL=:firstOfLetter2All WHERE DESKTOP_FILE_PATH=:desktopFilePath"); + query.prepare("UPDATE appInfo SET LOCAL_NAME=:localName, FIRST_LETTER_ALL=:firstOfLetter2All, LOCAL_KEYWORDS=:localKeywords WHERE DESKTOP_FILE_PATH=:desktopFilePath"); query.bindValue(":localName", localName); query.bindValue(":firstOfLetter2All", firstLetter2All); query.bindValue(":desktopFilePath", desktopFilePath); + query.bindValue(":localKeywords", desktopFile.localizedValue("Keywords", "NULL").toString()); if (!this->startTransaction()) { return false; @@ -576,9 +579,9 @@ bool AppDBManager::handleDBItemInsert(const QString &desktopFilePath) "LOCAL_NAME, NAME_EN, NAME_ZH, PINYIN_NAME, " "FIRST_LETTER_OF_PINYIN, FIRST_LETTER_ALL, " "ICON, TYPE, CATEGORY, EXEC, COMMENT, MD5, " - "LAUNCH_TIMES, FAVORITES, LAUNCHED, TOP, LOCK, DONT_DISPLAY, AUTO_START, START_UP_WMCLASS) " + "LAUNCH_TIMES, FAVORITES, LAUNCHED, TOP, LOCK, DONT_DISPLAY, AUTO_START, START_UP_WMCLASS, KEYWORDS, LOCAL_KEYWORDS) " "VALUES(:desktopFilePath, '%0', '%1', :localName, :enName, :zhName, :pinyinName, :firstLetterOfPinyin, :firstLetter2All, " - ":icon, :type, :categories, :exec, :comment,'%2',%3,%4,%5,%6,%7,%8,%9, :wmClass)") + ":icon, :type, :categories, :exec, :comment,'%2',%3,%4,%5,%6,%7,%8,%9, :wmClass, :keywords, :localKeywords)") .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")) .arg(getAppDesktopMd5(desktopFilePath)) @@ -602,6 +605,8 @@ bool AppDBManager::handleDBItemInsert(const QString &desktopFilePath) sql.bindValue(":exec", desktopfile.value("Exec").toString()); sql.bindValue(":comment", desktopfile.value("Comment").toString()); sql.bindValue(":wmClass", desktopfile.value("StartupWMClass").toString()); + sql.bindValue(":keywords", desktopfile.value("Keywords").toString()); + sql.bindValue(":localKeywords", desktopfile.localizedValue("Keywords", "NULL").toString()); if (!this->startTransaction()) { return false; @@ -779,6 +784,8 @@ bool AppDBManager::handleDBItemUpdate(const QString &desktopFilePath) "EXEC=:exec," "COMMENT=:comment," "START_UP_WMCLASS=:wmClass," + "KEYWORDS=:keywords," + "LOCAL_KEYWORDS=:localKeywords," "MD5='%1'," "DONT_DISPLAY=%2," "AUTO_START=%3 " @@ -800,6 +807,8 @@ bool AppDBManager::handleDBItemUpdate(const QString &desktopFilePath) sql.bindValue(":exec", desktopfile.value("Exec").toString()); sql.bindValue(":comment", desktopfile.value("Comment").toString()); sql.bindValue(":wmClass", desktopfile.value("StartupWMClass").toString()); + sql.bindValue(":keywords", desktopfile.value("Keywords").toString()); + sql.bindValue(":localKeywords", desktopfile.localizedValue("Keywords", "NULL").toString()); if (!this->startTransaction()) { return false; diff --git a/ukui-search-app-data-service/app-db-manager.h b/ukui-search-app-data-service/app-db-manager.h index 1b51f34..413fb96 100644 --- a/ukui-search-app-data-service/app-db-manager.h +++ b/ukui-search-app-data-service/app-db-manager.h @@ -41,8 +41,10 @@ #define CONNECTION_NAME QLatin1String("ukss-appdb-connection") /** * changelog(1.2 to 1.3): Add the START_UP_WMCLASS field in order to find desktop file path by the windowClassClass. + * changelog(1.3 to 1.4): Add the KEYWORDS & LOCAL_KEYWORDS field in order to find application conveniently. */ -static const QString APP_DATABASE_VERSION = QStringLiteral("1.3"); + +static const QString APP_DATABASE_VERSION = QStringLiteral("1.4"); namespace UkuiSearch { /** @@ -184,7 +186,9 @@ private: {"LOCK", "INT"}, {"DONT_DISPLAY", "INT"}, {"AUTO_START", "INT"}, - {"START_UP_WMCLASS", "TEXT"} + {"START_UP_WMCLASS", "TEXT"}, + {"KEYWORDS", "TEXT"}, + {"LOCAL_KEYWORDS", "TEXT"} }; //应用黑名单