在没有服务器端代码的 Firebase 中搜索

Posted

技术标签:

【中文标题】在没有服务器端代码的 Firebase 中搜索【英文标题】:Searching in Firebase without server side code 【发布时间】:2016-02-25 07:57:31 【问题描述】:

我正在尝试从 Firebase 获取名称中包含给定字符串的所有用户。 例如,如果我有这些用户:

Devid, Andy, Bob

我想获取名称中包含“D”的所有用户,所以我希望结果如下:

Devid, Andy

这是我的 Firebase 目前的结构:

由于 Firebase 区分大小写,我创建了一个包含小写名称的属性 name_

使用 startAt 和 endAt 我可以获取名称以定义的字符串开头的所有用户

ref.orderByChild("name_").startAt(text).endAt(text+"\uf8ff").on('value', ...);

但这只会给我名称以给定字符串开头的用户,例如,如果文本是“D”,我会得到:

Devid

1) 目前我的查询的意思是,“给我所有 name_ 以给定字符串开头的用户”有没有办法让它意味着“给我所有用户的名字包含给定的字符串”? 编辑:否

Firebase 查询没有类似于全文搜索的功能 运营商。要完成这些,您要么必须集成一个 外部全文搜索引擎,还是搞个很精致的 自定义索引方案。 Firebase and indexing/search

2) 目前我不想拥有服务器端代码,有什么好的和有效的方式来实现自定义索引?

谢谢

【问题讨论】:

使用正则表达式? 遗憾的是 startAt/endAt 不支持正则表达式 使用正则表达式时,不需要使用 startAt/endAt... 这就是重点 你是对的,问题是我们只能使用 startAt/endAt/equalsTo 来做查询。这是文档firebase.com/docs/web/guide/… Firebase 查询没有任何类似于全文搜索运算符的功能。要完成这些,您要么必须集成一个外部全文搜索引擎,要么提出一个非常复杂的自定义索引方案。以前有人问过这个问题,所以我会找到一个重复的。 【参考方案1】:

好的 - 目前的结构无法完全按照您的意愿行事。

但是这只是突然出现在我的脑海中:

users:
  user_1234
    first_name: "Devid"
    components:
       "D": true
       "e": true
       "v": true
       "i": true
       "d": true
  user_5678
    first_name: "Andy"
    components:
       "A": true
       "n": true
       "d": true
       "y": true
  user_1010
    first_name: "Bob"
    components:
       "B": true
       "o": true
       "b": true

这里有一些 ObjC 代码来实现它(并且已经过测试!)

Firebase *ref = [myRootRef childByAppendingPath:@"users"];

FQuery *q1 = [ref queryOrderedByChild:@"components/b"];
FQuery *q2 = [q1 queryEqualToValue:@1];

[q2 observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) 

    NSLog(@"%@", snapshot.value);

];

此代码返回 Bob。

要获取所有“d”人,请将“components/b”更改为“components/d”

编辑:

您可以非常疯狂并添加更​​多组合以扩展您的搜索能力

users:
  user_1234
    first_name: "Devid"
    components:
       "D": true
       "e": true
       "v": true
       "i": true
       "d": true
       "De": true
       "Dev": true
       "Devi": true
       "Devid": true
       "ev": true
       "evi": true
       "evid": true
       ... etc

编写几行代码来迭代名称并写出组合非常简单。

显然,将所有名字读取到快照中,将它们转储到数组中并(在 ObjC 中)使用 NSPredicate 提取您需要的内容会更有效(如果您的数据集有限)。

【讨论】:

感谢您的回复杰!我在想类似的事情。有没有办法使用这个解决方案来搜索像“De”这样的 2 个字符? 我认为像 "devid", "evid", "vid", "id", "d" 这样的东西应该可以工作,我也在考虑这样的解决方案 "d" :“e”:“v”:“i”:“d”:真。问题是:1)这个解决方案有效吗?有没有办法告诉 Firebase 索引这些数据? (我必须研究 Firebase 中的索引是如何工作的)2)是否可以在 Firebase 查询中使用这些索引,这样我就不必将所有数据下载到客户端,而只需将搜索结果下载到客户端? 1) 效率高吗?没有真正的方法来回答这个问题。这取决于您的数据集大小、搜索频率和许多其他因素。然而,虽然在视觉上它有点凌乱,但磁盘空间很便宜,所以它不应该成为问题。 2)索引,是的。请参阅 firebase 指南和示例。当您查询时,节点(或节点)中的所有数据都将包含在快照中,因此是的,它们被下载到客户端。数据的影响和数量将再次取决于您的数据集大小。 杰伊的答案很好。我从没想过有人会认真对待我评论中的“精心设计的自定义索引方案”部分,但你肯定正朝着这个方向前进。请注意,您在此处构建的内容本质上是全文搜索引擎也将执行的操作,尽管它们使用专门的数据结构来存储搜索词。 感谢两位的帮助!我决定接受这个答案,因为它提供了一个示例,说明如何在没有服务器端代码的情况下实现文本搜索,这就是问题的目的。自定义索引实现起来很有趣,但我可能会使用处理搜索的服务器端脚本。【参考方案2】:

github中的oxyzen库做到了 假设您使用一些包装的 firebase 进行插入和更新

对于索引部分基本上是功能:

    JSON 对文档进行字符串化。 删除所有属性名称和 JSON 只保存数据(正则表达式)。 删除所有 xml 标记(因此也包括 html)和属性(记住旧指南,“数据不应在 xml 属性中”),如果存在 xml 或 html,则仅保留纯文本。 删除所有特殊字符并用空格替换(正则表达式) 用一个空格替换多个空格的所有实例(正则表达式) 拆分为空格和循环: 对于每个单词,在您的数据库中的某个索引结构中添加对文档的引用,基本上包含以单词命名的子项,而子项以“ref/inthedatabase/dockey”的转义版本命名 然后像普通的 firebase 应用程序那样插入文档

在 oxyzen 实现中,文档的后续更新实际上会读取索引并更新它,删除不再匹配的单词,并添加新单词。

随后的单词搜索可以轻松找到单词 child 中的文档。 使用 hits 实现多词搜索

【讨论】:

以上是关于在没有服务器端代码的 Firebase 中搜索的主要内容,如果未能解决你的问题,请参考以下文章

为 Android 实现 Firebase 服务器端倒数计时器?

如何在没有客户端身份验证的情况下从服务器验证 Firebase 用户?

DataTables 服务器端搜索输入

Firebase(客户端与服务器端)

从 android 设备中删除 firebase 通知(服务器端)

在没有 cors 的情况下接收有关 firebase 功能的外部请求