Перейти к содержимому

Data Lake, Lakehouse и Vector Databases для AI/RAG (2026)

Зачем знать на Middle 3: Современная архитектура данных — это не «один Postgres». Tech lead решает: что класть в lake (S3+Parquet), что в warehouse, что в lakehouse (Iceberg/Delta), как организовать ETL/ELT. С 2023 года к этому добавились vector databases для RAG/AI — Weaviate (на Go!), pgvector, Qdrant. Понимание этих систем — must-have, иначе ты будешь «делать аналитику в Postgres» и упрёшься в его пределы.

  1. Концепция: Data Lake vs Warehouse vs Lakehouse
  2. Глубже: форматы, query engines, Go-инструменты, vector DBs
  3. Gotchas: schema drift, маленькие файлы, vector recall vs latency
  4. Real cases: observability, аналитика, RAG-системы
  5. Вопросы (20+)
  6. Practice: построить мини data lake + RAG
  7. Источники

2000s: Data Warehouse (Teradata, Oracle, Vertica)
- Structured, schema-on-write
- Дорого, ограниченно
2010s: Data Lake (Hadoop, S3 + Parquet)
- Raw, schema-on-read
- Дёшево, но "data swamp" риск
2020s: Lakehouse (Delta Lake, Iceberg, Hudi)
- Лучшее из двух миров: ACID на S3
- Time travel, schema evolution
2024+: Lake + Vector + LLM
- Embedding storage, RAG, semantic search
ПризнакData LakeData Warehouse
СтруктураRaw, semi-structuredStructured (star/snowflake schema)
SchemaSchema-on-readSchema-on-write
ХранилищеObject storage (S3)Specialized DB (Snowflake, Redshift, BigQuery)
СтоимостьНизкая (≈$0.02/GB/мес)Высокая
QueryЧерез engines (Trino, Spark)Built-in SQL engine
Use casesML, ad-hoc, raw eventsBI, reporting, dashboards
СкоростьМедленнееБыстрее (optimized)

Lakehouse = ACID transactions на object storage.

Технологии:

TechOwnerОсобенности
Apache IcebergNetflix → ApacheOpen table format, vendor-neutral, поддержан AWS, Snowflake, Databricks
Delta LakeDatabricks → Linux FoundationTight integration with Spark/Databricks
Apache HudiUber → ApacheOptimized for upserts, streaming

Возможности lakehouse:

  • ACID транзакции на S3
  • Time travel (read snapshot at T-1h)
  • Schema evolution
  • Hidden partitioning
  • Compaction (мерж мелких файлов)
FormatTypeUse case
ParquetColumnarАналитика, OLAP, query engines
ORCColumnarHive ecosystem, аналогично Parquet
AvroRow-based с schemaKafka payloads, schema evolution friendly
JSON Lines (NDJSON)Text, rowПростой, неоптимальный
CSVTextТолько для интеграций, не для production
ArrowIn-memory columnarZero-copy между процессами

Когда Parquet:

  • Аналитика, агрегации.
  • Хорошее сжатие (snappy/zstd).
  • Predicate pushdown (читаем только нужные колонки).

Когда Avro:

  • Kafka messages.
  • Schema evolution с registry.

Когда JSON Lines:

  • Дёшевые/быстрые промежуточные.
  • Не для production query layer.
ServiceNotes
AWS S3De facto standard
GCSGoogle Cloud Storage
Azure BlobMicrosoft
MinIOSelf-hosted, S3-compatible, на Go
CephSelf-hosted, не только object
Wasabi, Backblaze B2Cheaper S3 alternatives

S3 в Go:

import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/config"
)
cfg, _ := config.LoadDefaultConfig(ctx)
client := s3.NewFromConfig(cfg)
_, err := client.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String("my-lake"),
Key: aws.String("events/2026/05/21/part-001.parquet"),
Body: file,
})
EngineОсобенности
Trino (бывший PrestoSQL)Federated queries, SQL, ANSI compliance
Apache SparkBatch + stream, ML, Python/Scala
DuckDBEmbedded, blazing fast, single-node
ClickHouseColumnar OLAP DB, но умеет читать Parquet из S3
AWS AthenaManaged Trino
SnowflakeManaged warehouse + lakehouse
DatabricksSpark + Delta Lake
BigQueryGoogle managed

