2017-05-11 8 views
1

独自の順序付けを提供するカスタムのComparableBinding/ByteIterableの組み合わせを実装することは可能ですか?そして私はどのようにこれをシステムに登録しますか? また、キーに使用する場合はByteIterable.subIterable(final int offset、final int length)メソッドを実装しない方が安全でしょうか?私のユースケースでは、順序を壊すので、有効なサブタイトルはありません。カスタムComparableBindingの実装

次のTestStore.test()メソッドでは、下位のassert文が失敗するため、カーソルを昇順に移動させるには不十分です。

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); 
    } 

} 
+0

|あなたはこのとの結合使用しようとしている(環境EntityStores)? –

+0

環境のみ。 – wolpers

答えて

1

を環境のAPIを使用している場合、APIがデータを受け入れるために、キー/値の順序を気にする必要はありません。これは、しかし、鍵を生成するために、ビルドインIntegerBinding.intToEntry(インデックス)を使用する場合に動作しますByteIterablesのインスタンスのみであるため、ByteIterablesの生成方法には無関心です。何らかの形でバインディングを登録する必要もなく、アプリケーションで定義することもできます。カスタム注文の唯一の欠点は、range searchかもしれません。

subIterable()の方法については、FixedLengthByteIterableをご覧ください。カスタムByteIterablesをキーとしてのみ使用する場合、メソッドを実装しないのが安全ですが、APIの明示的な保証はありません。

あなたのテストでは、TestKeyクラスはあいまいな順序を定義します。一方では、それは自然な整数の順序としてキーの順序を定義します。一方、バイナリ表現では、自然数の文字列表現によって順序付けられます。整数の文字列表現を格納する必要がある場合は、それを何らかの精度でゼロで埋めてください。その場合、キーのクラスを宣言する必要はありません。以下のように、例えば、int key、10桁のByteIterables(keyEntry)のために計算することができます

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

私が念頭に置いていたユースケースは、大規模なデータセット([Sequence CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type#Sequence_CRDTs))を順番に反復することでした。また、キー/値のペアを挿入するときには、既存のキーが左右のキーの間に収まるように左右を見る必要があります。したがって、私のユースケースが動作するためには範囲検索が機能する必要があります。 – wolpers

+0

カスタムバインディングが単調に増加する関数、つまり2つの比較可能なオブジェクトo1、o2(o1 <= o2)の場合、範囲検索は予期されたとおりに(事前定義されたバインディングと同じ方法で)動作します。任意のb1、b2(b1 <= b2)に対して、o1 <= o2となるようなオブジェクトo1、o2を生成する。 –

+0

私はここに何かがありません。 Xodus Cursorが私のカスタムByteIterable実装を実際に使用/見つけることができない場合、意図した順序にどう対応することができないのか分かりません。質問をコードスニペットで更新しました。あなたが見て、カーソルを希望の順序でStoreを歩かせるためにこれをどのように拡張するかを教えてもらえれば素晴らしいでしょう。ありがとう! – wolpers

関連する問題