[英]Is there a way to query multiple hash keys in DynamoDB?
有沒有辦法在亞馬遜的 AWS SDK 中使用單個查詢來查詢多個 hash 鍵以獲取 Java?
這是我的問題; 我有一個項目狀態的數據庫表。 Hash 鍵是項目的狀態(即:新的、分配的、處理中的或完成的)。 范圍鍵是一組項目 ID。 目前,我有一個查詢設置,可以簡單地找到所有列為“已分配”狀態(哈希)的項目,另一個查詢設置可以查找“處理”狀態。 有沒有辦法使用單個查詢而不是為我需要查找的每個狀態發送多個查詢來執行此操作? 代碼如下:
DynamoDBMapper mapper = new DynamoDBMapper(new AmazonDynamoDBClient(credentials));
PStatus assignedStatus = new PStatus();
assignedStatus.setStatus("assigned");
PStatus processStatus = new PStatus();
processStatus.setStatus("processing");
DynamoDBQueryExpression<PStatus> queryAssigned = new DynamoDBQueryExpression<PStatus>().withHashKeyValues(assignedStatus);
DynamoDBQueryExpression<PStatus> queryProcessing = new DynamoDBQueryExpression<PStatus>().withHashKeyValues(processStatus);
List<PStatus> assigned = mapper.query(PStatus.class, queryAssigned);
List<PStatus> process = mapper.query(PStatus.class, queryProcessing);
所以基本上,我想知道是否有可能消除queryAssigned
和assigned
變量,並通過相同的查詢process
處理assignedStatus
和processStatus
,以查找不是新的或完整的項目。
不,截至今天,無法在同一個請求中發送多個查詢。 如果您擔心延遲,您可以在不同的線程中同時發出多個請求。 如果 Dynamo 提供,這將需要與“雙重查詢”相同數量的網絡帶寬(假設您正在制作 2 個,而不是數百個)。
無法通過多個哈希鍵進行查詢,但是,從 2014 年 4 月開始,您可以使用 QueryFilter 以便除了哈希鍵字段之外還可以通過非鍵字段進行過濾。
在 2014 年 4 月 24 日的一篇博客文章中,AWS 宣布發布“QueryFilter”選項:
隨着今天的發布,我們擴展了這個模型,支持對非關鍵屬性的查詢過濾。 您現在可以將QueryFilter作為對 Query 函數調用的一部分。 在基於鍵的檢索之后和結果返回給您之前應用過濾器。 以這種方式過濾可以減少返回到應用程序的數據量,同時還可以簡化和精簡代碼
分享我今天的空缺。
使用正常的 DynamoDB 操作,您可以在每個請求中僅查詢一個 hash 鍵(使用GetItem
或Query
操作)或一次查詢所有 hash 鍵(使用Scan
操作)。
您可以使用BatchGetItem
操作,但它需要您指定一個完整的主鍵(包括范圍鍵,如果有的話)。
最近,您還可以使用PartiQL ——AWS 支持的一種查詢語言來查詢 DynamoDB 表。 使用它,您可以查詢多個 hash 鍵,例如使用IN
運算符:
SELECT * FROM "table_name" WHERE "status" IN ['assigned', 'processing'];
我在 Python 代碼中使用了 PartiQL,而不是 Java,因此我無法提供實現細節。 但它應該很容易找到,因為您知道您需要使用 PartiQL。 為了以防萬一,我將在此處留下 Python 的參考。
在 C# 中試試這個。 我認為它在Java中是相似的。 UserId 它是哈希密鑰。
var table = Table.LoadTable(DynamoClient, "YourTableName");
var batchGet = table.CreateBatchGet();
batchGet.AddKey(new Dictionary<string, DynamoDBEntry>() { { "UserId", 123 } });
batchGet.AddKey(new Dictionary<string, DynamoDBEntry>() { { "UserId", 456 } });
batchGet.Execute();
var results = batchGet.Results;
為后代分享我的工作答案。 截至 2020 年 10 月,有一種方法可以使用aws-java-sdk-dynamodb-1.11.813.jar
使用單個查詢來查詢多個哈希鍵。 我有相同的要求,我必須根據多個哈希鍵(分區鍵)選擇項目,您可以將要求與 RDMS 場景相關聯,類似於查詢select * from photo where id in ('id1','id2','id3')
,這里 id 是photo
表的主鍵。
代碼片段
package com.test.demo.dynamodb.entity;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@NoArgsConstructor
@AllArgsConstructor
@lombok.Data
@DynamoDBTable(tableName = "test_photos")
@Builder
public class Photo implements Serializable {
@DynamoDBHashKey
private String id;
private String title;
private String url;
private String thumbnailUrl;
}
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.KeyPair;
import com.test.demo.dynamodb.entity.Photo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Repository
public class PhotoRepository {
@Autowired
private DynamoDBMapper dynamoDBMapper = null;
public List<Photo> findByIds(Collection<String> photoIds) {
//Constructing `KeyPair` instance and setting the HashKey,
// in this example I have only hash key,
// if you have RangeKey(Sort) you can set that also here using KeyPair#withRangeKey
List<KeyPair> keyPairs = photoIds.stream()
.map(id -> new KeyPair().withHashKey(id))
.collect(Collectors.toList());
//Creating Map where Key as Class<?> and value as a list of created keyPairs
//you can also directly use batchLoad(List<Photo> itemsToGet), the only constraint
//is if you didn't specify the Type as key and simply using the
//DynamoDBMapper#batchLoad(Iterable<? extends Object> itemsToGet)
//then the Type of Iterable should have annotated with @DynamoDBTable
Map<Class<?>, List<KeyPair>> keyPairForTable = new HashMap<>();
keyPairForTable.put(Photo.class, keyPairs);
Map<String, List<Object>> listMap = dynamoDBMapper.batchLoad(keyPairForTable);
//result map contains key as dynamoDBtable name of Photo.class
//entity(test_photo) and values as matching results of given ids
String tableName = dynamoDBMapper.generateCreateTableRequest(Photo.class)
.getTableName();
return listMap.get(tableName).stream()
.map(e -> (Photo) e)
.collect(Collectors.toList());
}
}
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.TableCollection;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.ListTablesRequest;
import com.amazonaws.services.dynamodbv2.model.ListTablesResult;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.test.demo.dynamodb.Application;
import com.test.demo.dynamodb.entity.Photo;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@ActiveProfiles("test")
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = Application.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DynamoDBFindByIdsITest {
@Autowired
private DynamoDBMapper dynamoDBMapper = null;
@Autowired
private DynamoDB dynamoDB = null;
@Autowired
private PhotoRepository photoRepository = null;
@Test
void findByIdsTest() throws InterruptedException {
//Creating dynamodb table if not already exists
createDataTableIfNotExists("test", Photo.class);
int size = 5;
//creating dummy entries for test and persisting and collecting it to
//validate with results
List<Photo> photos = IntStream.range(0, size)
.mapToObj(e -> UUID.randomUUID().toString())
.map(id ->
Photo.builder()
.id(id)
.title("Dummy title")
.url("http://photos.info/" + id)
.thumbnailUrl("http://photos.info/thumbnails/" + id)
.build()
).peek(dynamoDBMapper::save)
.collect(Collectors.toList());
//calling findByIds with the Collection of HashKey ids (Partition Key Ids)
Set<String> photoIds = photos.stream()
.map(Photo::getId)
.collect(Collectors.toSet());
List<Photo> photosResultSet = photoRepository.findByIds(photoIds);
Assertions.assertEquals(size, photosResultSet.size());
//validating returned photoIds with the created Ids
Set<String> resultedPhotoIds = photosResultSet.stream()
.map(Photo::getId)
.collect(Collectors.toSet());
Assertions.assertTrue(photoIds.containsAll(resultedPhotoIds));
}
public <T> void createDataTableIfNotExists(String tablePrefix, Class<T> clazz)
throws InterruptedException {
ListTablesRequest listTablesRequest = new ListTablesRequest();
listTablesRequest.setExclusiveStartTableName(tablePrefix);
TableCollection<ListTablesResult> tables = dynamoDB.listTables();
List<String> tablesList = new ArrayList<>();
tables.forEach((tableResult) -> {
tablesList.add(tableResult.getTableName());
});
String tableName = dynamoDBMapper.generateCreateTableRequest(clazz).getTableName();
if (!tablesList.contains(tableName)) {
CreateTableRequest tableRequest = dynamoDBMapper.generateCreateTableRequest(clazz);
tableRequest.withProvisionedThroughput(new ProvisionedThroughput(5L, 5L));
Table table = dynamoDB.createTable(tableRequest);
table.waitForActive();
}
}
}
Amazon API 不支持多個 hashkey 過濾器,但您可以使用 HASH KEY + RANGE KEY 過濾器來使用 batchGetItem 方法獲取結果..
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.