Пишем первый рабочий пример векторного поиска сразу — без глубокой теории. Вы увидите результат за 15 минут и поймёте, зачем всё это нужно.
Пишем первый рабочий векторный поиск сразу — без глубокой теории. Вы увидите результат за 15 минут.
За следующие 15 минут вы:
Откройте терминал и установите две библиотеки:
pip install sentence-transformers faiss-cpuСоздайте файл search.py и вставьте код:
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
# 1. Документы для поиска
documents = [
"Python — язык программирования общего назначения",
"Питон — это змея из семейства удавов",
"Django — веб-фреймворк на Python для быстрой разработки",
"Flask — микрофреймворк для создания веб-приложений",
"FastAPI — современный фреймворк для создания API"
]
# 2. Загружаем модель для эмбеддингов
model = SentenceTransformer('all-MiniLM-L6-v2')
# 3. Создаём эмбеддинги для документов
embeddings = model.encode(documents)
print(f"Форма эмбеддингов: {embeddings.shape}") # (5, 384)
# 4. Создаём индекс FAISS (косинусное сходство)
dimension = embeddings.shape[1]
index = faiss.IndexFlatIP(dimension) # Inner Product
faiss.normalize_L2(embeddings) # Нормализуем для косинусного сходства
index.add(embeddings)
# 5. Поиск по запросу
query = "веб-разработка на Python"
query_embedding = model.encode([query])
faiss.normalize_L2(query_embedding)
distances, indices = index.search(query_embedding, k=2)
print(f"\nЗапрос: {query}")
print(f"Найдено документов: {indices[0]}")
print(f"Сходство: {distances[0]}")
print("\nРезультаты:")
for idx, score in zip(indices[0], distances[0]):
print(f" [{score:.3f}] {documents[idx]}")Запустите:
python search.pyОжидаемый вывод:
Форма эмбеддингов: (5, 384)
Запрос: веб-разработка на Python
Найдено документов: [2 4]
Сходство: [0.823 0.756]
Результаты:
[0.823] Django — веб-фреймворк на Python для быстрой разработки
[0.756] FastAPI — современный фреймворк для создания API
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐
│ Документы │ ──→ │ Модель │ ──→ │ FAISS │ ──→ │ Результаты │
│ (текст) │ │ Embedding │ │ (индекс) │ │ поиска │
└─────────────┘ └──────────────┘ └─────────────┘ └──────────────┘
Обратите внимание: в запросе "веб-разработка на Python" нет слова "Django", но система нашла его!
Почему? Потому что модель понимает смысл:
Традиционный поиск (по ключевым словам) не нашёл бы Django — там нет слова "веб-разработка". Векторный поиск находит документы по смыслу.
Модифицируем код, чтобы видеть, что именно ищем:
# Добавьте после строки с query:
print(f"Исходный запрос: {query}")
print(f"Эмбеддинг (первые 10 чисел): {query_embedding[0][:10]}")Вы увидите, что запрос тоже превратился в вектор чисел.
Попробуйте разные запросы в коде:
# Попробуйте эти запросы:
test_queries = [
"змея удав", # Найдёт питона
"фреймворк для API", # Найдёт FastAPI
"быстрая веб-разработка", # Найдёт Django
"маленький фреймворк", # Найдёт Flask
]
for query in test_queries:
query_embedding = model.encode([query])
faiss.normalize_L2(query_embedding)
distances, indices = index.search(query_embedding, k=1)
print(f"\nЗапрос: {query}")
print(f"→ {documents[indices[0][0]]}")Чем больше документов, тем интереснее поиск. Расширьте список:
documents = [
"Python — язык программирования общего назначения",
"Питон — это змея из семейства удавов",
"Django — веб-фреймворк на Python для быстрой разработки",
"Flask — микрофреймворк для создания веб-приложений",
"FastAPI — современный фреймворк для создания API",
"NumPy — библиотека для научных вычислений",
"Pandas — инструмент для анализа данных",
"Matplotlib — библиотека для визуализации данных",
"Scikit-learn — машинное обучение на Python",
"TensorFlow — фреймворк для глубокого обучения"
]
# Пересоздайте эмбеддинги и индекс с новыми документами
embeddings = model.encode(documents)
# ... остальной кодТеперь попробуйте запросы:
ModuleNotFoundError: No module named 'sentence_transformers'Решение:
pip install sentence-transformersModuleNotFoundError: No module named 'faiss'Решение:
pip install faiss-cpuНормально. При первой загрузке модель скачивается (~100 МБ). Последующие запуски будут быстрыми.
Возможные причины:
Давайте напишем простой поиск по ключевым словам и сравним:
def keyword_search(query, documents, k=2):
"""Поиск по вхождению слов."""
query_words = set(query.lower().split())
scores = []
for i, doc in enumerate(documents):
doc_words = set(doc.lower().split())
# Количество общих слов
overlap = len(query_words & doc_words)
scores.append((i, overlap))
# Сортировка по убыванию
scores.sort(key=lambda x: x[1], reverse=True)
return scores[:k]
# Сравнение
query = "веб-фреймворк Python"
print("Keyword поиск:")
for idx, score in keyword_search(query, documents):
print(f" [{score}] {documents[idx]}")
print("\nВекторный поиск:")
query_embedding = model.encode([query])
faiss.normalize_L2(query_embedding)
distances, indices = index.search(query_embedding, k=2)
for idx, score in zip(indices[0], distances[0]):
print(f" [{score:.3f}] {documents[idx]}")Вы увидите разницу:
sentence-transformers и faiss-cpuТеперь вы видели, как работает векторный поиск в действии. В следующих темах вы узнаете:
# ❌ НЕЛЬЗЯ
model1 = SentenceTransformer('all-MiniLM-L6-v2')
model2 = SentenceTransformer('all-mpnet-base-v2')
emb1 = model1.encode("текст")
emb2 = model2.encode("текст")
# Эти векторы несовместимы!Правило: Используйте одну модель для всех эмбеддингов в проекте.
# ❌ Без нормализации
index = faiss.IndexFlatIP(dimension)
index.add(embeddings) # Неправильные результаты!
# ✅ С нормализацией
faiss.normalize_L2(embeddings)
index.add(embeddings)# ❌
query_embedding = model.encode([query])
distances, indices = index.search(query_embedding, k=2)
# ✅
query_embedding = model.encode([query])
faiss.normalize_L2(query_embedding) # Важно!
distances, indices = index.search(query_embedding, k=2)my_search.py с 10+ документами на вашу тему (работа, хобби, учёба)Готовы к следующей теме? Открывайте first_embeddings — узнаете, как работают эмбеддинги изнутри!
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.