2011-03-07 4 views
3

Azure 테이블 서비스를 유지하려는 엔티티가 연속적으로 나열되어 있지만 RowKey 열의 유형은 문제가 있습니다. 엔티티 수는 RowKey 열에 저장해야하므로 엔티티를 빨리 쿼리 할 수 ​​(PK = '..' && RowKey = 5), 최신 엔티티 (RowKey > 10)를 가져오고 엔티티 집합 (RowKey > 5 && RowKey < 10)을 쿼리 할 수 ​​있습니다.Azure 테이블 저장소에서 정수 RowKeys를 사용하는 방법은 무엇입니까?

RowKey는 문자열이어야하므로보다 낮은 비교는 문제가됩니다 ("100" < "11"). 숫자 앞에 0을 붙이는 것에 대해 생각했지만 (즉 "100" > "011") 엔티티의 수 (따라서 0의 수)를 예측할 수 없습니다.

정수 열을 만들 수는 있지만 인덱스 된 RowKey 열의 성능 이점이 느슨해 졌을뿐 아니라 RowKey에 적합한 다른 정보도 없습니다. 이전에이 문제가 발생한 사람이 있습니까?

답변

1

이 문제는 RowKey 클래스를 작성하여 해결했습니다.이 클래스는 문자열을 감싸고 Increment 메서드를 제공합니다.

유효한 문자 범위 (예 : 0-9 + a-z + A-Z)와이 범위 내에서 "카운트"를 정의 할 수 있습니다 (예 : az9 + 1 = aza, azZ + 1 = aA0). 이것의 장점은 오직 숫자를 사용하는 것보다 더 큰 범위의 가능한 키를 가지고 있다는 것입니다 (10^n 대신 62^n).

문자열의 길이를 미리 정의하고 변경하면 안되지만 문자열 자체를 훨씬 더 짧게 유지하면서 엔티티의 수를 저장할 수 있습니다. 예를 들어, 10 자리 숫자를 사용하면 ~8*10^17 키와 20 자리 숫자 ~7*10^35을 저장할 수 있습니다.

유효 문자 수를 더 늘리면 더 효과적으로 숫자를 사용할 수 있지만 제 경우에는 위의 범위가 충분하며 디버깅 목적으로도 충분히 읽을 수 있습니다.

이 답변으로 같은 문제가 발생하는 다른 사용자에게 도움이되기를 바랍니다.

EDIT : 비슷한 것을 구현하려는 사람을위한 부수적 인 메모입니다. 맞춤 문자 범위를 만들어야하며 0보다 큰 수를 계산할 수 없습니다 (예 : /, \). 숫자 (0-9)와 소문자.

+4

포스트 업, 바퀴에게 매력 같은 –

0

Linq to query against Azure Table Storage을 사용하는 경우 잠재적 인 해결책을 발견했습니다.

당신은 테이블에 대한 모델이 뭔가를 추가

...

public int ID 
{ 
    get 
    { 
     return int.Parse(RowKey); 
    } 
} 

그리고 당신은 당신의 LINQ 쿼리에서이 작업을 수행 할 수 있습니다 ...이 기술 당신 '으로

.Where(e => e.ID > 1 && e.ID < 10); 

테이블에 "set"연산이 없으므로 실제로 "ID"열을 추가하지 않습니다.

내가 확신 할 수없는 한 가지는 정확히 장면 뒤에서 일어나는 일입니다.Azure 테이블 스토리지에 대한 쿼리가 최종 형식으로 어떻게 보이는지 알고 싶지만 그 결과를 찾는 방법을 모르겠습니다. 디버깅 및 퀵타임을 사용할 때 그 정보를 찾을 수 없었습니다.

UPDATE

난 아직도 무슨 일이 일어나고 있는지 파악하지 않은,하지만이 매우 효율적 아니라고 강한 느낌을 가지고있다. 나는 갈 길이 OP를했을 때 sortable string을 만드는 것이라고 생각하고 있습니다. 그런 다음 Linq where 절에 RowKey.CompareTo() 함수를 사용하여 범위로 필터링 할 수 있습니다.

3

쉬운 방법을 발견했지만 이전 방법이 더 효율적입니다 (키 길이와 관련하여). 대신에 우리는 단지 숫자와 키를 사용할 수있는 모든 알파벳을 사용 은 (..... 000000010002) 길이를 고정하는 것입니다 :

public class ReadingEntity : TableEntity 
{ 
    public static string KeyLength = "000000000000000000000"; 
    public ReadingEntity(string partitionId, int keyId) 
    { 
     this.PartitionKey = partitionId; 
     this.RowKey = keyId.ToString(KeyLength); ; 


    } 
    public ReadingEntity() 
    { 
    } 
} 


public IList<ReadingEntity> Get(string partitionName,int date,int enddate) 
{ 
     CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); 

     // Create the CloudTable object that represents the "people" table. 
     CloudTable table = tableClient.GetTableReference("Record"); 

     // Construct the query operation for all customer entities where PartitionKey="Smith". 
     TableQuery<ReadingEntity> query = new TableQuery<ReadingEntity>().Where(TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionName), 
    TableOperators.And,TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThan, enddate.ToString(ReadingEntity.KeyLength)), TableOperators.And, 
    TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.GreaterThanOrEqual, date.ToString(ReadingEntity.KeyLength))))); 
     return table.ExecuteQuery(query).ToList(); 
} 