DuckDB в Go (через CGO):

import "database/sql"
import _ "github.com/marcboeker/go-duckdb"
db, _ := sql.Open("duckdb", "")
rows, _ := db.Query(`
SELECT COUNT(*)
FROM read_parquet('s3://my-lake/events/2026/05/*.parquet')
WHERE event_type = 'purchase'
`)

Библиотеки:

  • github.com/parquet-go/parquet-go (форкнутый из segmentio, активный)
  • github.com/apache/arrow/go/v15/parquet

Запись:

import "github.com/parquet-go/parquet-go"
type Event struct {
UserID string `parquet:"user_id,zstd"`
EventType string `parquet:"event_type,dict"`
Timestamp int64 `parquet:"timestamp,delta"`
Amount float64 `parquet:"amount"`
}
f, _ := os.Create("events.parquet")
defer f.Close()
w := parquet.NewGenericWriter[Event](f)
for _, e := range events {
_, _ = w.Write([]Event{e})
}
w.Close()

Чтение:

r := parquet.NewGenericReader[Event](file)
defer r.Close()
batch := make([]Event, 1000)
for {
n, err := r.Read(batch)
if n > 0 {
// process batch
}
if err == io.EOF { break }
}
s3://my-lake/events/
└── year=2026/
└── month=05/
└── day=21/
├── hour=00/part-00000.parquet
├── hour=01/part-00000.parquet
└── ...

Преимущества:

  • Query engines читают только нужные партиции (partition pruning).
  • Параллелизм по партициям.

Гранулярность:

  • Слишком мелкие (per hour) — тысячи мелких файлов, slow listing.
  • Слишком крупные (per year) — нет pruning.
  • Sweet spot: day или hour для high-volume.

Проблема small files: stream ingestion пишет много мелких parquet (100KB). Query engine читает каждый файл — overhead на open/close > чтения.

Решение: периодический compaction job:

1000 файлов × 100KB → 10 файлов × 10MB

Делают через Spark/Trino или специализированные jobs Iceberg/Delta.

Iceberg в Go ещё молодой (2024–2026 — активное развитие):

  • github.com/apache/iceberg-go (Apache)
  • github.com/cloudquery/iceberg-go

Concept: Iceberg table = metadata (json) + manifests + data files (parquet).

my_table/
├── metadata/
│ ├── v1.metadata.json
│ ├── v2.metadata.json (после INSERT)
│ └── snap-xxx.avro (snapshot)
└── data/
├── part-001.parquet
└── part-002.parquet

Time travel:

-- Trino
SELECT * FROM iceberg.db.events FOR VERSION AS OF 1234567890;
SELECT * FROM iceberg.db.events FOR TIMESTAMP AS OF TIMESTAMP '2026-05-01 00:00:00';

Классический ETL:

1. Extract (от Kafka, DB, API)
2. Transform (Go-код)
3. Load в lake/warehouse

ELT (modern):

  • Load raw, transform в SQL внутри warehouse.
  • dbt — оркестратор transformations.

Go ETL skeleton:

func runETL(ctx context.Context) error {
// Extract
consumer, _ := kafka.NewReader(...)
// Transform + buffer
batch := make([]Event, 0, 10000)
for {
msg, err := consumer.ReadMessage(ctx)
if err != nil { return err }
var e Event
json.Unmarshal(msg.Value, &e)
batch = append(batch, transform(e))
if len(batch) >= 10000 {
// Load
if err := writeParquetToS3(ctx, batch); err != nil {
return err
}
batch = batch[:0]
consumer.CommitMessages(ctx, msg)
}
}
}

Orchestration:

  • Airflow (Python) — стандарт.
  • Prefect — Python, modern.
  • Dagster — Python, asset-oriented.
  • Temporal — workflow, есть Go SDK.

В Go-стеке часто используют Temporal для долгих ETL workflows.

Parquet:

  • Add column — OK (старые файлы → NULL).
  • Drop column — OK (новые читатели игнорируют).
  • Rename — break (нужны aliases).
  • Change type — break (с оговорками).

Iceberg/Delta:

  • Full schema evolution support.
  • Add/drop/rename/reorder columns.
  • Promote int → long, float → double.

Best practice: schema-on-write для критических таблиц, schema-on-read для raw events.

