Размер файла может стать большим на S3. Я писал API для получения данных на S3, которые соответствуют условию в SQL-запросе, и возникает ошибка, говорящая, что размер файла слишком велик для использования selectObjectContent из S3 SDK.

Один из способов обработки — запросить его сжатую версию.

Во-первых, давайте использовать GZIP для сжатия файла.

with gzip.GzipFile('data.gz', 'w') as cf:
    cf.write(bytes(json.dumps(payload, default=str).encode('utf-8')))
# data is a list of json [{key: val]}, {key, val}, ...]

Затем загрузите файл на S3.

s3.Bucket('bucket-name').upload_file('data.gz',
                                    'file-path-on-s3/data.gz')

Теперь давайте запустим SQL-запрос к этому GZIP-файлу на S3, используя SDK, предоставленный AWS S3. Я использовал SDK в javascript.

Вы можете обнаружить, что поток событий прерывается в неправильном месте, поэтому выходные данные трудно анализировать. Я использую функцию-обработчик для объединения возвращаемого списка строк, что-то вроде нескольких сломанных фрагментов строки json, а затем разделяю их по символу «\n», который является разделителем записей в полезной нагрузке.

Вывод будет выглядеть как обычный объект json.

const s3 = new AWS.S3({
  region: 'your region',
  accessKeyId: 'your key id',
  secretAccessKey: 'your secret key',
  httpOptions: {timeout: 2000, connectTimeout: 2000},
});
s3.selectObjectContent({
    Bucket: 'bucket-name',
    Key: 'file-path-on-s3/data.gz',
    Expression: `SELECT * FROM S3Object[*][*] s WHERE [Your SQL Condition]`,
    ExpressionType: 'SQL',
    InputSerialization: {'JSON': {'Type': 'DOCUMENT'}, 'CompressionType': 'GZIP',},
    OutputSerialization: {'JSON': {}},
  }
).promise()
  .then(data => jsonHandler(data, res))
  .catch(e => res.status(500).send({err: e.toString()}))
const jsonHandler = (output, res) => new Promise((resolve, reject) => {
  const eventStream = output.Payload;
  let jsonData = null;
  let stream = '';
  eventStream.on('data', event => {
    if (event.Records) {
      // records expected: {}\n OR {}\n...{}\n
      const records = get(event, 'Records.Payload', '').toString();
      //join two partial payloads(string) which are split at incorrect position and split them in correct position after stream ends
      stream = stream.concat(records);
    } else if (event.End) {
      let stringArr = stream.split('\n')
      //the last el is ""
      var filtered = stringArr.filter(function (el) {
        return el !== '';
      });

      jsonData = filtered.map(d => JSON.parse(d));

      return resolve(res.status(200).send({data: jsonData}));
    }
  });