Go to file
JunjieBai f1f6b36588 Fix#146819 the app-data-service crashes when the destructor is executed. 2022-11-22 09:20:05 +08:00
3rd-parties Add ukui-search-service. 2021-11-22 16:03:31 +08:00
data 新增搜索服务应用数据库接口;新增搜索应用插件功能;搜索服务接口新增设置返回数据结构(应用搜索插件);目录结构优化等; 2022-06-13 13:38:47 +08:00
frontend 解决平板模式下,单机结果项直接执行打开动作,无法打开详情页的问题。 2022-11-04 17:35:40 +08:00
libchinese-segmentation@64268d2ff1 同步子项目. 2022-10-12 10:36:32 +08:00
libsearch 修复内容搜索详情页加载图片失败导致的崩溃问题。 2022-11-17 11:38:01 +08:00
search-ukcc-plugin 修复控制面板搜索插件崩溃的问题 2022-11-21 10:11:12 +08:00
tests Add file system watcher(Encapsulate inotify). 2022-07-29 11:22:53 +08:00
translations Add app widget plugin. 2022-10-21 09:14:21 +08:00
ukui-search-app-data-service Fix#146819 the app-data-service crashes when the destructor is executed. 2022-11-22 09:20:05 +08:00
ukui-search-service Add the ukui-search-dir-manager process which is instead of dir-watcher to solve the qSettings conflict in the case of multiple processes. 2022-05-27 14:32:01 +08:00
ukui-search-service-dir-manager !18 Solve the problem that the dir watcher's dbus crashed because of deadlock. Add the support for nvme device. Add the dir path check of searchable dir for direct search. 2022-10-20 08:57:23 +00:00
ukuisearch-systemdbus Optimized the strategy of modifying inotify/max_user_watches. 2021-11-17 10:15:47 +08:00
.gitignore Merge from dev-unity. 2021-08-20 16:03:51 +08:00
.gitmodules 整理项目结构 2022-08-18 09:48:41 +08:00
LICENSE Add LICENSE and README.md 2020-12-21 16:30:40 +08:00
README.md Fix link. 2022-05-11 10:30:40 +08:00
ukui-search.pro Add file system watcher(Encapsulate inotify). 2022-07-29 11:22:53 +08:00

README.md

ukui-search介绍

[dWIP] UKUI Search is a user-wide desktop search feature of UKUI desktop environment.

简介

狭义上的ukui-search指ukui桌面环境中的全局搜索应用目前最新版本为3.1-xxx。全局搜索应用提供了本地文件、文本内容、应用、设置项、便签等聚合搜索功能基于其文件索引功能可以为用户提供快速准确的搜索体验。

广义的ukui-search除了包括全局搜索应用还包括在ukui桌面环境中的本地搜索服务以及其开发接口。基于文建索引服务应用搜索数据服务等基础数据源服务可以提供基于C++接口的搜索功能应用开发者可以通过引用动态库的形式直接使用其搜索功能。除此之外ukui桌面环境搜索服务还提供了一组基于Qt插件框架的插件接口用户可以通过继承接口以实现搜索功能的扩展。 以下提到的ukui-search如无说明均指后者。

ukui-search 目前共有5个包

  • ukui-search_xxxxxx.deb
  • libukui-search-dev_xxxxx.deb
  • libukui-search0_xxxxx.deb
  • libchinese-segmentation0_xxxx.deb
  • ukui-search-systemdbus_xxxxx.deb

xxx代表版本号。其中ukui-search 为全局搜索应用本体libukui-search包提供了搜索服务基本功能以及扩展接口libukui-search-dev为其开发包。libchinese-segmentation包为搜索服务提供了NLP能力如中文分词等。ukui-search-systemdbus包提供了一些systemdbus提权操作。

运行

搜索服务相关的进程共有5个包括ukui-search(全局搜索GUI界面)ukui-search-service(文件搜索服务)first-index(文件搜索服务子进程)inotify-index(文件搜索服务子进程)ukui-search-app-data-service(应用数据维护服务)。

ukui-search、ukui-search-service和ukui-search-app-data-service服务默认开机自启其中first-index进程和inotify-index进程作为ukui-search-service的子进程并由其控制启动和退出。

快捷键、命令行和dbus接口

呼出搜索GUI界面的系统快捷键为WIN+s

ukui-search进程的命令行如下

Usage: ukui-search [options]
Options:
  -h, --help     Displays this help.
  -v, --version  Displays version information.
  -q, --quit     Quit ukui-search application
  -s, --show     Show main window

ukui-search-service的命令行如下

Usage: ukui-search-service [options]
Options:
  -h, --help            Displays this help.
  -v, --version         Displays version information.
  -q, --quit            Stop service
  -i, --index <option>  start or stop file index

ukui-search 提供的dbus接口

service: com.ukui.search.service
path: /
interface: com.ukui.search.service
    showWindow () ↦ () //显示搜索主窗口
    searchKeyword (String keyword) ↦ () //显示主窗口并搜索传入的关键字

交互

搜索的功能有一部分依赖于其他桌面环境组件:

设置项搜索依赖ukui-control-center提供的配置文件安装路径为

/usr/share/ukui-control-center/shell/res/search.xml

跳转到搜索结果对应的控制面板页面使用了ukui-control-center的命令行

Usage: ukui-control-center [options]
Options:
  -h, --help     Displays this help.
  -v, --version  Displays version information.
  -m <module>    display the specified module page  //全局搜索使用的是这个命令

在线应用搜索依赖kylin-software-center提供的dbus接口

service: com.kylin.softwarecenter.getsearchresults
path: /com/kylin/softwarecenter/getsearchresults
interface: com.kylin.getsearchresults
        get_search_result (String keyword) ↦ (Boolean arg_1)

跳转到软件商店安装页面的使用了以下dbus接口

service: com.kylin.softwarecenter
path: /com/kylin/softwarecenter
interface: com.kylin.utiliface
        show_search_result (String appname) ↦ (Array of [Dict of {String, String}] arg_1)

如果软件商店未打开或接口不可用时,则调用以下命令行:

kylin-software-center -find <包名>

便签本搜索依赖ukui-notebook提供的dbus接口

serviceorg.ukui.note
path/org/ukui/note
interfaceorg.ukui.note.interface
         keywordMatch (Array of [String] keyList) ↦ (Dict of {String, Variant} arg_0)

打开文件所在路径功能调用了peony提供的dbus接口

serviceorg.freedesktop.FileManager1
path/org/freedesktop/FileManager1
interface: org.freedesktop.FileManager1
         ShowItems (Array of [String] uriList, String startUpId) ↦ ()

原理与功能特点

全局搜索支持控制面板设置项搜索,应用搜索,文件搜索,便签本搜索。支持名称,拼音,或拼音首字母搜索(文本内容搜索和便签本搜索不支持拼音搜索)。其中,设置项搜索通过读取控制面板提供的配置文件实现,打开对应的控制面板页面也依赖与控制面板提供的命令行;应用搜索分为本地已安装应用(包括安卓兼容应用)和软件商店已上架的在线应用,在线应用的搜索和跳转安装通过软件商店提供的接口实现。所以,当怀疑搜索的设置搜索或应用搜索有问题时,可以直接测试控制面板或软件商店对应的接口。