Kafka → ClickHouse (Kafka engine)
MergeTree table
Grafana / Metabase

ClickHouse умеет читать parquet из S3:

SELECT count() FROM s3('https://my-bucket.s3.amazonaws.com/*.parquet', 'Parquet');

В Go: clickhouse-go или native protocol.

Что такое vector embedding:

  • Текст → числовой вектор фиксированной размерности (768/1024/1536/3072 float).
  • Семантически близкие тексты → близкие векторы (cosine similarity).

Модели для embeddings (2026):

  • OpenAI text-embedding-3-small (1536d) / -large (3072d).
  • BGE (BAAI General Embedding) — open source, multilingual.
  • E5 (Microsoft) — open source.
  • sentence-transformers — старый стандарт.
  • Cohere embed-v3.
  • Voyage AI embeddings.

Exact NN: brute force, O(N·D) на каждый запрос — не масштабируется.

ANN: жертвуем точностью ради скорости.

Алгоритмы:

  1. HNSW (Hierarchical Navigable Small World) — most popular.

    • Графовый, многоуровневый.
    • Recall 95–99%, latency ms.
    • Используется в Qdrant, Weaviate, Elastic, pgvector (HNSW index с 2024).
  2. IVF (Inverted File) — кластеризация + поиск в ближайших кластерах.

    • Подходит для миллиардов векторов.
    • Используется в FAISS.
  3. PQ (Product Quantization) — сжатие векторов в кодбук.

    • Меньше памяти, чуть хуже recall.
    • Часто combine: IVF+PQ.
  4. DiskANN — графовый, оптимизирован под SSD.

DBЯзыкОсобенности
pgvectorCPostgres extension, HNSW/IVFFLAT, де факто стандарт для small/medium
WeaviateGoOpen source, hybrid search, GraphQL API
QdrantRustFast, filters + vectors, REST/gRPC
MilvusGo/C++Massive scale, billion vectors
PineconeClosedManaged, serverless
ChromaPythonLightweight, dev-friendly
VespaJavaProduction-grade, hybrid retrieval
LanceDBRustEmbedded vector DB (как SQLite for vectors)
Elasticsearch / OpenSearchJavaVector search built-in с 8.x
MongoDB Atlas Vector SearchCloudManaged

Weaviate факт: написан на Go, активно используется в production (DataStax, etc.).

Установка:

CREATE EXTENSION vector;
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT,
embedding vector(1536)
);
-- HNSW index (PG 16+ с pgvector 0.5+)
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);

Go (через pgx):

import "github.com/pgvector/pgvector-go"
// Insert
emb := pgvector.NewVector(embedding) // []float32
_, _ = pool.Exec(ctx, `INSERT INTO documents (content, embedding) VALUES ($1, $2)`,
text, emb)
// Search top-10 nearest
rows, _ := pool.Query(ctx, `
SELECT id, content, embedding <=> $1 AS distance
FROM documents
ORDER BY embedding <=> $1
LIMIT 10
`, pgvector.NewVector(queryEmbedding))

<=> — cosine distance в pgvector.

import "github.com/weaviate/weaviate-go-client/v4/weaviate"
cfg := weaviate.Config{Host: "localhost:8080", Scheme: "http"}
client, _ := weaviate.NewClient(cfg)
// Insert object с auto-vectorization (если настроен module)
_, err := client.Data().Creator().
WithClassName("Document").
WithProperties(map[string]interface{}{
"content": "Go is a statically typed language...",
}).Do(ctx)
// Search nearest
result, _ := client.GraphQL().Get().
WithClassName("Document").
WithNearText(client.GraphQL().NearTextArgBuilder().
WithConcepts([]string{"programming language"})).
WithLimit(5).
Do(ctx)

Idea: LLM сам не знает наших данных → достаём релевантные документы из vector DB → даём LLM как контекст.

Pipeline:

1. Ingestion:
docs → chunks → embeddings → vector DB
2. Query time:
user question → embedding → ANN search → top-K chunks
LLM (chunks + question → answer)

Go implementation skeleton:

// 1. Embed query
queryVec := embedClient.Embed(ctx, userQuestion)
// 2. Retrieve top-K
rows, _ := db.Query(ctx, `
SELECT content FROM documents
ORDER BY embedding <=> $1
LIMIT 5
`, pgvector.NewVector(queryVec))
var contexts []string
for rows.Next() {
var c string
rows.Scan(&c)
contexts = append(contexts, c)
}
// 3. Generate
prompt := buildRAGPrompt(userQuestion, contexts)
answer := llmClient.Complete(ctx, prompt)

