【问题标题】:How to querying and filtering efficiently on Fauna DB?如何在 Fauna DB 上高效地查询和过滤?
【发布时间】:2021-11-02 23:35:07
【问题描述】:

例如,假设我们有一个包含数十万客户文档的集合,其中包含 3 个字段:姓名、月薪和年龄。

如何搜索monthly_salary大于2000且年龄大于30的文档?

在 SQL 中,这很简单,但对于 Fauna,我很难理解最佳方法,因为 Index 的术语仅适用于完全匹配。我在文档中看到我可以使用 Filter 功能,但我需要提前获取所有文档,因此它看起来有点违反直觉且性能不佳。

以下是我如何实现它的示例,但不确定这是否是最佳方法,尤其是在它包含大量记录的情况下。

Map(
  Filter(
    Paginate(Documents(Collection('clients'))),
    Lambda(
      'client',
      And(
        GT(Select(['data', 'monthly_salary'], Get(Var('client'))), 2000),
        GT(Select(['data', 'age'], Get(Var('client'))), 30),
        )
      )
    ),
    Lambda(
      'filteredClients',
      Get(Var('filteredClients'))
      )
  
  )

  

这是正确的还是我遗漏了一些关于 Fauna 和 FQL 的基本概念? 谁能帮忙?

提前致谢

【问题讨论】:

    标签: faunadb


    【解决方案1】:

    使用索引执行高效搜索。您可以查看search with Indexesthere is a "cookbook" 的文档,了解一些不同的搜索示例。

    有两种使用索引进行搜索的方法,你使用哪一种取决于你是搜索相等(完全匹配)还是不等式(大于或小于,例如)。

    搜索平等

    如果您需要完全匹配,请使用索引 terms。这在文档中是最明确的,这也不是你最初的问题,所以我不会在这里多说。但这里是一个简单的例子

    给定具有此形状的用户文档

    {
      ref: Ref(Collection("User"), "1234"),
      ts: 16934907826026,
      data: {
        name: "John Doe",
        email: "jdoe@example.com,
        age: 50,
        monthly_salary: 3000
      }
    }
    

    以及如下定义的索引

    CreateIndex({
      name: "users_by_email",
      source: Collection("User"),
      terms: [ { field: ["data", "email"] } ],
      unique: true // user emails are unique
    })
    

    您可以使用...搜索完全匹配的Match function

    Get(
      Match(Index("user_by_email"), "jdoe@example.com")
    )
    

    搜索不等式

    搜索不等式更有趣也更复杂。它需要使用索引 valuesRange function

    按照上面的文档,我们可以新建一个索引

    CreateIndex({
      name: "users__sorted_by_monthly_salary",
      source: Collection("User"),
      values: [ 
        { field: ["data", "monthly_salary"] },
        { field: ["ref"] }
      ]
    })
    

    请注意,我没有在上述索引中定义任何 terms。对于不等式来说,重要的还是values。我们还将 ref 作为一个值包含在内,因为我们稍后会需要它。

    现在我们可以使用Range 来获取所有工资在给定范围内的用户。该查询将获取所有工资在 2000 年及以上的用户。

    Paginate(
      Range(
        Match(Index("users__sorted_by_monthly_salary")),
        [2000],
        []
      )
    )
    

    组合索引

    对于“或”运算,请使用Union function。 对于“AND”操作,请使用Intersection function

    MatchRange 等函数返回集合。其中一个非常重要的部分是确保当您将 Set 与 Intersection 之类的函数“组合”时,数据的形状是相同的。

    对于没有values 的索引,使用具有相同形状的集合并不困难,它们默认为相同的单个参考值。

    Paginate(
      Intersection(
        Match(Index("user_by_age"), 50), // type is Set<Ref>
        Match(Index("user_by_monthly_salary, 3000) // type is Set<Ref>
      )
    )
    

    当 Set 有不同的形状时,需要对其进行修改,否则 Intersection 将永远不会返回结果

    Paginate(
      Intersection(
        Range(
          Match(Index("users__sorted_by_age")),
          [30],
          []
        ), // type is Set<[age, Ref]>
        Range(
          Match(Index("users__sorted_by_monthly_salary")),
          [2000],
          []
        ) // type is Set<[salary, Ref]>
      )
    )
    
    {
      data: [] // Intersection is empty
    }
    

    那么我们如何改变 Set 的形状以便它们可以相交呢?我们可以使用Join functionSingleton function

    Join 将对集合中的所有条目运行操作。我们将使用它来仅返回一个参考。

    Join(
      Range(Match(Index("users__sorted_by_age")), [30], []),
      Lambda(["age", "ref"], Singleton(Var("ref")))
    )
    

    总之:

    Paginate(
      Intersection(
        Join(
          Range(Match(Index("users__sorted_by_age")), [30], []),
          Lambda(["age", "ref"], Singleton(Var("ref")))
        ),
        Join(
          Range(Match(Index("users__sorted_by_monthly_salary")), [2000], []),
          Lambda(["age", "ref"], Singleton(Var("ref")))
        )
      )
    )
    

    组合索引的技巧

    当提供不同的术语时,您可以使用额外的逻辑来组合不同的索引,或者使用绑定搜索缺失的字段。你可以做很多很酷的事情。

    请查看cook bookFauna forums 以获取想法。

    但是为什么!!!

    这是个好问题!

    考虑一下:由于 Fauna 是作为无服务器 API 提供的,因此您需要为对文档和索引的每次读取和写入以及执行查询的计算时间付费。 SQL 可以更容易,但它是一种更高级别的语言。 SQL 后面是一个查询规划器,它对如何获取数据做出假设。如果它不能有效地做到这一点,它可能会默认扫描您的整个数据表,或者执行比您预期的要昂贵得多的操作。

    有了 Fauna,您就是查询计划者。这意味着入门要复杂得多,但这也意味着您可以很好地控制数据库的性能,从而控制您的成本。

    我们正在努力改善定义架构和所需索引的体验,但目前您必须在低级别定义这些查询。

    【讨论】:

      猜你喜欢
      • 2021-08-14
      • 2021-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多