如何使用 dynamodb aws 中的索引有效地检索记录

How to retrieve records efficiently using indices in dynamodb aws

我想获取class 5到class 11所有男生或女生的记录,他们获得了x1数学成绩 x2 之间,科学成绩介于 y1y2 之间z1z2 英文标记在 w1w2[=52= 之间] 社会标记...

我的模型如下所示:

type StudentMarks
    @model
    @key(
        name: "filterbyClassAndMarks"
        fields: [
            "gender"
            "classCode"
            "mathsMarks"
            "socialMarks"
            "englishMarks"
            "scienceMarks"
        ]
        queryField: "filterbyClassAndMarks"
    )
    @auth(
        rules: [
            { allow: private, provider: iam, operations: [read] }
            { allow: public, provider: iam, operations: [read] }
        ]
    ) {
    id: ID!
    name: String
    gender: String
    classCode: String
    mathsMarks: String
    socialMarks: String
    englishMarks: String
    scienceMarks: String
}

以性别作为分区键(hashkey)和复合 sort/range 键与 classCode、mathMarks、socialMarks、scienceMarks、englishMarks 字段 is showing item count as 0.

我正在尝试使用以下 graphql 进行查询:

    const listOfStudents = await API.graphql({
                query: queries.filterbyClassAndMarks,
                variables: {
                    gender: "m",
                    classCodeMathsMarksSocialMarksEnglishMarksScienceMarks: {
                        between: [
                            {
                                classCode: "05",
                                mathsMarks: "06",
                                scienceMarks: "07",
                                englishMarks: "04",
                                socialMarks: "05",
                            },
                            {
                                classCode: "11",
                                mathsMarks: "90",
                                scienceMarks: "91",
                                englishMarks: "95",
                                socialMarks: "92",
                            },
                        ],
                    },
                },
                authMode: "AWS_IAM",
            });

This table 有 11 条记录应该 return 4 条记录如绿色所示

云看日志如下:

{
    "logType": "RequestMapping",
    "path": [
        "filterbyClassAndMarks"
    ],
    "fieldName": "filterbyClassAndMarks",
    "resolverArn": "arn:aws:appsync:ap-south-1:488377001042:apis/4tbr6xolzjfctl5tdbiur7jqnu/types/Query/resolvers/filterbyClassAndMarks",
    "requestId": "5de45e66-1a5d-44dd-80cc-1a5b93a3c3aa",
    "context": {
        "arguments": {
            "gender": "m",
            "classCodeMathsMarksSocialMarksEnglishMarksScienceMarks": {
                "between": [
                    {
                        "classCode": "05",
                        "mathsMarks": "06",
                        "socialMarks": "05",
                        "englishMarks": "04",
                        "scienceMarks": "07"
                    },
                    {
                        "classCode": "11",
                        "mathsMarks": "90",
                        "socialMarks": "92",
                        "englishMarks": "95",
                        "scienceMarks": "91"
                    }
                ]
            },
        },
        "stash": {},
        "outErrors": []
    },
    "fieldInError": false,
    "errors": [],
    "parentType": "Query",
    "graphQLAPIId": "4tbr6xolzjfctl5tdbiur7jqnu",
    "transformedTemplate": "{\"version\":\"2018-05-29\",\"operation\":\"Query
\",\"limit\":100,\"query\":{\"expression\":\"#gender = :gender AND #sortKey 
BETWEEN :sortKey0 AND :sortKey1\",\"expressionNames\":{\"#gender\":\"gender
\",\"#sortKey\":\"classCode#mathsMarks#socialMarks#englishMarks#scienceMarks
\"},\"expressionValues\":{\":gender\":{\"S\":\"m\"},\":sortKey0\":{\"S
\":\"05#06#05#04#07\"},\":sortKey1\":{\"S\":\"11#90#92#95#91\"}}},\"index
\":\"filterbyClassAndMarks\",\"scanIndexForward\":true}"

}

它在结果中显示扫描计数为 0:

 "result": {
            "items": [],
            "scannedCount": 0
        },

最终响应成功,结果为空,如下所示:

Object { data: {…} }
​
data: Object { filterbyClassAndMarks: {…} }
​​
filterbyClassAndMarks: Object { items: [], nextToken: null }
​​​
items: Array []
​​​​
length: 0
​​​​
<prototype>: Array []
​​​
nextToken: null