Чистый vector поиск иногда промахивается по keywords (например, точное имя продукта).

Hybrid = vector similarity + BM25/keyword score, объединённые reranking.

query → vector search top-100 (semantic)
→ BM25 search top-100 (lexical)
union + rerank (e.g., reciprocal rank fusion, RRF)
top-10

Weaviate, Qdrant, Elastic — все поддерживают hybrid.

Fixed-size: split каждые 512 токенов. Просто, но рвёт смысл.

Sentence-based: разбить по предложениям, склеить до лимита.

Semantic chunking: разрывы по смысловым границам (через embedding diff).

Sliding window: перекрытие между chunks (20%).

Document structure aware: уважать markdown headings.

ModelDimSpeedQualityCost
OpenAI text-embedding-3-small1536FastHigh$0.02/M tokens
OpenAI text-embedding-3-large3072MediumHigher$0.13/M tokens
BGE-small-en-v1.5384Very fastGoodFree (self-host)
BGE-large-en-v1.51024MediumVery goodFree
E5-mistral-7b-instruct4096SlowTop tierGPU required
Voyage AI voyage-31024FastTop tier$0.06/M

Stream ingestion (Kafka → S3 every 1 min) → миллионы файлов по 1 МБ → query engine задыхается на listing/open. Регулярный compaction обязателен.

Producer добавил поле, parquet reader не знает → старые файлы NULL, новые с данными. С Iceberg/Delta нормально, с raw parquet — сложно.

После 2020 AWS S3 strongly consistent, но в legacy системах ещё помнят. В MinIO/Ceph могут быть нюансы.

LIST бакета с миллионами файлов — медленно. Используй prefixes (partitions) и метаданные Iceberg.

HNSW параметры ef_construction, ef_search, M напрямую влияют. Высокий recall → больше памяти и latency.

Если поменял модель embeddings — все векторы в БД больше не совместимы. Нужна полная переиндексация.

Положил 1536-векторы, потом захотел 3072 — нужна новая колонка или таблица.

HNSW индекс на больших объёмах строится часами. Не делай это в production sync.

До pgvector 0.7 индекс HNSW ограничивал dim 2000. С 0.7+ — 16000. Проверь версию.

100M документов × $0.02/M tokens × 500 tokens avg ≈ десятки тысяч долларов на one-time индексацию.

Cosine, dot product, L2 — разные. Нельзя смешивать. Embedding модель обычно требует cosine (normalized).

RAG = только поиск + LLM. Если chunks плохо составлены — ответы плохие. Это не «магия».

Iceberg/Delta дают ACID, но усложняют операции (надо catalog, periodic compaction, etc.). Для маленьких объёмов overhead.


Apps → OTLP / Vector → Kafka
Go service:
- Парсит, фильтрует
- Партиционирует
- Пишет parquet в S3
Trino + Grafana
ClickHouse hot-data (последние 7d)
S3 cold (на год+)

Реально: десятки ТБ/день логов, экономия 80% vs Elastic.

  • Sirena (от Booking, Uber, etc.) — feature store на основе S3+Parquet+Iceberg.
  • Go-сервисы пишут фичи в lake.
  • Spark/Trino считает aggregations.
  • Online layer (Redis) для serving.
  • Kafka → ClickHouse (real-time dashboards).
  • Историческое — S3+parquet+Iceberg.
  • Аналитики работают через Trino/Metabase.
  • ML фичи — отдельный feature store.
Confluence/Notion/Docs → embeddings → Weaviate
User question → embedding → top-5 docs
GPT-4 / Claude / local LLM
Ответ + ссылки

