Поиск по фото на AWS: Rekognition, Neptune, Bedrock | Гайд 2026 | AiManual
AiManual Logo Ai / Manual.
08 Мар 2026 Гайд

Интеллектуальный поиск по фото на AWS: пошаговый разбор системы на Rekognition, Neptune и Bedrock

Постройте систему интеллектуального поиска по фотографиям на AWS с использованием Rekognition, Neptune и Bedrock. Подробный гайд с архитектурой и кодом на 2026

Проблема, которая бесит: как найти старую фотографию без тегов?

У вас на S3 лежит терабайт семейных фотографий, архив клиентских проектов или просто куча мемов. Вы точно помните: там была фотография с красной машиной на фоне гор, снятая зимним утром. Но как ее найти? Перебирать тысячи файлов? Придумывать сложные названия папок? Я ненавижу этот процесс.

Обычный поиск по имени файла или EXIF-данным работает только если вы дисциплинированный архивариус (я - нет). Нужно что-то умнее. Система, которая понимает содержание фотографий и связи между ними. Которая найдет "то самое фото с собакой у озера" по описанию, даже если файл называется IMG_5487.jpg.

Забудьте про ручную разметку. В 2026 году нейросети делают это за вас, причем с пониманием контекста, который вы бы сами не заметили.

Архитектура: три кита, которые держат ваш фотоархив

Мы строим систему из трех сервисов AWS. Каждый решает свою задачу, вместе они создают полноценный интеллектуальный поиск.

Сервис Зачем нужен Что делает в нашей системе
Amazon Rekognition Компьютерное зрение Распознает объекты, лица, текст, сцены на фотографиях. Извлекает структурированные метаданные.
Amazon Bedrock Мультимодальные эмбеддинги Превращает изображения и текстовые описания в семантические векторы (эмбеддинги) для поиска по смыслу.
Amazon Neptune Графовая база данных Хранит связи между фотографиями, объектами, людьми, местами. Позволяет искать по сложным запросам типа "покажи все фото, где я и Маша были на природе".

Плюс AWS CDK для развертывания инфраструктуры как кода. Потому что настраивать это через консоль - самоубийство.

💡
В связке Rekognition + Neptune есть тонкий момент. Rekognition дает факты ("на фото есть собака, трава, закат"). Neptune добавляет отношения ("эта собака - моя, ее зову Барсик, она была на этой фотографии в 2024 году"). Bedrock же позволяет искать по описаниям, которые не привязаны к конкретным тегам.

Подготовка: что нужно перед стартом

Убедитесь, что у вас есть AWS аккаунт с правами на создание ресурсов. Установите AWS CLI и CDK. Все примеры кода будут на Python - он сейчас де-факто стандарт для таких задач.

npm install -g aws-cdk
pip install aws-cdk.aws-rekognition aws-cdk.aws-neptune aws-cdk.aws-bedrock

Создайте новый CDK проект. Я не буду разжевывать базовые вещи - если вы не знаете, как инициализировать CDK стэк, сначала разберитесь с основами.

1Загрузка и анализ: заставляем Rekognition смотреть на ваши фото

Первый шаг - анализ фотографий. Закидываем их в S3, запускаем Rekognition, получаем JSON с разметкой. Кажется просто? Почти.

Вот как НЕ надо делать:

# Плохой код: анализируем каждую фотографию отдельным вызовом
for photo in photos:
    response = rekognition.detect_labels(Image={'S3Object': {'Bucket': bucket, 'Name': photo}})
    # Сохраняем куда-то
    # Это дорого и медленно

Вместо этого используем асинхронный анализ для пачек фотографий и сохраняем результаты в DynamoDB. Стоимость снижается в разы.

# Хороший подход: запускаем задание для всей папки
response = rekognition.start_label_detection(
    Video={'S3Object': {'Bucket': bucket, 'Name': 'photos/'}},
    NotificationChannel={'SNSTopicArn': topic_arn, 'RoleArn': role_arn}
)
job_id = response['JobId']

# Когда задание завершится (через SNS), получаем результаты
results = rekognition.get_label_detection(JobId=job_id, MaxResults=1000)

