DynamoDB Python Query with Pagination (не сканировать) - PullRequest
0 голосов
/ 04 апреля 2019

Я использую следующий код для запроса и разбивки на страницы через запрос DynamoDB:

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            return str(o)
        return super(DecimalEncoder, self).default(o)


def run(date: int, start_epoch: int, end_epoch: int):
    dynamodb = boto3.resource('dynamodb',
                              region_name='REGION',
                              config=Config(proxies={'https': 'PROXYIP'}))

    table = dynamodb.Table('XYZ')

    response = table.query(
        # ProjectionExpression="#yr, title, info.genres, info.actors[0]", #THIS IS A SELECT STATEMENT
        # ExpressionAttributeNames={"#yr": "year"},  #SELECT STATEMENT RENAME
        KeyConditionExpression=Key('date').eq(date) & Key('uid').between(start_epoch, end_epoch)
    )

    for i in response[u'Items']:
        print(json.dumps(i, cls=DecimalEncoder))

    while 'LastEvaluatedKey' in response:
        response = table.scan( ##IS THIS INEFFICIENT CODE?
            # ProjectionExpression=pe,
            # FilterExpression=fe,
            # ExpressionAttributeNames=ean,
            ExclusiveStartKey=response['LastEvaluatedKey']
        )

        for i in response['Items']:
            print(json.dumps(i, cls=DecimalEncoder))

Хотя этот код работает, он невероятно медленный, и я боюсь, что результатом является * response = table.scan. У меня сложилось впечатление, что запросы выполняются намного быстрее, чем запросы сканирования (поскольку сканирование требует полной итерации таблицы). Этот код вызывает полную итерацию таблицы базы данных?

Это может быть отдельный вопрос, но есть ли более эффективный способ (с примерами кода) сделать это? Я попытался использовать разбиение на страницы в Boto3, но не смог заставить его работать и с запросами.

Ответы [ 2 ]

1 голос
/ 05 апреля 2019

Ответ, предоставленный Надавом Хар'Элом, был ключевым для решения этой проблемы. Я неправильно использовал примеры кода разбиения на страницы DynamoDB, выполняя первоначальный запрос DynamoDB, но затем использовал сканирование для разбивки на страницы!

Правильный способ был использовать запрос изначально И для нумерации страниц:

class DecimalEncoder(json.JSONEncoder):
        def default(self, o):
            if isinstance(o, decimal.Decimal):
                return str(o)
            return super(DecimalEncoder, self).default(o)


    def run(date: int, start_epoch: int, end_epoch: int):
        dynamodb = boto3.resource('dynamodb',
                                  region_name='REGION',
                                  config=Config(proxies={'https': 'PROXYIP'}))

        table = dynamodb.Table('XYZ')

        response = table.query(
            KeyConditionExpression=Key('date').eq(date) & Key('uid').between(start_epoch, end_epoch)
        )

        for i in response[u'Items']:
            print(json.dumps(i, cls=DecimalEncoder))

        while 'LastEvaluatedKey' in response:
            response = table.query(
                KeyConditionExpression=Key('date').eq(date) & Key('uid').between(start_epoch, end_epoch),
                ExclusiveStartKey=response['LastEvaluatedKey']
            )

            for i in response['Items']:
                print(json.dumps(i, cls=DecimalEncoder))

Я все же отметил ответ Надава Хар'Эля как правильный, поскольку именно его ответ привел к этому примеру кода.

1 голос
/ 04 апреля 2019

К сожалению, да, операция «Сканирование» читает всю таблицу. Вы не сказали, что является ключом раздела вашей таблицы, но если это дата, то, что вы на самом деле делаете, это читаете один раздел, и это действительно то, что операция «Запрос» делает намного эффективнее, потому что она может перейти непосредственно к нужному разделу вместо сканирования всей таблицы в поисках этого.

Даже в Query вам все равно нужно выполнять разбиение по страницам точно так же, как вы это делали, потому что есть вероятность, что в разделе все еще много элементов. Но, по крайней мере, вы не будете сканировать всю таблицу.

Кстати, сканирование всей таблицы обойдется вам в много операций чтения. Вы можете спросить AWS, сколько считываний было учтено для вас, и это может помочь вам отследить случаи, когда вы читаете слишком много - помимо очевидной медлительности, которую вы заметили.

...