自定义可比绑定实现



是否可以实现提供自己排序的自定义ComparableBinding/ByteIterable组合?我将如何在系统中注册它? 另外,当仅用于键时,不实现 ByteIterable.subIterable(final int offset, final int length) 方法是否安全? 在我的用例中没有有效的可子可提对象,因为这会破坏排序。

下面的 TestStore.test() 方法不足以使光标按升序移动,因为底部的断言语句失败。 当使用内置的IntegerBinding.intToEntry(index)生成键时,它工作,但是:

import jetbrains.exodus.ArrayByteIterable;
import jetbrains.exodus.ByteIterable;
import jetbrains.exodus.ByteIterator;
import org.jetbrains.annotations.NotNull;
import java.nio.charset.Charset;
public class TestKey implements ByteIterable {
private final int value;
private final byte[] bytes;
public TestKey(int value) {
this.value = value;
this.bytes = Integer.toString(value).getBytes(Charset.forName("utf-8"));
}
@Override
public int compareTo(@NotNull ByteIterable o) {
return Integer.compare(value, ((TestKey)o).value);
}
@Override
public ByteIterator iterator() {
return new ArrayByteIterable(bytes).iterator();
}
@Override
public byte[] getBytesUnsafe() {
return bytes;
}
@Override
public int getLength() {
return bytes.length;
}
@Override
public @NotNull ByteIterable subIterable(int offset, int length) {
throw new UnsupportedOperationException("subIterable");
}
}

import jetbrains.exodus.ByteIterable;
import jetbrains.exodus.bindings.IntegerBinding;
import jetbrains.exodus.bindings.StringBinding;
import jetbrains.exodus.env.Cursor;
import jetbrains.exodus.env.Environment;
import jetbrains.exodus.env.Environments;
import jetbrains.exodus.env.Store;
import jetbrains.exodus.env.StoreConfig;
import jetbrains.exodus.env.Transaction;
import jetbrains.exodus.env.TransactionalExecutable;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.Arrays;
import java.util.UUID;
public class TestStore {

private Store store;
private Environment environment;
public TestStore(File folder) {
environment = Environments.newContextualInstance(folder);
environment.executeInTransaction(new TransactionalExecutable() {
@Override
public void execute(@NotNull Transaction txn) {
store = environment.openStore(
UUID.randomUUID().toString(),
StoreConfig.WITHOUT_DUPLICATES,
txn,
true);
}
});
}
public void test() {
int count = 1000;
int[] orig = new int[count];
int[] iterated = new int[count];
for(int i = 0; i < count; i++) {
final int index = i;
environment.executeInTransaction(new TransactionalExecutable() {
@Override
public void execute(@NotNull Transaction txn) {
orig[index] = index;
store.put(txn,
new TestKey(index),
//     IntegerBinding.intToEntry(index),
StringBinding.stringToEntry(Integer.toString(index))
);
}
});
}

environment.executeInTransaction(new TransactionalExecutable() {
@Override
public void execute(@NotNull Transaction txn) {
int offset = 0;
try(Cursor cursor = store.openCursor(txn)) {
while(cursor.getNext()) {
ByteIterable key = cursor.getKey();
ByteIterable value = cursor.getValue();
iterated[offset++] = Integer.parseInt(StringBinding.entryToString(value));
}
}
}
});
assert Arrays.equals(orig, iterated);
}
}

如果使用环境 API,则无需关心键/值的顺序,因为 API 仅接受数据作为 ByteIterables 实例,因此它与 ByteIterable 的生成方式无关。也不需要以某种方式注册绑定,它可以在应用程序中定义。自定义排序的唯一缺点可能是范围搜索会产生有点奇怪的结果。

至于subIterable()方法,看看FixedLengthByteIterable。如果仅将自定义字节可比函数用作键,则不实现该方法是安全的,尽管 API 中没有明确的保证。

至于你的测试,TestKey 类定义了一个不明确的顺序。一方面,它将键的顺序定义为自然整数顺序。另一方面,在二进制表示中,它按自然整数的字符串表示形式排序。如果需要存储整数的字符串表示形式,请用零填充它以达到一定的精度。在这种情况下,您甚至不必为键声明一个类。例如,对于int key,10位字节可比量(keyEntry)可以计算如下:

final DecimalFormat format = (DecimalFormat) NumberFormat.getIntegerInstance();
format.applyPattern("0000000000");
final ByteIterable keyEntry = StringBinding.stringToEntry(format.format(key));

最新更新