Isar中能否基于索引对IsarLinks关联的Foo对象做文本搜索?
场景说明
我有一个Bar集合,每个Bar对象通过IsarLinks关联多个Foo对象:
@collection class Bar{ Id? id; final foos = IsarLinks<Foo>(); // 其他Bar相关代码 };
每个Foo对象包含一个String类型的text字段:
@collection class Foo{ Id? id; late String text; // 其他Foo相关代码 };
需求是:搜索并找到与特定Bar关联的、text字段包含所有指定关键词的Foo对象(不区分大小写)。比如用关键词“canada”和“street”搜索时,要匹配text为"I don't know what street, Canada is on. - Al Capone"的Foo对象。
按照Isar官方的全文搜索建议,我已经给Foo类添加了分词索引:
@collection class Foo{ Id? id; late String text; @Index(type: IndexType.value, caseSensitive: false) List<String> get words => Isar.splitWords(text); };
但目前没法通过IsarLinks便捷地基于这个索引做过滤,因此有以下问题:
问题
- 是否存在通过IsarLinks的所有项基于索引进行过滤的方法?
- 如果没有,实现上述文本搜索的最佳方案是什么?
额外问题:为什么无法通过IsarLinks实现该操作?
注:我知道可以用IsarLinks.filter构建查询筛选text包含所有关键词的Foo对象,但想了解能不能按Isar推荐的索引方式在IsarLinks上实现文本搜索。
回答
1. 目前无法直接通过IsarLinks基于索引过滤
Isar当前的API设计中,IsarLinks的过滤接口并未支持直接关联到Foo类的words索引进行查询。你没法直接在Bar.foos的链式调用里利用这个预定义的索引来做关键词匹配,必须换其他方式。
2. 最佳实现方案
推荐反向查询:直接从Foo集合入手,同时关联指定Bar的ID和关键词条件,这样就能利用words索引提升查询效率。
示例代码:
// 假设已经拿到目标Bar的id:targetBarId final matchingFoos = await isar.foos .filter() .bars((q) => q.idEqualTo(targetBarId)) // 关联到指定的Bar .wordsContainsAll(['canada', 'street']) // 利用索引匹配所有关键词 .findAll();
这里的核心是通过Foo的反向关联(Isar会自动为IsarLinks生成反向关联)来限定属于目标Bar的Foo,同时用wordsContainsAll触发索引查询,既满足需求又保证性能。
如果你的代码里没有显式定义反向关联,Isar也会自动生成默认的反向链接,命名规则是关联类名的复数形式(比如bars),可以直接使用。
额外问题:为什么IsarLinks无法实现该操作?
Isar的IsarLinks本质是面向对象的关联封装,其过滤接口IsarLinks.filter()是为简单的字段条件查询设计的,并没有和集合的索引系统做深度绑定。当前Isar的查询优化和索引利用逻辑,主要是针对直接从集合发起的查询,而非通过关联对象的链接发起的嵌套查询。简单来说,IsarLinks的查询链路没有被设计为能复用关联对象的独立索引,因此无法直接基于Foo的words索引做过滤。
内容的提问来源于stack exchange,提问作者Captain Hatteras

