← Назад к вопросам

Athena выполняет запросы по JSON или JSON использовался только для описания схемы

2.0 Middle🔥 91 комментариев
#DevOps и инфраструктура#Базы данных (NoSQL)

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Amazon Athena и JSON

Это хороший вопрос, который проверяет понимание работы Athena с различными форматами данных. Дам полный ответ.

Краткий ответ

JSON использовался ТОЛЬКО для описания схемы. Athena выполняет запросы по самим данным, которые хранятся в S3 в определённом формате (Parquet, CSV, JSON и т.д.), но схема может быть определена разными способами, включая JSON.

Как это работает

Способ 1: Сразу же создание таблицы с JSON данными

CREATE EXTERNAL TABLE users (
  id INT,
  name STRING,
  email STRING,
  age INT
)
STORED AS JSONLINES
LOCATION 's3://my-bucket/users/'

Что это означает:

  • STORED AS JSONLINES — данные в S3 хранятся в JSON-формате (newline-delimited JSON)
  • Каждая строка — отдельный JSON объект
  • Athena выполняет запросы прямо по этим JSON файлам в S3
  • Схема определена в SQL CREATE TABLE
{"id": 1, "name": "Alice", "email": "alice@example.com", "age": 30}
{"id": 2, "name": "Bob", "email": "bob@example.com", "age": 25}
{"id": 3, "name": "Charlie", "email": "charlie@example.com", "age": 35}
SELECT * FROM users WHERE age > 30;
-- Результат:
-- id=1, name=Alice, email=alice@example.com, age=30
-- id=3, name=Charlie, email=charlie@example.com, age=35

Athena читает JSON файлы из S3 и выполняет запросы по ним.

Способ 2: Использование Glue Catalog

# AWS Glue создает схему в JSON-подобном формате
{
  "Name": "users",
  "StorageDescriptor": {
    "Columns": [
      {"Name": "id", "Type": "int"},
      {"Name": "name", "Type": "string"},
      {"Name": "email", "Type": "string"},
      {"Name": "age", "Type": "int"}
    ],
    "Location": "s3://my-bucket/users/",
    "InputFormat": "org.apache.hadoop.mapred.TextInputFormat",
    "OutputFormat": "org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat",
    "SerdeInfo": {
      "SerializationLibrary": "org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe"
    }
  }
}

Это JSON используется только для ОПИСАНИЯ схемы в Glue Catalog. Athena использует эту информацию для понимания структуры таблицы, но сами данные в S3 могут быть в любом формате (JSON, Parquet, CSV, ORC и т.д.).

Различие между форматом данных и схемой

ВАЖНО: format != schema definition

┌──────────────────────────────────┐
│ SCHEMA DEFINITION (SQL или JSON) │
│ ┌─────────────────────────────┐  │
│ │ id INT                      │  │
│ │ name STRING                 │  │
│ │ email STRING                │  │
│ │ age INT                     │  │
│ └─────────────────────────────┘  │
└──────────────────────────────────┘
              ↓
┌──────────────────────────────────┐
│ DATA FORMAT IN S3                │
│ ┌─────────────────────────────┐  │
│ │ JSON, CSV, Parquet,         │  │
│ │ ORC, или другой формат      │  │
│ └─────────────────────────────┘  │
└──────────────────────────────────┘

Поддерживаемые форматы в Athena

1 JSON / JSONLINES (Newline-delimited JSON)

CREATE EXTERNAL TABLE logs (
  timestamp STRING,
  level STRING,
  message STRING
)
STORED AS JSONLINES
LOCATION 's3://my-bucket/logs/'

Данные в S3:

{"timestamp": "2024-01-01T10:00:00Z", "level": "INFO", "message": "System started"}
{"timestamp": "2024-01-01T10:00:01Z", "level": "ERROR", "message": "Connection failed"}

2 Parquet (рекомендуется для Athena)

CREATE EXTERNAL TABLE events (
  event_id STRING,
  event_name STRING,
  timestamp BIGINT
)
STORED AS PARQUET
LOCATION 's3://my-bucket/events/'

Плюсы Parquet:

  • Columnar формат (быстрее для аналитики)
  • Сжатие (меньше места в S3)
  • Более быстрые запросы
  • Дешевле (Athena считает по объёму отсканированных данных)

3 CSV

