如何在Fauna DB上高效查询和过滤?

Per*_*elo 2 faunadb

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

\n

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

\n

在 SQL 中,这很简单,但在 Fauna 中,我很难理解最佳方法,因为索引项仅适用于完全匹配。我在文档中看到我可以使用 Filter 函数,但我需要提前获取所有文档,因此它看起来有点违反直觉并且不高效。

\n

下面是我如何实现它的示例,但不确定它是否\xe2\x80\x99 是最好的方法,特别是如果它包含大量记录。

\n
Map(\n  Filter(\n    Paginate(Documents(Collection('clients'))),\n    Lambda(\n      'client',\n      And(\n        GT(Select(['data', 'monthly_salary'], Get(Var('client'))), 2000),\n        GT(Select(['data', 'age'], Get(Var('client'))), 30),\n        )\n      )\n    ),\n    Lambda(\n      'filteredClients',\n      Get(Var('filteredClients'))\n      )\n  \n  )\n\n  \n
Run Code Online (Sandbox Code Playgroud)\n

这是正确的还是我\xc2\xb4m 缺少一些有关动物群和 FQL 的基本概念?\n有人可以帮忙吗?

\n

提前致谢

\n

ptp*_*son 6

使用索引执行有效的搜索。您可以查看使用 Indexes 进行搜索的文档,并且一些不同搜索示例的“cookbook”。

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

寻求平等

如果您需要精确匹配,请使用 Index terms。这在文档中是最明确的,而且也不是您最初的问题的内容,所以我不会在这里过多阐述。但这是一个简单的例子

给定具有这种形状的用户文档

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

和一个如下定义的索引

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

Match您可以使用...功能搜索精确匹配!

Get(
  Match(Index("user_by_email"), "jdoe@example.com")
)
Run Code Online (Sandbox Code Playgroud)

寻找不平等

寻找不平等更有趣,也更复杂。它需要使用索引Range函数

与上面的文档保持一致,我们可以创建一个新索引

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

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

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

Paginate(
  Range(
    Match(Index("users__sorted_by_monthly_salary")),
    [2000],
    []
  )
)
Run Code Online (Sandbox Code Playgroud)

组合索引

对于“OR”运算,请使用Union函数。对于“AND”运算,请使用Intersection函数

Match类似和返回集合的函数Range。其中一个非常重要的部分是确保当您将 Sets 与诸如 之类的函数“组合”时Intersection,数据的形状是相同的。

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

Paginate(
  Intersection(
    Match(Index("user_by_age"), 50), // type is Set<Ref>
    Match(Index("user_by_monthly_salary, 3000) // type is Set<Ref>
  )
)
Run Code Online (Sandbox Code Playgroud)

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

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
}
Run Code Online (Sandbox Code Playgroud)

那么我们如何改变集合的形状以便它们可以相交呢?我们可以使用该Join函数,以及该Singleton函数

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

Join(
  Range(Match(Index("users__sorted_by_age")), [30], []),
  Lambda(["age", "ref"], Singleton(Var("ref")))
)
Run Code Online (Sandbox Code Playgroud)

那么总共:

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")))
    )
  )
)
Run Code Online (Sandbox Code Playgroud)

组合索引的技巧

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

请查看烹饪书动物群论坛以获取想法。

但为什么!!!

这是个好问题!

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

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

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