FoundationDB 中的 getKey returns 意外结果

getKey in FoundationDB returns unexpected result

我试图使用 getKey 和 KeySelector 在 FoundationDB 的某个子空间中找到一个键。如果子空间中存在结果,则效果很好。

val key      = new Tuple().add(3)
val subspace = new Subspace(new Tuple().add("test-subspace"))

tr.set(key.pack(), new Tuple().pack())
tr.set(subspace.pack(key), new Tuple().pack())

tr.getKey(KeySelector.firstGreaterOrEqual(subspace.pack(key)))
              .thenApply[Tuple] { result =>
                println(Tuple.fromBytes(result)) // ("test-subspace", 3)
                subspace.unpack(result) // (3)
              }

同时,如果目标子空间中不存在key,则returns默认子空间中找到的key。这不是我所期望的...

val key      = new Tuple().add(3)
val subspace = new Subspace(new Tuple().add("test-subspace"))

tr.set(key.pack(), new Tuple().pack())

tr.getKey(KeySelector.firstGreaterOrEqual(subspace.pack(key)))
              .thenApply[Tuple] { result =>
                println(Tuple.fromBytes(result)) // (3)
                subspace.unpack(result) // Cannot unpack key that is not contained in subspace.
              }

此外,如果 db 为空,getKey 而不是返回 null,returns 一些无法被 Tuple.fromBytes 解析的奇怪字节数组。

val key = new Tuple().add("my-key")    

tr.getKey(KeySelector.firstGreaterOrEqual(key.pack()))
              .thenApply[Tuple] { result =>
                println(result == null) // false
                Tuple.fromBytes(result) // throws java.lang.IllegalArgumentException: Unknown tuple data type -1 at index 0
              }

当目标子空间不包含搜索结果时,我应该如何处理?

这是预期的行为。 Keyselector returns 你匹配条件的键 - 在这种情况下第一个键大于或等于传递的 byte[]。您需要根据您的子空间要求检查返回的密钥是否有效 - 通过使用 subspace.contains() 或对返回的密钥进行任何其他验证。

第二个问题的解释相同——返回的键可能是数据库中一些特殊的预先存在的行,不是使用元组层创建的。因此它不能使用元组层进行解析。您需要使用 subspace.contains 或一些类似的检查来检查密钥有效性。

补充一下 Guarav 所说的,当键选择器解析为数据库开头之前的键时,它 returns 空键 ('')。如果密钥解析超过数据库末尾,您将在正常事务中获得 '\xff''\xff\xff' 如果允许您的事务读取系统密钥。在密钥选择器文档 here.

的末尾简要提到了这一点

至于不在您的子空间之外返回结果,这样做可能需要 getKey 接受一个限制搜索超出该键的绑定键参数。它目前没有那个参数,但是 getRange 有并且可以用来执行相同的查询,如果你使用 1 的限制。例如,你可以这样做:

tr.getRange(KeySelector.firstGreaterOrEqual(subspace.pack(key)), subspace.range().end, 1)

在这种情况下,如果可以在与您的键选择器匹配的子空间中找到一个键,则结果将有一个键;如果找不到,则结果将为空。当然,您也将在此查询中取回值。