희망이 도움이됩니다.

5

비슷한 문제가 있습니다. RowKey가 내림차순으로 정렬되도록 지원하고 싶다는 경고가 추가되었습니다. 필자는 PartitionKey를 올바로 사용하고 있으며, "scope-id"-> "12-8374"와 같이 RowKey를 더 세분화 할 필요가있을 때 범위 지정 접두사를 사용하기 때문에 가능한 많은 수의 값을 지원하는 데 신경 쓰지 않았습니다.

마지막으로 나는 enzi가 제안한 일반적인 접근법의 특정 구현을 결정했습니다. Base64 인코딩의 수정 된 버전을 사용하여 1600 만 개가 넘는 값을 지원하며 오름차순 또는 내림차순으로 정렬 할 수있는 네 개의 문자열을 생성했습니다. 단위 테스트를 받았지만 범위 검사/유효성 검사가없는 코드가 있습니다.

/// <summary> 
/// Gets the four character string representation of the specified integer id. 
/// </summary> 
/// <param name="number">The number to convert</param> 
/// <param name="ascending">Indicates whether the encoded number will be sorted ascending or descending</param> 
/// <returns>The encoded string representation of the number</returns> 
public static string NumberToId(int number, bool ascending = true) 
{ 
    if (!ascending) 
     number = 16777215 - number; 

    return new string(new[] { 
     SixBitToChar((byte)((number & 16515072) >> 18)), 
     SixBitToChar((byte)((number & 258048) >> 12)), 
     SixBitToChar((byte)((number & 4032) >> 6)), 
     SixBitToChar((byte)(number & 63)) }); 
} 

/// <summary> 
/// Gets the numeric identifier represented by the encoded string. 
/// </summary> 
/// <param name="id">The encoded string to convert</param> 
/// <param name="ascending">Indicates whether the encoded number is sorted ascending or descending</param> 
/// <returns>The decoded integer id</returns> 
public static int IdToNumber(string id, bool ascending = true) 
{ 
    var number = ((int)CharToSixBit(id[0]) << 18) | ((int)CharToSixBit(id[1]) << 12) | ((int)CharToSixBit(id[2]) << 6) | (int)CharToSixBit(id[3]); 

    return ascending ? number : -1 * (number - 16777215); 
} 

/// <summary> 
/// Converts the specified byte (representing 6 bits) to the correct character representation. 
/// </summary> 
/// <param name="b">The bits to convert</param> 
/// <returns>The encoded character value</returns> 
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)] 
static char SixBitToChar(byte b) 
{ 
    if (b == 0) 
     return '!'; 
    if (b == 1) 
     return '$'; 
    if (b < 12) 
     return (char)((int)b - 2 + (int)'0'); 
    if (b < 38) 
     return (char)((int)b - 12 + (int)'A'); 
    return (char)((int)b - 38 + (int)'a'); 
} 

/// <summary> 
/// Coverts the specified encoded character into the corresponding bit representation. 
/// </summary> 
/// <param name="c">The encoded character to convert</param> 
/// <returns>The bit representation of the character</returns> 
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)] 
static byte CharToSixBit(char c) 
{ 
    if (c == '!') 
     return 0; 
    if (c == '$') 
     return 1; 
    if (c <= '9') 
     return (byte)((int)c - (int)'0' + 2); 
    if (c <= 'Z') 
     return (byte)((int)c - (int)'A' + 12); 
    return (byte)((int)c - (int)'a' + 38); 
} 

오름차순 매개 변수에 false를 전달하면 인코딩 된 값이 반대 방향으로 정렬됩니다. 나는 선택했다! Base64 세트는 RowKey 값에 유효하기 때문에 $를 완료해야합니다. 이 알고리즘은 추가 문자를 지원하도록 쉽게 수정 될 수 있지만 테이블 저장 키를 효율적으로 세그먼트 화해야하므로 RowKey 값에 더 큰 숫자가 적합하지 않다고 믿습니다. 다음은 출력의 예입니다.

0 -> !!!! 오름차순 & ZZZZ 내림차순

1000

-> !! DC 오름차순 & zzkL 내림차순

2000

-> !! TE 오름차순 & zzUj 내림차순

3000

-> !!입니다 오름차순 & zzF5 내림차순

4000 -> !! yU asc &zz $ T desc

5000 ->! $ C6 asc & zylr desc

,451,515,

6000 -> $ Rk를 오름차순 & zyWD 내림차순

7000 -!!!> $의 X -> $ HM 오름차순 & zyGb

8000 DESC! 오름차순 & zy0z 내림차순

9000! -> 0Ac 오름차순 & zxnL 내림차순 코드

+0

작품을 재창조 절약! Thx Thomas, 너 천재 야 !! –

관련 문제