Array []

复合排序键的关键条件是可能的as per aws documentation...我不明白我到底错过了什么。可能 GSI 索引不正确 configured/written.

由于大多数时候结果小于 table 中记录的 1% 并且是读取密集型的,因此 scanning/reading 所有记录并过滤它们是一个非常幼稚的解决方案。需要更好的解决方案,无论是使用索引还是其他方式。

第二次编辑:
Example of expected behavior of applying hash key and compound sort key before filtering.。该示例仅用于突出显示预期行为,并不表示由于散列键或复合排序键而未读取的记录的大致百分比。

DynamoDB excel 不支持在任意属性列表中进行临时查询。如果您想使用未定义(或大量)属性(例如,通过 mathMarks、socialMarks、scienceMarks、姓名、性别等获取学生)来获取相同的项目,您最好使用 DynamoDB 以外的东西。

编辑:

您已使用从根本上改变访问模式的信息更新了您的问题。你最初说

I want to fetch records of all male or female students from dynamodb who have secured more than x1 marks in maths, more than x2 marks in science, less than y1 marks in social and less than y2 marks in English...

后来将此访问模式更改为 say(强调我的)

I want to fetch records of all male or female students from class 5 to class 11 who have secured between x1 and x2 marks in maths, between y1 and y2 marks in science, between z1 and z2 marks in english and between w1 and w2 marks in social

根据性别和 class 范围对数据进行分区 可能 允许您实施此访问模式。您还从示例架构中删除了 ... other variables,这表明您可能有一个固定的标记列表,包括数学、科学、社会和英语。这不如性别和 class 重要,但听我说完 :)

您在原始问题中没有提到它,但您的数据表明您有一个 fetch Student by ID 访问模式。所以我开始通过 ID 定义学生:

分区键是STUDENT#student_id,排序键是A。我有时使用“METADATA”或“META”作为排序键,但“A”既好又短。

为了支持您的主要访问模式,我创建了一个名为 GSI1 的全局二级索引,其 PK 和 SK 属性分别为 GSI1PKGSI1SK。我分配了 GSI1PK STUDENTS#gender 并且 GSISK 是 class 属性。

这会按性别和 class 对您的数据进行分区。要进一步缩小结果范围,您需要对各种标记使用过滤器。例如,如果您想获取 class 5 到 9 之间所有具有特定分数的学生,您可以执行以下操作(在 DynamoDB 伪代码中):

QUERY from GSI1 where PK=STUDENTS#M SK BETWEEN 05 and 09
      FILTER englishMark BETWEEN 009 and 050 AND
             mathsMark BETWEEN 050 and 075 AND
             scienceMark BETWEEN 045 and 065 AND
             socialMark BETWEEN 020 and 035 AND

DynamoDB 中的过滤并不像大多数人想象的那样有效。过滤时,DynamoDB:

  1. 阅读 table
  2. 中的项目
  3. 应用过滤器删除不匹配的项目
  4. Return 项

如果您有大量 table 并且正在过滤非常小的数据集,这可能会导致糟糕的性能(和成本)。例如,如果您要对数 TB 的数据执行 scan 操作并应用过滤器来识别单个项目,那么您将会遇到麻烦。

但是,在某些情况下过滤是一个很好的解决方案。一个例子是当您可以使用分区键和排序键来缩小您正在使用的数据集时应用过滤器之前。在上面的示例中,我将您的数据按性别划分(可能将您的搜索 space 分成两半),然后再按 class 进一步缩小项目范围。您留下的数据量可能足够小,可以有效地过滤掉剩余的项目。

不过,我要指出的是,性别的基数相当 。也许有更多关于您的访问模式的细节可以帮助解决这个问题。例如,也许您可​​以按 primary/secondary 学校对学生进行分组,并创建 STUDENTS#F#1-5 的 PK。也许您可以按学区或邮政编码对它们进行分组?使用 NoSQL 数据库时,关于访问模式的细节再具体不过了!

这个练习的重点是说明两点:

  1. DynamoDB 中的过滤最好通过选择一个好的主键来实现。
  2. DynamoDB 过滤机制最适用于较小的数据子集。不要害怕在正确的地方使用它!