2016-12-06 79 views
0

我在「userId」上有一個名爲「product」的全局二級索引的DynamoDB表。主鍵位於「id」上。 我試圖用「userID」GSI上的「withExclusiveStartKey」實現查詢分頁。 不過,我得到以下情況例外,當我通過一個有效的lastId:DyanmoDB:在全局二級索引上使用「withExclusiveStartKey」分頁

獨家啓動密鑰必須具有相同的尺寸表的主要模式 (服務:AmazonDynamoDBv2;狀態代碼:400;錯誤代碼: ValidationException;請求ID: 822db97e-04a3-4c36-8c72-6008e2693679)

我在做什麼錯在這裏?

public QueryResultPage<Product> findPaged(String userId,int limit,String lastId) { 
     DynamoDBMapper mapper = new DynamoDBMapper(dynamoDb);  
     Map<String, AttributeValue> vals = new HashMap<>(); 
     vals.put(":valUserId", new AttributeValue().withS(userId)); 
       DynamoDBQueryExpression<Product> queryExp = new   DynamoDBQueryExpression<Product>() 
       .withKeyConditionExpression("userId = :valUserId") 
       .withIndexName(ModelConsts.TBL_PRODUCT_GSI_USERID) 
       .withExpressionAttributeValues(vals) 
       .withScanIndexForward(false) 
       .withConsistentRead(false) 
       .withLimit(limit); 
      if (lastId != null) {//paging 
      Map<String, AttributeValue> exclusiveStartKey = new HashMap<String, AttributeValue>(); 
        exclusiveStartKey.put("id", new AttributeValue().withS(lastId)); 
       queryExp = queryExp.withExclusiveStartKey(exclusiveStartKey); 
     } 
     QueryResultPage<Product> result = mapper.queryPage(Product.class, queryExp); 
     return result;  
    } 

回答

1

GSI原始表格的所有關鍵值都應該設置爲開始鍵。如果該表具有分區鍵和排序鍵,則應將這兩個鍵值設置爲開始鍵值。

在下面的示例: -

1)videos表具有videoid作爲分區鍵和category作爲排序鍵

2)GSI與category作爲分區鍵和videoid作爲排序定義鍵

下面的代碼通過category值與開始鍵集(即分區和排序鍵)查詢GSI。

當我不填充分區或排序鍵時,我可以重現您的錯誤。

示例代碼: -

public QueryResultPage<VideoDynamoMappingAdapter> findVideosByCategoryUsingGSIAndMapperWithStartKey(
     String category) { 
    DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(dynamoDBClient); 
    QueryResultPage<VideoDynamoMappingAdapter> queryResult = null; 
    Map<String, AttributeValue> vals = new HashMap<>(); 
    vals.put(":val1", new AttributeValue().withS(category)); 
    DynamoDBQueryExpression<VideoDynamoMappingAdapter> queryExp = new DynamoDBQueryExpression<VideoDynamoMappingAdapter>() 
      .withKeyConditionExpression("category = :val1").withIndexName("VideoCategoryGsi") 
      .withExpressionAttributeValues(vals).withScanIndexForward(false).withConsistentRead(false).withLimit(1); 

    Map<String, AttributeValue> startKey = new HashMap<>(); 

    startKey.put("videoid", new AttributeValue().withS("2")); 
    startKey.put("category", new AttributeValue().withS("Thriller")); 

    queryExp.setExclusiveStartKey(startKey); 

    queryResult = dynamoDBMapper.queryPage(VideoDynamoMappingAdapter.class, queryExp); 

    System.out.println("Result size ===>" + queryResult.getResults().size()); 
    System.out.println("Last evaluated key ===>" + queryResult.getLastEvaluatedKey()); 

    for (VideoDynamoMappingAdapter videoDynamoMappingAdapter : queryResult.getResults()) { 
     System.out.println("Video data ===>" + videoDynamoMappingAdapter.toString()); 
    } 

    return queryResult; 

} 
3

我在寫這個答案對於那些你,誰試圖構建exclusiveStartKey手動,對於GSI查詢。看來,獨家開始鍵由3個部分組成:

  • GSI的哈希鍵,
  • GSI範圍鍵
  • 表鍵

這似乎並不要記錄在任何地方,因爲你應該只使用返回的lastEvaluatedKey通過撥打電話:

setLastEvaluatedKey(queryResult.getLastEvaluatedKey()); 

接受的答案是正確的,但它給讀者留下了這樣的印象:只有兩個組件對於這個鍵來說沒有幫助,在我的情況下。 這裏描述的解決方案首先在this GitHub issue中提到。

相關問題