Rekognition в 2026 году умеет определять не только объекты, но и сцены, эмоции, текст (с помощью Textract), даже небезопасный контент. Для семейного архива последнее может быть неожиданным сюрпризом.

Важно: настройте политику хранения результатов. DynamoDB с TTL (Time To Live) в 90 дней плюс экспорт в S3 для долгосрочного хранения - разумный компромисс между стоимостью и доступностью.

2Семантические эмбеддинги: Bedrock превращает картинки в числа

Метаданные от Rekognition - это хорошо, но недостаточно. Пользователь ищет "уютный вечер с друзьями", а не "диван, пицца, 3 человека". Нужен семантический поиск.

Здесь в игру вступает Amazon Bedrock, точнее, его мультимодальные модели для создания эмбеддингов. На момент марта 2026 года актуальны модели Titan Multimodal Embeddings G2 - они работают и с текстом, и с изображениями, приводя их к одному векторному пространству.

import boto3
from botocore.exceptions import ClientError

bedrock = boto3.client('bedrock-runtime', region_name='us-east-1')

# Получаем эмбеддинг для изображения из S3
response = bedrock.invoke_model(
    modelId='amazon.titan-embed-image-v2:0',  # Актуальная модель на 2026 год
    body=json.dumps({
        "inputImage": {
            "imageSource": {
                "s3Location": {
                    "uri": f"s3://{bucket}/{image_key}"
                }
            }
        }
    })
)
embedding = json.loads(response['body'].read())['embedding']

# То же самое для текстового запроса
text_response = bedrock.invoke_model(
    modelId='amazon.titan-embed-text-v2:0',
    body=json.dumps({"inputText": "уютный вечер с друзьями"})
)
text_embedding = json.loads(text_response['body'].read())['embedding']

Теперь можно искать фотографии, сравнивая косинусное сходство векторов. Фото "уютного вечера" будет близко к текстовому запросу, даже если на нем нет явных тегов "диван" или "пицца".

Если хотите глубже понять, как работают мультимодальные эмбеддинги, посмотрите мой разбор про кроссмодальный поиск на практике.

3Граф знаний: Neptune запоминает, кто, что и с кем

Самый интересный этап. Мы берем разрозненные данные (метки от Rekognition, эмбеддинги от Bedrock, EXIF-данные) и превращаем их в граф. В графе появляются сущности: Фотография, Человек, Объект, Место, Событие. И связи между ними.

Почему граф, а не реляционная база? Попробуйте в SQL сделать запрос "найди все фотографии, где я и мой брат были вместе в горах, но без наших родителей". В графе это естественно и быстро.

# Запрос на Gremlin для Neptune
# Находим все фотографии, где я (id: person123) и мой брат (id: person456)
# были вместе в местах с тегом 'горы', но без родителей (id: person789, person999)
g.V().hasLabel('Person').has('id', 'person123').as('me')
 .out('APPEARED_IN').as('photo')
 .in('APPEARED_IN').hasLabel('Person').has('id', 'person456').as('brother')
 .select('photo')
 .out('TAGGED_WITH').has('name', 'горы').as('location')
 .select('photo')
 .not(__.in('APPEARED_IN').hasLabel('Person').has('id', within('person789', 'person999')))
 .valueMap('id', 's3_url', 'date_taken')
 .toList()

Настройка Neptune - отдельная история. Не экономьте на инстансе. T3.medium для продакшна - путь к боли. Берите хотя бы r6g.large с памятью оптимизированной. Графовые запросы жрут RAM.

Ошибка новичков: пытаться хранить сами эмбеддинги в Neptune. Не делайте так. Храните их в S3 или векторной базе типа OpenSearch, а в Neptune держите только ссылки и метаданные.

4API поиска: соединяем все вместе

Финальный шаг - создать API, который принимает текстовый запрос или фотографию и возвращает релевантные результаты. Логика такая:

  1. Пользователь отправляет запрос "фото с моря прошлым летом"
  2. Bedrock создает эмбеддинг запроса
  3. Ищем похожие эмбеддинги в векторной базе (я использую OpenSearch с k-NN плагином)
  4. Получаем кандидатов (скажем, 50 фотографий)
  5. Фильтруем через Neptune: оставляем только те, которые были сделаны летом и имеют тег "море" или "пляж"
  6. Ранжируем по релевантности и дате
  7. Возвращаем топ-10 результатов

