Harmony NEXT:如何给数据库添加自定义分词

前言

在移动端,全文搜索(FTS)是对于搜索大量数据非常好用的一种技术。比如微信的聊天内容搜索、邮箱的邮件内容搜索都是基于 SQLite 的全文搜索来实现的。但 SQLite 内置的分词器并不支持中文分词,所以我们想要搜中文的话需要自己实现中文分词器或者使用别人的库。

在 iOS 中,我们可以使用微信团队提供的 wcdb 库去实现该功能。但不幸的是,该框架不支持鸿蒙系统。那么,在鸿蒙系统如何让数据库支持中文搜索呢?

大的步骤分为以下三步:

  • 通过鸿蒙提供的 SDK 将我们的源码编译为动态库(.so 文件)。
  • 将编译好的动态库集成到项目中。
  • 最后一步测试动态库是否正常工作即可。

首先,我们来看下如何用鸿蒙的 SDK 编译动态库。

鸿蒙 SDK 编译动态库

环境配置

中文分词的框架,我选择的是 simple 这个 C++ 的库。

C++ 的编译一般都通过 cmake,所以需要我们电脑上安装 cmake:brew install cmake

除了 cmake,我们还需要安装 make: brew install make

接下来,我们需要在 Gitee 上下载相应的 ohos SDK,我的电脑是 iMac,芯片是 M系列的,所以我对应的 ohos SDK 是下图这个,大家找自己环境对应的下载即可:

下载完成后,将其解压即可。

因为当前 SDK 中的 cmake 是 X86 架构,在 arm 架构的编译机上无法使用,因此我们需要在编译机上安装系统的cmake 命令:

bash 复制代码
cp sdk/packages/ohos-sdk/darwin/native/build-tools/cmake/share/cmake-3.16/Modules/Platform/OHOS.cmake /opt/homebrew/Cellar/cmake/3.28.0/share/cmake/Modules/Platform/
  • 前半部分替换为你自己电脑下载的ohos-sdk的文件路径。
  • 第二部分如果你的 cmake 版本不是 3.28.0,需要将版本号替换成你电脑 cmake 的当前版本号。

比如我的 ohos-sdk 的文件路径是: /Users/fengzhihao/Downloads/sdk/packages/ohos-sdk;cmake 的版本号是: 3.30.3,则命令如下:

bash 复制代码
cp /Users/fengzhihao/Downloads/sdk/packages/ohos-sdk/darwin/native/build-tools/cmake/share/cmake-3.16/Modules/Platform/OHOS.cmake /opt/homebrew/Cellar/cmake/3.30.3/share/cmake/Modules/Platform

编译 simple

首先,进入 simple 项目,然后新建一个 build 的文件夹,然后进入 build 文件夹:

bash 复制代码
cd simple-master
mkdir build 
cd build

接着,执行 cmake 命令:

ruby 复制代码
cmake -DCMAKE_TOOLCHAIN_FILE=/Users/fengzhihao/Downloads/sdk/packages/ohos-sdk/darwin/native/build/cmake/ohos.toolchain.cmake -DCMAKE_INSTALL_PREFIX=/Users/fengzhihao/Downloads/simple-master2 -DOHOS_ARCH=arm64-v8a .. -L

命令说明:

  • DCMAKE_TOOLCHAIN_FILE 该参数后面的路径为你电脑的 ohos-sdk 的路径。
  • DCMAKE_INSTALL_PREFIX 该参数后面的路径为 simple 的本地路径。
  • DOHOS_ARCH 配置交叉编译的CPU架构,一般为arm64-v8a(编译64位的三方库)、armeabi-v7a(编译32位的三方库),本示例中我们设置编译64位的 simple 库。

执行完截图如下:

执行完 cmake 后,我们在当前目录直接执行 make:

go 复制代码
make

这一步不出意外的话,会遇到如下报错😂:

通过上图我们可以看到是 google 的测试框架报错了。通过在网上搜索发现华为技术论坛也有人遇到了相同的问题,但并没有解决方案。。。

所以我的解决办法就是把相关的代码给注释掉,如果有小伙伴知道如何解决这个问题麻烦评论区告知一下。

将 test 目录下的 CMakeList.txt 内容修改如下:

objectivec 复制代码
cmake_minimum_required(VERSION 3.2)
project(simple_tests)

# https://github.com/maps-gpu/MAPS/issues/7#issuecomment-418200278
cmake_policy(SET CMP0057 NEW)

# https://github.com/google/googletest/issues/2791
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src)