Метрики: hit rate (нашли релевантное?), helpfulness (помог ли ответ?).

  • Описания товаров → embeddings (BGE).
  • pgvector в основной DB.
  • Hybrid search: query embedding + BM25 поверх категорий.
  • A/B test против чистого full-text.
  • Файлы репо → chunks → embeddings.
  • Vector DB по репозиторию.
  • “Find где обрабатывается auth” → семантический поиск.

  1. Чем data lake отличается от data warehouse?
  2. Что такое lakehouse? Перечисли 3 реализации.
  3. Чем Parquet лучше JSON для аналитики?
  4. Что такое predicate pushdown в parquet?
  5. Какие проблемы решает Iceberg vs голый S3+parquet?
  6. Объясни partitioning стратегию для Kafka → S3 pipeline.
  7. Что такое compaction и зачем он нужен?
  8. Сравни Trino, Spark, DuckDB. Когда что использовать?
  9. Какие есть Go-библиотеки для работы с parquet?
  10. Что такое CDC и как он связан с lake ingestion?
  11. Что такое vector embedding?
  12. Объясни HNSW. Чем отличается от IVF?
  13. Сравни pgvector, Weaviate, Qdrant. Когда что?
  14. Что такое RAG? Опиши pipeline.
  15. Что такое hybrid search?
  16. Какие стратегии chunking ты знаешь?
  17. Какие метрики оценки качества RAG-системы?
  18. Чем cosine similarity отличается от dot product? Когда что?
  19. Что произойдёт, если поменять embedding модель в production?
  20. Опиши schema evolution в Iceberg.
  21. Какие проблемы возникают с small files?
  22. Как оптимизировать стоимость embedding (cost of indexing)?
  23. Сравни OpenAI embeddings vs BGE — когда какой?
  24. Что такое reranking в search pipeline?
  25. Как сделать time travel в lakehouse?

  1. Go-consumer Kafka.
  2. Батчинг 10000 событий или 1 минута.
  3. Запись в parquet (parquet-go).
  4. Партиционирование year=/month=/day=/hour=.
  5. Upload в MinIO/S3.
  1. На лежащие в MinIO parquet направить DuckDB.
  2. Написать query: SELECT event_type, COUNT(*) FROM ... GROUP BY 1.
  3. Сравнить latency с SELECT напрямую из Postgres.
  1. Скачать 1000 markdown файлов (например, документация Go).
  2. Chunking по 500 токенов.
  3. Embeddings через OpenAI API или локальный BGE через ollama.
  4. Сохранить в pgvector.
  5. Простой HTTP endpoint: вопрос → top-5 chunks.
  6. Подключить LLM (OpenAI/local) → итоговый ответ.
  1. Развернуть Weaviate в Docker.
  2. Импортировать 10000 продуктов (название, описание).
  3. Hybrid search: name match "iphone" + semantic similarity.
  4. Сравнить с чистым BM25 и чистым vector.
  1. Создать Iceberg table через Trino/Spark.
  2. Из Go (iceberg-go) добавить записи.
  3. Сделать time travel: state before/after.

  1. Bill Inmon — Building the Data Lakehouse (2021)
  2. Apache Iceberg documentation: https://iceberg.apache.org/
  3. Delta Lake documentation: https://delta.io/
  4. Apache Hudi: https://hudi.apache.org/
  5. Trino docs: https://trino.io/docs/current/
  6. DuckDB documentation: https://duckdb.org/docs/
  7. parquet-go: https://github.com/parquet-go/parquet-go
  8. pgvector: https://github.com/pgvector/pgvector
  9. Weaviate docs: https://weaviate.io/developers/weaviate
  10. Qdrant docs: https://qdrant.tech/documentation/
  11. Pinecone Learning Center: https://www.pinecone.io/learn/
  12. Foundations of Vector Retrieval (Sebastian Bruch, 2024)
  13. Anthropic — Contextual Retrieval (2024 blog)
  14. Hyung Won Chung — Embeddings and BERT lectures
  15. Spotify ANN benchmarks: https://github.com/erikbern/ann-benchmarks
  16. Iceberg-Go: https://github.com/apache/iceberg-go
  17. Designing Data-Intensive Applications — Kleppmann (главы про analytical storage)

Резюме. Data lake/lakehouse — это новая стандартная архитектура для аналитики. Tech lead решает: что в S3+parquet, что в lakehouse (Iceberg), что в warehouse (ClickHouse). В Go — parquet-go, S3 SDK, и обёртки. Vector DBs стали обязательной частью стека из-за RAG: pgvector для простых случаев, Weaviate (Go-native!) для production, Qdrant для perf. Понимание ANN (HNSW), embedding моделей, chunking стратегий — must-have для tech lead в 2026.