前言
在移动端,全文搜索(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 可以看到可以正常的搜索到结果:
接下来,我们就可以愉快的使用中文分词的全文搜索了。