文件搜索分为文件名(文件夹名)搜索和文本内容搜索。文件搜索有两种模式:直接搜索建立索引搜索

  • 直接搜索:类似文件管理的搜索,通过遍历匹配关键字搜索,不支持文本内容搜索。

  • 索引搜索:搜索通过遍历文件系统建立数据库(需要消耗一定的时间和资源),搜索时直接对数据库进行搜索,可以实现毫秒级的搜索响应,建立索引的过程中,搜索结果可能不全或者搜不出结果。 首次索引进程first-index由ukui-search-service进程拉起在用户首次开启索引功能或者索引损坏需要重建索引时开启索引更新进程为inotify-index同样由ukui-search-service进程拉起但更新进程不会一直存在其只在用户有文件更新时启动一段时间后自动关闭。 索引数据库会基于文件系统监听进行实时更新。但是由于解析文本需要时间,所以大文件的索引新可能会有短暂的延迟。由于各种意外原因,比如索引更新过程中掉电关机,可能会导致索引损坏,此时搜索在下次开机时会重新建立索引来保证正常的文件搜索功能。基于机器配置和本地文件的数量,大小以及种类,索引重建的时间可以从几秒到数分钟不等。 索引搜索支持文本内容搜索,基本原理可以参考 倒排索引与优麒麟的文件搜索 。建立索引时,搜索会对常用的文本文件进行解析,提取关键词存入数据库。搜索时,用户输入的文本也会被提取关键词,和数据库中的关键词进行匹配, 所以文本索引并不能保证你搜索一个文本文件里的任意内容都能搜出这个文件这也不是普遍的应用场景。搜索输入的文本中必须要包含【关键词】才可以。比如你搜索一个由于并不是任何文件的关键词所以并不会有搜索到任何文件。事实上我们有一个停用词词库专门用来排除于是等等基本上在每个文档都会出现的一些无用词。目前搜索支持解析的文件格式有docxpptx, xlsx, txt(大部分编码格式), doc, dot, wps, ppt, pps, dps, et, xls, pdf以上格式均不支持加密文件的解析。

注意:应用的.desktop文件并不是应用本身或者“快捷方式”对于搜索来说它只是一个文件所以搜索desktop文件的名字并不能搜出这个应用除非它恰好和应用重名。另外在文件搜索中显示的dekstop文件并不会以应用的形式显示而是显示它本来的样子——一个文件。

配置文件与用户数据

ukui-search应用和ukui-search-service、ukui-search-app-data-service的配置文件以及用户数据都保存在如下路径

~/.config/org.ukui/ukui-search

文件说明:

  • ukui-search.conf ------------------------------------全局搜索GUI配置文件。
  • ukui-search-block-dirs.conf ---------------------文件搜索黑名单,在控制面板中设置
  • ukui-search-index-status.conf ------------------文件索引服务状态记录
  • index_data ---------------------------------------------文件索引数据库
  • content_index_data ---------------------------------文本内容数据库
  • ocr_index_data --------------------------------------- OCR图片搜索数据库

编译

下载源码切换到ukss-dev分支优麒麟2204版本

根据debian/control文件安装编译依赖

mkdir build;cd build;qmake ..;make

编译会生成的二进制文件:

  • ukui-search搜索应用
  • ukui-search-service搜文件索引服务
  • ukui-search-app-data-service应用数据服务
  • ukui-search-systemdbus文建索引服务的system dbus提权接口

库文件:

  • libchinese-segmentation.so中文分词
  • libukui-search.so提供搜索服务和搜索应用的API
  • libsearch-ukcc-plugin.so(ukui-contorl-center插件)

调试

ukui-search目前并未采用ukui-log4qt模块的日志功能。如需调试可在以下目录新建ukui-search.logukui-search-service.log以及ukui-search-app-data-service.log文件分别对应全局搜索GUI应用全局搜索文件索引服务和应用数据服务。新建日志文件后日志会自动打印到对应额文件中但目前日志没有自动备份或删除机制。

开发接口

搜索服务接口(此接口目前处于快速更新总,请以代码为准)

Use with CMake:

find_package(PkgConfig)
pkg_check_modules(ukui-search REQUIRED ukui-search)
include_directories(${ukui-search_INCLUDE_DIRS})
target_link_libraries(yourapp ukui-search)

Use with Qmake

CONFIG += link_pkgconfig
PKGCONFIG += ukui-search

使用示例:

#include <UkuiSearchTask>
......
//初始化一个搜索实例
UkuiSearch::UkuiSearchTask ukst;    
//初始化队列
UkuiSearch::DataQueue<UkuiSearch::ResultItem> *queue = ukst.init();    
//加载想要使用的搜索插件
ukst.initSearchPlugin(UkuiSearch::SearchType::File);    
//添加搜索条件
ukst.setOnlySearchFile(true);   
ukst.addKeyword(m_keyword);   
 //启动搜索(异步)