API лучше делать на Lambda с API Gateway. Почему? Потому что поиск - не постоянная нагрузка. Lambda запускается по запросу, вы платите только за время выполнения. Для CDK это выглядит так:

from aws_cdk import (
    aws_lambda as _lambda,
    aws_apigateway as apigateway,
)

search_lambda = _lambda.Function(self, "SearchFunction",
    runtime=_lambda.Runtime.PYTHON_3_12,
    handler="search.handler",
    code=_lambda.Code.from_asset("lambda"),
    environment={
        "NEPTUNE_ENDPOINT": neptune.cluster_endpoint.hostname,
        "OPENSEARCH_ENDPOINT": opensearch.domain_endpoint,
        "BEDROCK_MODEL_ID": "amazon.titan-embed-text-v2:0"
    }
)

api = apigateway.RestApi(self, "PhotoSearchApi",
    rest_api_name="Photo Search Service",
    description="Search photos by semantic similarity"
)
search_resource = api.root.add_resource("search")
search_resource.add_method("POST",
    apigateway.LambdaIntegration(search_lambda,
        proxy=True,
        integration_responses=[{
            'statusCode': '200',
            'responseParameters': {
                'method.response.header.Access-Control-Allow-Origin': "'*'"
            }
        }]
    ),
    method_responses=[{
        'statusCode': '200',
        'responseParameters': {
            'method.response.header.Access-Control-Allow-Origin': True
        }
    }]
)

Нюансы, которые заставят вас вырвать волосы (но не надо)

Первый нюанс - стоимость. Rekognition стоит $1 за 1000 изображений (при пакетном анализе). Bedrock - $0.0001 за 1000 токенов. Neptune - от $0.5 в час за инстанс. Для архива в 100к фото система обойдется в ~$200 в месяц. Это много или мало? Зависит от того, сколько времени ваши сотрудники тратят на поиск фото вручную.

Второй нюанс - задержки. Bedrock + Neptune + OpenSearch дают ответ за 200-500 мс. Для веб-приложения нормально. Но если вам нужна молниеносная скорость, кэшируйте популярные запросы в ElastiCache (Redis).

Третий нюанс - точность. Система ищет "счастливые моменты" и находит фото с улыбающимися людьми. Но также может найти фото грустного человека на фоне надписи "счастье". Это проблема всех семантических моделей. Решение - комбинировать подходы: семантический поиск + фильтрация по точным тегам.

Четвертый нюанс - приватность. Если у вас фотографии людей, нужны согласия на обработку персональных данных. Rekognition определяет лица, эмоции, возраст. В некоторых странах это регулируется строго. Для корпоративных архивов смотрите в сторону автоматической чистки персональных данных.

Что дальше? Куда развивать систему

Базовая система работает. Но есть куда расти:

  • Добавьте поиск по видео. Тот же принцип: вырезаем кадры, анализируем, индексируем. Только дороже в 10 раз.
  • Подключите генерацию описаний. Bedrock может не только искать, но и описывать фото: "На фотографии пожилая пара держится за руки на закате". Полезно для альтернативных текстов (alt text) и архивирования.
  • Сделайте рекомендации: "Вам может понравиться вот эта фотография из того же места".
  • Добавьте временные линии и автоматические альбомы: "Июнь 2025: поездка на Байкал".

Главное - не увлекайтесь. Каждая фича увеличивает сложность и стоимость. Начните с минимально рабочего продукта: поиск по текстовым запросам. Когда пользователи привыкнут, добавляйте фильтры по дате, людям, местам.

И последний совет: если вы делаете систему для e-commerce, посмотрите, как Amazon использует AI для каталогов. Там свои специфические требования к точности и скорости.

А если проект кажется слишком сложным - начните с локального прототипа. Инструменты вроде AI File Sorter показывают, что можно сделать многое даже без облачной инфраструктуры.

Только не храните терабайты фото на своем ноутбуке. Это я проверил на собственном опыте.

Подписаться на канал