2017-05-11 1 views
1

고유 한 순서 지정을 제공하는 사용자 지정 ComparableBinding/ByteIterable 조합을 구현할 수 있습니까? 그리고 어떻게 이것을 시스템에 등록 할 수 있습니까? 또한, 키에만 사용될 때 ByteIterable.subIterable (final int offset, final int length) 메서드를 구현하지 않는 것이 안전할까요? 내 유스 케이스에는 유효한 서브 테이블이 없으므로 순서가 깨질 수 있습니다.사용자 지정 ComparableBinding 구현

아래 TestStore.test() 메소드는 커서를 오름차순으로 이동시키기에 충분하지 않으므로 하단의 assert 문이 실패합니다. 하지만 키를 생성하는 빌드 - IntegerBinding.intToEntry (인덱스)를 사용 때 작동합니다

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가 데이터를 수용하기 때문에 키/값의 순서를 처리 할 필요가없는 경우 ByteIterables 인스턴스로만 사용되므로 ByteIterables가 생성되는 방식에 대해 알 수 없습니다. 또한 바인딩을 어떻게 든 등록 할 필요가 없으며 응용 프로그램에서 바인딩을 정의 할 수 있습니다. 맞춤 주문의 유일한 단점은 다소 이상한 결과를 나타내는 range search 일 수 있습니다.

subIterable() 방법은 FixedLengthByteIterable을 참조하십시오. 사용자 정의 ByteIterables를 키로만 사용하는 경우 API에서 명시적인 보증이 없어도 메소드를 구현하지 않는 것이 안전합니다.

테스트의 경우 TestKey 클래스는 모호한 순서를 정의합니다. 한편으로는, 키의 순서를 정수형의 자연 순서로 정의합니다. 다른 한편, 이진 표현에서는 자연수의 문자열 표현으로 정렬됩니다. 정수의 문자열 표현을 저장해야하는 경우 정확도를 0으로 채 웁니다. 이 경우 키에 대한 클래스를 선언 할 필요조차 없습니다. 다음과 같은 예를 들어, 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

사용자 정의 바인딩이 단조롭게 증가하는 함수, 즉 두 개의 유사한 객체 o1, o2 (o1 <= o2) 인 경우 범위 검색은 미리 정의 된 바인딩과 동일한 방식으로 예상대로 작동합니다. 두 개의 ByteIterable b1, b1 = b2 및 b1 = b2 인 경우 b1, b2 (b1 <= b2)는 o1 <= o2와 같은 객체 o1, o2를 생성합니다. –

+0

여기에 뭔가가 빠졌습니다. Xodus Cursor가 실제로 사용자 정의 ByteIterable 구현을 사용하거나 찾을 수 없다면 의도 한 순서를 따라 잡을 수있는 방법을 알 수 없습니다. 코드 스 니펫으로 질문을 업데이트했습니다. 모양을 가지고 커서를 원하는 순서로 Store를 걸어 가게하는 방법을 알려 주면 좋을 것입니다. 감사! – wolpers

관련 문제