getKey в FoundationDB возвращает неожиданный результат
Я пытаюсь найти ключ в некотором подпространстве в FoundationDB с помощью getKey и KeySelector. В случае, если результат существует в Subspace, он работает довольно хорошо.
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)
}
В то же время, если ключ не существует в целевом подпространстве, он возвращает ключ, который был найден в подпространстве по умолчанию. Что не то, что я ожидал...
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 возвращает некоторый странный байтовый массив, который не может быть проанализирован 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
}
Как я должен обрабатывать ситуации, когда целевые подпространства не содержат результат поиска?
2 ответа
Это ожидаемое поведение. Keyselector возвращает вам ключ, который соответствует условию - в этом случае первый ключ, который больше или равен переданному байту []. Вам нужно будет проверить, является ли возвращенный ключ действительным в соответствии с вашим требованием подпространства - с помощью subspace.contains() или любой другой проверки возвращенного ключа.
То же самое объяснение для второго вопроса - возвращаемый ключ может быть какой-то специальной предварительно существующей строкой в БД, которая не создается с использованием кортежного слоя. Следовательно, он не может быть проанализирован с использованием кортежного слоя. Вам необходимо проверить правильность ключа, используя subspace.contains или аналогичную проверку.
Чтобы добавить к тому, что сказал Гуарав, когда ключевой селектор разрешает ключ до начала базы данных, он возвращает пустой ключ (''
). Если ключ разрешается после конца базы данных, вы получите '\xff'
в обычной транзакции или '\xff\xff'
если вашей транзакции разрешено чтение системных ключей. Это кратко упомянуто в конце документации по выбору ключа здесь.
Что касается не возврата результата за пределы вашего подпространства, для этого, вероятно, потребуется getKey
принятие параметра связанного ключа, который ограничивает поиск за пределами этого ключа. В настоящее время у него нет этого параметра, но getRange
делает и может использоваться для выполнения того же запроса, если вы используете ограничение 1. Например, вы можете сделать:
tr.getRange(KeySelector.firstGreaterOrEqual(subspace.pack(key)), subspace.range().end, 1)
В этом случае у результата будет либо ключ, если он может быть найден в подпространстве, соответствующем вашему ключевому селектору, либо он будет пустым, если не смог. Конечно, вы также вернете значение в этом запросе.