然后再次运行 make 命令,即可成功:

最后再验证一下生成的动态库是否正确:

bash 复制代码
cd src
file libsimple.so

出现以下信息即编译成功:

scala 复制代码
libsimple.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=601bce3b289d08192f3417e1d2ac0a30f2f2b9e0, with debug_info, not stripped

编译好产物,下一步就是集成到项目中。

项目集成

集成还是比较简单的,方式就是在 entry 目录下新建一个 libs 的文件夹,然后在 libs 下新建一个 arm64-v8a 的文件夹,将产物拖进去即可:

需要注意的是,文件夹的名字是严格要求的,不能起别的命名,否则获取数据库的时候会报错。

动态库的使用

最后一步,就是动态库的使用了。示例代码如下:

ini 复制代码
let context = getContext(this) as common.UIAbilityContext;
let bundleCodeDir = context.bundleCodeDir;
// 将自定义的分词动态库的路径传进去
let path = [bundleCodeDir + "/libs/arm64/libsimple.so"]
console.log("testtag " + path)
const STORE_CONFIG: relationalStore.StoreConfig = {
  name: "RdbTest.db",
  securityLevel: relationalStore.SecurityLevel.S1,
  pluginLibs: path
};

relationalStore.getRdbStore(context, STORE_CONFIG, (err: BusinessError, rdbStore: relationalStore.RdbStore) => {
  rdbStore.executeSql("CREATE VIRTUAL TABLE IF NOT EXISTS t1 USING fts5(x, tokenize = 'simple');")
    .then(() => {
      rdbStore.executeSql("insert into t1(x) values ('周杰伦 Jay Chou:最美的不是下雨天,是曾与你躲过雨的屋檐')," +
        "('I love China! 我爱中国!')," +
        "('@English &special _characters."''bacon-&and''-eggs%');").then(() => {
        const resultSet =
          rdbStore.querySqlSync("select x from t1 where x match simple_query('杰伦');");
        console.info(`ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}, row count: ${resultSet.rowCount}`);
        // resultSet是一个数据集合的游标,默认指向第-1个记录,有效的数据从0开始。
        resultSet.goToFirstRow();
        if (resultSet.goToFirstRow()) {
          do {
            const x = resultSet.getString(resultSet.getColumnIndex("x"));
            console.info(`x=${x}`);
          } while (resultSet.goToNextRow());
        }
        // 释放数据集的内存,若不释放可能会引起fd泄露与内存泄露
        resultSet.close();
      }).catch((err: Error) => {
        console.log("")
      })
    })
    .catch((err: Error) => {
      console.log("")
    })
});

根据 console 可以看到可以正常的搜索到结果:

接下来,我们就可以愉快的使用中文分词的全文搜索了。

参考链接

相关推荐
Miguo94well4 小时前
Flutter框架跨平台鸿蒙开发——地理知识速记APP的开发流程
flutter·华为·harmonyos·鸿蒙
讯方洋哥5 小时前
HarmonyOS App开发——鸿蒙音乐播放机应用App开发
华为·harmonyos
小雨青年6 小时前
【鸿蒙原生开发会议随记 Pro】 会议随记 Pro v1.1 发布 详解 HarmonyOS NEXT 原生国际化(i18n)架构与最佳实践
华为·harmonyos
木斯佳7 小时前
HarmonyOS 6实战(源码教学篇)— Speech Kit TextReader:【仿某云音乐接入语音朗读控件】
华为·harmonyos
南村群童欺我老无力.8 小时前
Flutter 框架跨平台鸿蒙开发 - 校园生活一站式:打造智慧校园服务平台
flutter·华为·harmonyos
南村群童欺我老无力.9 小时前
Flutter 框架跨平台鸿蒙开发 - 城市文创打卡:探索城市文化创意之旅
android·flutter·华为·harmonyos
yingdonglan11 小时前
Flutter 框架跨平台鸿蒙开发 ——AnimatedBuilder性能优化详解
flutter·性能优化·harmonyos
菜鸟小芯11 小时前
【开源鸿蒙跨平台开发先锋训练营】DAY8~DAY13 底部选项卡&首页功能实现
flutter·harmonyos
大雷神11 小时前
HarmonyOS智慧农业管理应用开发教程--高高种地-- 第19篇:语音合成 - TTS语音播报
华为·语音识别·harmonyos
b20772111 小时前
Flutter for OpenHarmony 身体健康状况记录App实战 - 提醒设置实现
python·flutter·macos·cocoa·harmonyos