2017-05-11 4 views
1

Ist es möglich, eine benutzerdefinierte ComparableBinding/ByteIterable-Kombination zu implementieren, die eine eigene Bestellung bereitstellt? Und wie würde ich dies beim System registrieren? Wäre es außerdem sicher, die Methode ByteIterableIterable (final int offset, final int length) nicht zu implementieren, wenn sie nur für Schlüssel verwendet wird? In meinem Anwendungsfall gäbe es keine gültige Subiterables, da dies die Reihenfolge brechen würde.Benutzerdefinierte ComparableBinding-Implementierung

Die folgende TestStore.test() -Methode würde nicht ausreichen, um den Cursor in aufsteigender Reihenfolge zu verschieben, da die Anweisung assert unten fehlschlägt. Es funktioniert, wenn der Build-in IntegerBinding.intToEntry (Index) mit den Tasten zu erzeugen, aber:

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

Welche API (Environments | EntityStores) sind Sie mit dieser Bindung verwenden, gehen? –

+0

Nur Umgebungen. – wolpers

Antwort

1

die Umgebungen API Bei der Verwendung gibt es keine Notwendigkeit die Ordnung der Schlüssel/Werte zu pflegen, da die API-Daten akzeptiert nur als ByteIterables Instanzen, so ist es agnostisch, wie die ByteIterables erzeugt werden. Es gibt auch keine Notwendigkeit, eine Bindung irgendwie zu registrieren, sie kann in der Anwendung definiert werden. Der einzige Nachteil der benutzerdefinierten Bestellung kann range search sein, die irgendwie seltsame Ergebnisse produziert.

Wie für die subIterable() Methode, werfen Sie einen Blick auf FixedLengthByteIterable. Wenn Sie benutzerdefinierte ByteIterables nur als Schlüssel verwenden, ist es sicher, die Methode nicht zu implementieren, obwohl dies in der API nicht ausdrücklich garantiert wird.

Wie bei Ihrem Test definiert die TestKey-Klasse eine mehrdeutige Reihenfolge. Auf der einen Seite definiert es die Reihenfolge der Schlüssel als natürliche Ganzzahl. Auf der anderen Seite ist es in binärer Darstellung nach String-Darstellung natürlicher Integer geordnet. Wenn Sie eine String-Repräsentation von Ganzzahlen speichern müssen, füllen Sie sie mit einiger Genauigkeit auf. In diesem Fall müssen Sie nicht einmal eine Klasse für Schlüssel deklarieren. Z. B. für int key, 10-stellige ByteIterables (keyEntry) kann wie folgt berechnet werden:

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

Der Anwendungsfall, den ich im Sinn hatte, war, in der Lage zu sein, über einen großen Datensatz ([Sequenz CRDT] (https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type#Sequence_CRDTs)) in der richtigen Reihenfolge zu iterieren. Auch beim Einfügen von Schlüssel/Wert-Paaren müsste ich in der Lage sein, nach links und rechts nach vorhandenen Schlüsseln zu suchen, um einen Schlüssel zu erzeugen, der dazwischen passt. Daher müsste die Bereichssuche funktionieren, damit mein Anwendungsfall funktioniert. – wolpers

+0

Bereichssuche würde wie erwartet funktionieren (genauso wie bei vordefinierten Bindungen), wenn Ihre benutzerdefinierte Bindung eine monoton steigende Funktion ist, dh für zwei vergleichbare Objekte o1, o2 (o1 <= o2) erzeugt sie zwei ByteIterables b1, b2, so dass b1 <= b2, und umgekehrt: für jedes b1, b2 (b1 <= b2) erzeugt es Objekte o1, o2, so dass o1 <= o2. –

+0

Ich vermisse etwas hier. Ich kann einfach nicht sehen, wie der Xodus Cursor mit der beabsichtigten Reihenfolge Schritt halten kann, wenn er meine benutzerdefinierte ByteIterable-Implementierung nicht verwenden kann. Ich habe die Frage mit einem Code-Snippet aktualisiert. Es wäre toll, wenn du einen Blick darauf werfen könntest und mir erzählst, wie ich das erweitern kann, damit der Cursor den Store in der gewünschten Reihenfolge laufen lässt. Vielen Dank! – wolpers

Verwandte Themen