CREATE EXTERNAL TABLE orders (
  order_id INT,
  customer_id INT,
  total DECIMAL(10, 2)
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION 's3://my-bucket/orders/'

4 ORC (Optimized Row Columnar)

CREATE EXTERNAL TABLE products (
  product_id INT,
  product_name STRING,
  price DECIMAL(10, 2)
)
STORED AS ORC
LOCATION 's3://my-bucket/products/'

Пример: Athena выполняет запросы по JSON

import boto3
import time

athena = boto3.client('athena')

# S3 содержит JSON файлы
# s3://my-bucket/users/part-00000.json с содержимым:
# {"id": 1, "name": "Alice", "email": "alice@example.com", "age": 30}
# {"id": 2, "name": "Bob", "email": "bob@example.com", "age": 25}

# Сначала создаем таблицу
create_table_query = """
CREATE EXTERNAL TABLE IF NOT EXISTS users (
  id INT,
  name STRING,
  email STRING,
  age INT
)
STORED AS JSONLINES
LOCATION 's3://my-bucket/users/'
"""

athena.start_query_execution(
    QueryString=create_table_query,
    QueryExecutionContext={'Database': 'default'},
    ResultConfiguration={'OutputLocation': 's3://my-bucket/athena-results/'}
)

time.sleep(5)  # Ждем создания таблицы

# Теперь выполняем запрос прямо по JSON данным
select_query = "SELECT * FROM users WHERE age > 28"

response = athena.start_query_execution(
    QueryString=select_query,
    QueryExecutionContext={'Database': 'default'},
    ResultConfiguration={'OutputLocation': 's3://my-bucket/athena-results/'}
)

query_execution_id = response['QueryExecutionId']

# Ждем результаты
while True:
    result = athena.get_query_execution(QueryExecutionId=query_execution_id)
    if result['QueryExecution']['Status']['State'] == 'SUCCEEDED':
        break
    time.sleep(1)

# Получаем результаты
results = athena.get_query_results(QueryExecutionId=query_execution_id)

for row in results['ResultSet']['Rows']:
    print(row)  # Результаты запроса по JSON данным

JSON для сложных типов

Athena может работать с вложенными JSON структурами:

CREATE EXTERNAL TABLE orders (
  order_id INT,
  customer STRUCT<id: INT, name: STRING, email: STRING>,
  items ARRAY<STRUCT<product_id: INT, quantity: INT, price: DECIMAL(10, 2)>>,
  metadata MAP<STRING, STRING>
)
STORED AS JSONLINES
LOCATION 's3://my-bucket/orders/'

Данные:

{
  "order_id": 1,
  "customer": {"id": 100, "name": "Alice", "email": "alice@example.com"},
  "items": [
    {"product_id": 1, "quantity": 2, "price": 50.00},
    {"product_id": 2, "quantity": 1, "price": 100.00}
  ],
  "metadata": {"source": "web", "campaign": "summer_sale"}
}

Запросы:

-- Доступ к полям struct
SELECT order_id, customer.name FROM orders;

-- Работа с массивами
SELECT order_id, items[0].product_id FROM orders;

-- Функции для работы с массивами
SELECT order_id, size(items) as item_count FROM orders;

Ответ на исходный вопрос

Вариант 1 (правильный)

JSON использовался ТОЛЬКО для описания схемы — это верно, если речь идёт о JSON как о способе определения структуры таблицы (например, в AWS Glue Catalog или CloudFormation).

Вариант 2 (тоже верно, но в другом контексте)

Athena выполняет запросы по JSON — это верно, если речь идёт о хранении данных в JSON-формате в S3 (JSONLINES). Athena может читать и выполнять запросы по JSON файлам напрямую.

Правильный полный ответ

"Athena может работать с JSON двумя способами:

  1. JSON как формат данных: Athena выполняет запросы по JSON файлам, хранящимся в S3 (STORED AS JSONLINES)
  2. JSON как описание схемы: JSON используется для определения структуры таблицы (например, в AWS Glue Catalog или при создании таблицы через AWS Console)

Они не взаимоисключающие — оба способа используются одновременно. Athena использует JSON описание схемы, чтобы понять, как интерпретировать JSON (или другие) данные в S3."

Рекомендация

Для лучшей производительности в Athena используй Parquet вместо JSON:

  • Parquet быстрее (columnar format)
  • Дешевле (меньше данных для сканирования)
  • Лучше сжимается
# Преобразование JSON в Parquet
import pandas as pd
import pyarrow.parquet as pq

# Читаем JSON
df = pd.read_json('s3://my-bucket/users.jsonl', lines=True)

# Сохраняем в Parquet
df.to_parquet('s3://my-bucket/users-parquet/')