簡體   English   中英

有沒有辦法在 DynamoDB 中查詢多個 hash 鍵?

[英]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);

所以基本上,我想知道是否有可能消除queryAssignedassigned變量,並通過相同的查詢process處理assignedStatusprocessStatus ,以查找不是新的或完整的項目。

不,截至今天,無法在同一個請求中發送多個查詢。 如果您擔心延遲,您可以在不同的線程中同時發出多個請求。 如果 Dynamo 提供,這將需要與“雙重查詢”相同數量的網絡帶寬(假設您正在制作 2 個,而不是數百個)。

無法通過多個哈希鍵進行查詢,但是,從 2014 年 4 月開始,您可以使用 QueryFilter 以便除了哈希鍵字段之外還可以通過非鍵字段進行過濾。

在 2014 年 4 月 24 日的一篇博客文章中,AWS 宣布發布“QueryFilter”選項:

隨着今天的發布,我們擴展了這個模型,支持對非關鍵屬性的查詢過濾 您現在可以將QueryFilter作為對 Query 函數調用的一部分。 在基於鍵的檢索之后和​​結果返回給您之前應用過濾器。 以這種方式過濾可以減少返回到應用程序的數據量,同時還可以簡化和精簡代碼

在那里查看http://aws.amazon.com/blogs/aws/improved-queries-and-updates-for-dynamodb/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+AmazonWebServicesBlog+%28Amazon+Web+Services+Blog% 29

分享我今天的空缺。

GetItem、查詢、掃描

使用正常的 DynamoDB 操作,您可以在每個請求中僅查詢一個 hash 鍵(使用GetItemQuery操作)或一次查詢所有 hash 鍵(使用Scan操作)。

批量獲取項目

您可以使用BatchGetItem操作,但它需要您指定一個完整的主鍵(包括范圍鍵,如果有的話)。

PartiQL

最近,您還可以使用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表的主鍵。

代碼片段

  • DynamoDB 實體
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;
}

  • DynamoDB 存儲庫類
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();
        }
    }
}

你可能有一個看BatchGetItem操作或batchLoad()的方法DynamoDBMapper 盡管與查詢略有不同,因為它不是在散列鍵上使用OR條件的查詢,但它可以讓您(通常)完成相同的事情。 這里是語言不可知文檔,這里是Javadoc

Amazon API 不支持多個 hashkey 過濾器,但您可以使用 HASH KEY + RANGE KEY 過濾器來使用 batchGetItem 方法獲取結果..

http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/batch-operation-lowlevel-java.html#LowLevelJavaBatchGet

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM