有没有办法在Amazon的AWS SDK for Java中使用单个查询查询多个哈希键?
这是我的问题;我有一个项目状态的数据库表。哈希键是项目的状态(即:新建,分配,处理或完成)。范围键是一组项目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
变量并通过相同的查询同时处理assignedStatus
和processStatus
{ {1}},查找非新的或完整的项目。
答案 0 :(得分:9)
不,截至今天,无法在同一请求中发送多个查询。如果您担心延迟,可以在不同的线程中同时发出多个请求。如果Dynamo提供它,则需要与“双重查询”相同的网络带宽量(假设你是2,而不是数百)。
答案 1 :(得分:5)
无法通过多个哈希键进行查询,但是,从2014年4月开始,您可以使用QueryFilter,以便除了哈希键字段之外还可以按非关键字段进行过滤。
在2014年4月24日的博客文章中,AWS宣布发布了&#34; QueryFilter&#34;选项:
随着今天的发布,我们正在扩展此模型,并支持非关键属性的查询过滤。您现在可以在查询功能的调用中包含 QueryFilter 。过滤器在基于密钥的检索之后和结果返回给您之前应用。以这种方式过滤可以减少返回到您的应用程序的数据量,同时还可以简化和简化代码
答案 2 :(得分:0)
在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;
答案 3 :(得分:0)
分享我的后代工作答案。截至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();
}
}
}
答案 4 :(得分:-1)
您可以查看BatchGetItem
操作或batchLoad()
的{{1}}方法。虽然与查询略有不同,因为它不是在散列键上具有DynamoDBMapper
条件的查询,它将允许您(通常)完成相同的操作。这是language agnostic documentation,这里是Javadoc。
答案 5 :(得分:-2)
Amazon API不支持多个hashkey过滤器,但您可以使用HASH KEY + RANGE KEY过滤器来使用batchGetItem方法获取结果。