ukst.startSearch(UkuiSearch::SearchType::File);
//接收结果(示例)
 while(true) {
     if(!queue->isEmpty()) {
         qDebug() << queue->dequeue().getItemKey();
     }
}

目前搜索服务内置的可初始化的插件有(目前仅支持文件,文本和应用搜索):

enum class SearchType{    
    File             = 0x1 << 0,    
    FileContent      = 0x1 << 1,    
    Application      = 0x1 << 2,    
    Setting          = 0x1 << 3,    
    Note             = 0x1 << 4,    
    Mail             = 0x1 << 5,    
    Custom           = 0x1 << 6
};

搜索服务插件接口

除了上面的内置插件,用户可以通过集成插件接口实现自定义搜索插件:

namespace UkuiSearch {
class SearchTaskPluginIface : public QObject, public PluginInterface{    
    Q_OBJECT
    public:    
    virtual QString getCustomSearchType() = 0;    
    virtual SearchType getSearchType() = 0;    
    //Asynchronous,multithread.    
    virtual void startSearch(std::shared_ptr<SearchController> searchController) = 0;    
    virtual void stop() = 0;
    Q_SIGNALS:    
    void searchFinished(size_t searchId);
};
}
Q_DECLARE_INTERFACE(UkuiSearch::SearchTaskPluginIface, SearchTaskPluginIface_iid)

调用方法和上面的类似,只是需要在初始化插件和启动搜索的时候,指定用户自定的插件名称(用户插件默认启动即加载):

表示加载用户插件

ukst.initSearchPlugin(UkuiSearch::SearchType::Custom);  

启动搜索

ukst.startSearch(UkuiSearch::SearchType::<用户自定义的名称>);

搜索应用插件接口

搜索应用本身也提供了一个插件接口,可以通过加载用户实现的插件以实现额外搜索功能:

namespace UkuiSearch {
class SearchPluginIface : public PluginInterface
{
public:
    struct DescriptionInfo
    {
        QString key;
        QString value;
    };
    struct Actioninfo
    {
        int actionkey;
        QString displayName;
    };
    /**
     * @brief The ResultInfo struct
     */
    struct ResultInfo
    {
        QIcon icon;
        QString name;
        QVector<DescriptionInfo> description;
        QString actionKey;
        int type;
    };

    virtual ~SearchPluginIface() {}
    virtual QString getPluginName() = 0;
    virtual void KeywordSearch(QString keyword,DataQueue<ResultInfo> *searchResult) = 0;
    virtual void stopSearch() = 0;
    virtual QList<Actioninfo> getActioninfo(int type) = 0;
    virtual void openAction(int actionkey, QString key, int type) = 0;
    virtual QWidget *detailPage(const ResultInfo &ri) = 0;
};
}

接口使用注意事项:

接口实现时,需要继承SearchPluginIface,并设置以下接口信息:

Q_PLUGIN_METADATA(IID SearchPluginIface_iid FILE "common.json") Q_INTERFACES(Zeeker::SearchPluginIface)

其中 common.json为开发者自己编写的插件元数据文件,比如可以用来指定版本号等。

子类需要上面两个接口类的所有虚函数,其中,

virtual void KeywordSearch(QString keyword,DataQueue<ResultInfo> *searchResult) = 0;

函数会被UI直接调用如果你的搜索功能十分费时请在子线程里实现搜索不要阻塞UI

ResultInfo代表每一个结果项,DataQueue是前端取结果的数据队列。

virtual QList<Actioninfo> getActioninfo(int type) = 0;

这个函数用于获取每一项搜索结果可以执行的动作,比如打开等,Actioninfo中的actionkey用于指定特定的actiontype用于指定搜索结果的类型(如果你的搜索结果有的话);

virtual QWidget *detailPage(const ResultInfo &ri) = 0;

这是用于获取每一项的详情页的函数,详情页同一时间只会显示一个,所以如果你的搜索结果详情页都是一致的风格,最好提前初始化,当这个方法被调用时只更新数据即可。

请一定要注意,搜索可能被快速触发,所以你需要确保当用户进行一次搜索时,队列里不会被错误的插入上一次的搜索结果。