Java 如何减少Firestore集合中的读取次数?

Java 如何减少Firestore集合中的读取次数?,java,android,firebase,google-cloud-firestore,Java,Android,Firebase,Google Cloud Firestore,我从前面的一个问题中学到了如何使用,并在我的海事术语词典应用程序中实现了它。数据库中有很多术语 db是这样的: maritime_terms |- id |- term: "broad reach" |- details: "Sailing with the wind abaft the beam." |- etc 与我使用的文档一样: db.collection("maritime_terms") .startAt(searchText

我从前面的一个问题中学到了如何使用,并在我的海事术语词典应用程序中实现了它。数据库中有很多术语

db是这样的:

maritime_terms
  |- id
      |- term: "broad reach"
      |- details: "Sailing with the wind abaft the beam."
      |- etc
与我使用的文档一样:

db.collection("maritime_terms")
        .startAt(searchText)
        .endAt(searchText+ "\uf8ff")
        .limit(20);
当我开始搜索例如“broad reach”并键入第一个字母
b
,我得到20个结果。当我输入第二个字母时,我得到另外20个结果。等等问题是,我键入的每个字母都有20次读取,因此,对于一个简单的搜索,我从最少100次读取到150次甚至更多


到目前为止,我的应用程序工作得很好,但我认为一个简单的字典应用程序很昂贵。如何减少如此大量的读取?

实现这一点的方法是
debounce
搜索

这意味着您可以利用这样一个事实,即用户将以每秒一定的按键次数键入,并在每次按键后将搜索延迟一小段时间

因此,例如,如果可以预期用户以每秒5次按键的速度键入,那么在每次按键后启动一个计时器,比如说0.3秒,只有在该计时器过期后才会启动搜索

如果用户在不到0.3秒的时间内轻触另一个键,则废弃计时器并再次启动计时器0.3秒

这样,只有当用户停止键入(或者至少现在停止键入)时,搜索才会使用整个字符串执行

然而,这并不是Firestore的变化。这将改变您的客户机逻辑

示例:

  • 用户类型
    B
    :启动计时器0.3秒
  • 用户类型
    r
    0.2秒后:取消计时器,启动新计时器0.3秒
  • 用户类型
    o
    0.1秒后:取消计时器,启动新计时器0.3秒
  • 0.3秒后没有输入。用文本
    Bro
    开始搜索

  • 执行此操作的方法是对搜索进行
    debounce

    这意味着您可以利用这样一个事实,即用户将以每秒一定的按键次数键入,并在每次按键后将搜索延迟一小段时间

    因此,例如,如果可以预期用户以每秒5次按键的速度键入,那么在每次按键后启动一个计时器,比如说0.3秒,只有在该计时器过期后才会启动搜索

    如果用户在不到0.3秒的时间内轻触另一个键,则废弃计时器并再次启动计时器0.3秒

    这样,只有当用户停止键入(或者至少现在停止键入)时,搜索才会使用整个字符串执行

    然而,这并不是Firestore的变化。这将改变您的客户机逻辑

    示例:

  • 用户类型
    B
    :启动计时器0.3秒
  • 用户类型
    r
    0.2秒后:取消计时器,启动新计时器0.3秒
  • 用户类型
    o
    0.1秒后:取消计时器,启动新计时器0.3秒
  • 0.3秒后没有输入。用文本
    Bro
    开始搜索

  • 虽然Fogmeister的答案可以帮助您显著减少读取次数,但我将尝试提供另一种方法,但这将意味着您的数据库结构发生变化。这就是我要做的

    首先,我将不再像您那样搜索
    maritical\u terms
    集合。相反,我将创建一个包含数据库中所有术语的文档。每个术语都将添加到术语数组中。根据条款的长度,可以在一份文件中包含所有条款。我这样说是因为文件有限制。因此,当涉及到可以将多少数据放入文档时,存在一些限制。根据官方文件,关于:

    文档的最大大小:1 MiB(1048576字节)

    如您所见,单个文档中的数据总量限制为1 MiB。当我们谈论存储文本时,您可以存储很多

    如果所有术语都不适合单个文档,那么您只需为字母表中的每个字母创建一个文档即可。由于您知道搜索内容,因此很容易知道要阅读的文档。因此,请看一下以下模式:

    Firestore-root
       |
       --- alphabetTerms (collection)
              |
              --- a (document)
              |   |
              |   --- aTerms: ["A-Term", "A-Term", "A-Term"]
              |
              --- b (document)
                  |
                  --- bTerms: ["B-Term", "B-Term", "B-Term"]
    
    要获取
    a
    文档,只需获取一个引用并进行
    get()
    调用:

    FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
    DocumentReference aRef = rootRef.collection("alphabetTerms").document("a");
    aRef.get().addOnCompleteListener(/* ... */);
    
    即使
    aTerms
    是一个数组,当您进行
    get()
    调用时,也会将其作为
    列表
    而不是作为数组。然后,您只需使用以下命令搜索该字符串列表:

    termFromTheList.contains(searchedTerm);
    
    需要注意的一点是,为了使用此解决方案,所有术语都必须是唯一的

    此解决方案比您现在使用的解决方案要好得多,因为它允许您搜索子字符串。例如,如果您想在
    broad reach
    中搜索
    reach
    ,这是不可能的,除非您使用的是第三方服务,如

    找到匹配项后,获取它并创建新查询:

    FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
    CollectionReference maritimeTermsRef = rootRef.collection("maritime_terms");
    Query searchQuery = maritimeTermsRef.whereEqualTo("term", searchedTerm);
    searchQuery.get().addOnCompleteListener(/* ... */);
    
    使用上述解决方案,您将只读取一个文档来查找文档中的术语,并读取一个文档来显示术语的详细信息

    因此,您将把读取次数从150次减少到仅2次


    虽然Fogmeister的答案可以帮助您显著减少读取次数,但我将尝试提供另一种方法,但这将意味着您的数据库结构发生变化。这就是我要做的

    首先,我将不再像您那样搜索
    maritical\u terms
    集合。相反,我将创建一个包含数据库中所有术语的文档。每个术语都将添加到术语数组中。根据条款的长度,可以在一份文件中包含所有条款