# isrc_fuse.js
**Repository Path**: zeyuli981029/isrc_fuse.js
## Basic Information
- **Project Name**: isrc_fuse.js
- **Description**: 针对OpenHarmony移植的Fuse.js三方库
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2025-05-28
- **Last Updated**: 2025-05-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Fuse.js
## 简介
Fuse.js是一款轻量级的JavaScript模糊搜索库,提供了模糊搜索和搜索排序功能。
该库有着如下移植价值:
- 高性能:Fuse.js使用了一种称为近似字符串匹配的算法,这使得它在大型数据集中的搜索速度非常快。
- 简单易用:Fuse.js提供了简单易用的API,使得开发者能够轻松地将模糊搜索和搜索排序功能集成到他们的应用程序中。
- 高度可配置:Fuse.js提供了许多可配置选项,使得开发者能够自定义搜索算法的行为和搜索结果的排序方式。
- 支持多种数据类型:Fuse.js可以用于不同类型的数据,包括字符串、数字、日期等。
- 支持多语言搜索:Fuse.js可以处理不同语言的搜索,包括中文、日文、阿拉伯文等。
- 该库可以用于各种应用场景,例如搜索引擎、电子商务网站、数据可视化等等。
本项目将该库在移植到OpenHarmony上运行,并通过XTS测试。
## 效果展示
使用该库实现的Demo应用效果如下:
## 下载安装
```
ohpm install @isrc/fuse.js
```
## 使用说明
字符串列表搜索典型使用示例如下:
```typescript
// 创建一个包含书籍信息的列表数组,作为待搜索的数据
var list = [
{
"title": "Old Man's War",
"author": "John Scalzi",
"tags": ["fiction"]
},
{
"title": "The Lock Artist",
"author": "Steve",
"tags": ["thriller"]
}
]
// 配置搜索选项,包括启用分数计算和指定搜索的键(作者和标签)
var options = {
includeScore: true,
// 在 'author' 和 'tags' 数组中进行搜索
keys: ['author', 'tags']
}
// 创建一个 Fuse 搜索实例,将列表和选项传递给它
var fuse = new Fuse(list, options)
// 使用 Fuse 搜索实例执行搜索,查找包含 'tion' 的结果
var result = fuse.search('tion')
```
此时result变量内容为:
```json
[
{
"item": {
"title": "Old Man's War",
"author": "John Scalzi",
"tags": ["fiction"]
},
"refIndex": 0,
"score": 0.03
}
]
```
## 接口说明
### 方法
##### `search`
搜索整个文档集合,并返回搜索结果列表。
```typescript
fuse.search(/* pattern , options*/)
```
选项:
- `limit`(`number`类型):表示返回搜索结果的最大数量。
##### `setCollection`
替换整个文档集合。如果未提供索引,则会自动生成一个。示例:
```typescript
const fruits = ['apple', 'orange']
const fuse = new Fuse(fruits)
fuse.setCollection(['banana', 'pear'])
```
##### `add`
将文档添加到集合中。示例:
```typescript
const fruits = ['apple', 'orange']
const fuse = new Fuse(fruits)
fuse.add('banana')
console.log(fruits.length)
// => 3
```
##### `remove`
从列表中删除谓词返回`true`的所有文档,并返回被删除文档的数组。使用两个参数调用谓词:`(doc, index)`。示例:
```typescript
const fruits = ['apple', 'orange', 'banana', 'pear']
const fuse = new Fuse(fruits)
const results = fuse.remove((doc) => {
return doc === 'banana' || doc === 'pear'
})
console.log(fruits.length)
// => 2
console.log(results)
// => ['banana', 'pear']
```
##### `removeAt`
删除指定索引处的文档。示例:
```typescript
const fruits = ['apple', 'orange', 'banana', 'pear']
const fuse = new Fuse(fruits)
fuse.removeAt(1)
console.log(fruits)
// => ['apple', 'banana', 'pear']
```
##### `getIndex`
返回生成的 Fuse 索引。示例:
```typescript
const fruits = ['apple', 'orange', 'banana', 'pear']
const fuse = new Fuse(fruits)
console.log(fuse.getIndex().size())
// => 4
```
### 配置选项
| 名称 | 类型 | 默认 | 说明 |
| -------------------- | -------- | -------------------------------------------------------- | ------------------------------------------------------------ |
| **基本选项** | | | |
| `isCaseSensitive` | boolean | false | 指示比较是否应区分大小写。 |
| `includeScore` | boolean | false | 是否将分数包含在结果集中。分数`0`表示完全匹配,分数`1`表示完全不匹配。 |
| `includeMatches` | boolean | false | 是否应将匹配项包括在结果集中。当设置为`true`时,结果集中的每个记录都将包括匹配字符的索引。这些索引可以用于高亮显示等目的。 |
| `minMatchCharLength` | number | 1 | 只有长度超过此值的匹配项才会被返回。(例如,如果要在结果中忽略单个字符的匹配项,请将其设置为`2`)。 |
| `shouldSort` | boolean | true | 是否应对结果列表按分数进行排序。 |
| `findAllMatches` | boolean | false | 当设置为`true`时,匹配函数将继续查找搜索模式的末尾,即使在字符串中已经找到完全匹配项。 |
| `keys` | Array | [] | 将被搜索的键的列表。这支持嵌套路径、加权搜索以及在字符串和对象数组中进行搜索。 |
| **模糊匹配选项** | | | |
| `location` | number | 0 | 确定模式大致应在文本中的哪个位置找到。 |
| `threshold` | number | 0.6 | 匹配算法在什么时候放弃。阈值`0.0`表示需要完美匹配(字母和位置),阈值`1.0`会匹配任何内容。 |
| `distance` | number | 100 | 确定匹配与模糊位置(由 `location` 指定)之间的接近程度。距离模糊位置 `distance` 个字符的确切字母匹配将得分为完全不匹配。当 `distance` 为 `0` 时,要求匹配必须位于精确的 `location` 所指定的位置。而当 `distance` 为 `1000` 时,要求使用 `threshold` 值为 `0.8` 进行查找时,完全匹配必须在距离 `location` 不超过 `800` 个字符的范围内才能找到。 |
| `ignoreLocation` | boolean | false | 当`true`时,搜索将忽略`location`和`distance`,因此模式出现在字符串中的位置并不重要。 |
| **高级选项** | | | |
| `useExtendedSearch` | boolean | false | 当为`true`时,它允许使用类 UNIX 搜索命令。 |
| `getFn` | Function | (obj: T, path: string | string[]) => string | string[] | 用于获取提供路径的对象值的函数。默认情况下,还将搜索嵌套路径。 |
| `sortFn` | Function | (a, b) => number | 用于对所有结果进行排序的函数。默认情况下,将按升序相关性得分和升序索引进行排序。 |
| `ignoreFieldNorm` | boolean | false | 当为`true`时,用于排序的相关性得分计算将忽略字段长度规范。 |
| `fieldNormWeight` | number | 1 | 确定字段长度范数对评分的影响程度。值为`0`等同于忽略字段长度范数。值`0.5`将大大降低字段长度规范的影响,而值`2.0`会大大增加其影响。 |
### 索引
##### `Fuse.createIndex`
预先生成索引列表,然后将其直接传递到 Fuse 实例中。如果列表很大,这将加快实例化速度。示例:
```typescript
var books = [
{
"title": "Old Man's War",
"author": {
"firstName": "John",
"lastName": "Scalzi"
}
},
{
"title": "The Lock Artist",
"author": {
"firstName": "Steve",
"lastName": "Hamilton"
}
}
/*...*/
]
const options = { keys: ['title', 'author.firstName'] }
// 创建 Fuse 索引
const myIndex = Fuse.createIndex(options.keys, books)
// 使用索引初始化 Fuse
const fuse = new Fuse(books, options, myIndex)
```
如果在实例化期间未提供索引表,Fuse 将自动索引表。
##### `Fuse.parseIndex`
解析序列化的 Fuse 索引。示例:
```typescript
// (1) 在构建步骤中
// 创建 Fuse 索引
const myIndex = Fuse.createIndex(['title', 'author.firstName'], books)
// 序列化并保存它
fs.writeFile('fuse-index.json', JSON.stringify(myIndex.toJSON()))
// (2) 当应用程序启动时
// 加载和反序列化索引
const fuseIndex = await require('fuse-index.json')
const myIndex = Fuse.parseIndex(fuseIndex)
// 使用索引初始化 Fuse
const fuse = new Fuse(books, options, myIndex)
```
### 逻辑查询运算符
Fuse.js 支持逻辑查询操作符。这些操作符用于筛选数据并根据给定条件获取精确的结果。以下表格包含逻辑查询操作符:
| 名称 | 描述 |
| ---- | ---------------------------------------- |
| $and | 返回与**所有**子句的条件匹配的所有文档。 |
| $or | 返回与**任何**子句的条件匹配的所有文档。 |
##### `$and`
```typescript
{ $and: [ { }, { } , ... , { } ] }
```
`$and `操作符在表达式数组上执行逻辑 **AND** 操作,并选择满足所有表达式的条目。`$and` 操作符使用短路评估(即,如果第一个表达式评估为 false,则 Fuse.js 不会评估剩余的表达式)。
当指定逗号分隔的表达式列表时,Fuse.js 提供了隐式的 **AND** 操作。在多个表达式中需要指定相同的字段或操作符时,使用 `$and` 操作符进行显式的 **AND** 操作是必要的。
示例:
```typescript
const result = fuse.search({
$and: [{ author: 'abc' }, { title: 'xyz' }]
})
```
##### `$or`
`$or` 操作符在表达式数组上执行逻辑 **OR** 操作,并选择满足至少一个表达式的条目。`$or` 操作符使用短路评估(即,如果第一个表达式评估为 true,则 Fuse.js 不会评估剩余的表达式)。
示例:
```javascript
const result = fuse.search({
$or: [{ author: 'abc' }, { author: 'def' }]
})
```
#### 具有点分隔键的逻辑搜索
要处理包含点的键,可以在构建查询时使用 `$path` 和 `$val` 属性。示例:
```typescript
[
{
"title": "Old Man's War",
"author": {
"first.name": "John",
"last.name": "Scalzi",
"age": "61"
}
}
]
const options = {
useExtendedSearch: true,
includeScore: true,
keys: [
'title',
['author', 'first.name'],
['author', 'last.name'],
'author.age'
]
}
const query = {
$and: [
{
$path: ['author', 'first.name'],
$val: 'jon'
},
{
$path: ['author', 'last.name'],
$val: 'scazi'
}
]
}
```
#### 与扩展搜索一起使用
逻辑查询操作与扩展搜索非常相配。
```typescript
const result = fuse.search({
$and: [
{ title: 'old war' }, // 模糊匹配 "old war"
{ color: "'blue" }, // 精确匹配 blue
{
$or: [
{ title: '^lock' }, // 以 "lock" 开头
{ title: '!arts' } // 不包含 "arts"
]
}
]
})
```
## 约束与限制
在下述版本验证通过:
DevEco Studio 版本:4.0 Beta2(4.0.0.400),OpenHarmony SDK:API 10(4.0.9.6)。
## 目录结构
```
|---- FusejsDemo # Demo 项目
| |---- entry # 示例代码文件夹
| |---- src
| |---- main/ets/pages # Demo 页面
| |---- Index.ets # Demo 主页
| |---- settings.ets # 搜索选项设置页面
| |---- ohosTest # 库测试用例文件夹
| |---- fusejs # fuse.js 库文件夹
| |---- build # fuse.js 模块打包后的文件
| |---- src # 模块代码
| |---- index.js # 入口文件
| |---- index.d.ts # 声明文件
| |---- *.json5 # 配置文件
| |---- README.md # 安装使用说明
| |---- README.OpenSource # 开源说明
| |---- CHANGELOG.md # 更新日志
```
## 贡献代码
使用过程中发现任何问题都可以提 [Issue](https://gitee.com/openharmony-tpc/openharmony_tpc_samples/issues) 给我们,当然,我们也非常欢迎你给我们发 [PR](https://gitee.com/openharmony-tpc/openharmony_tpc_samples/pulls) 。
## 开源协议
本项目基于 [Apache License 2.0](LICENSE.txt),请自由地享受和参与开源。
致谢:
(1)原库:https://github.com/krisk/Fuse
(2)开源之夏项目导师,林嘉诚:https://gitee.com/LLLLLLin
(3)本Demo中的书籍图片素材来自开源许可图片网站:https://www.pexels.com/zh-cn/license/
## 遗留问题
截至DevEco Studio 4.0 Beta2(4.0.0.400)构建 2023年8月2日,DevEco Studio并未完美支持测试中嵌套describe的情况,但原库测试用例中包含大量的嵌套测试,所以先暂时选取典型的用例进行移植并展开,以进行接口测试,保证接口可用性,其余嵌套会自动忽略执行,后续待DevEco Studio嵌套测试问题修复完成,完善移植原库的所有嵌套测试用例。