Files
core/docs/search-system.md
Untone 4489d25913
Some checks failed
Deploy on push / deploy (push) Failing after 1m34s
## [0.9.18] - 2025-01-09
### 🔍 Search System Redis Storage
- **💾 Redis-based vector index storage**: Переключились обратно на Redis для хранения векторного индекса
  - Заменили файловое хранение в `/dump` на Redis ключи для надежности
  - Исправлена проблема с правами доступа на `/dump` папку на сервере
  - Векторный индекс теперь сохраняется по ключам `search_index:{name}:data` и `search_index:{name}:metadata`
- **🛠️ Improved reliability**: Убрали зависимость от файловой системы для критичных данных
- ** Better performance**: Redis обеспечивает более быстрый доступ к индексу
- **🔧 Technical changes**:
  - Заменили `save_index_to_file()` на `save_index_to_redis()`
  - Заменили `load_index_from_file()` на `load_index_from_redis()`
  - Обновили автосохранение для использования Redis вместо файлов
  - Удалили неиспользуемые импорты (`gzip`, `pathlib`, `cast`)
2025-09-01 15:09:36 +03:00

312 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🔍 Система поиска Discours
## Обзор
Система поиска Discours использует **семантические эмбединги** для точного поиска по публикациям. Реализована на базе `SentenceTransformers` с поддержкой русского языка и FDE (Fast Document Encoding) для оптимизации.
## 🚀 Основные возможности
### **1. Семантический поиск**
- Понимание смысла запросов, а не только ключевых слов
- Поддержка русского и английского языков
- Векторное представление документов через SentenceTransformers
### **2. Оптимизированная индексация**
- Batch-обработка для больших объёмов данных
- Тихий режим для массовых операций
- FDE кодирование для сжатия векторов
### **3. Высокая производительность**
- Косинусное сходство для ранжирования
- Кеширование результатов
- Асинхронная обработка
## 📋 API
### GraphQL запросы
```graphql
# Поиск по публикациям
query SearchShouts($text: String!, $options: ShoutsOptions) {
load_shouts_search(text: $text, options: $options) {
id
title
body
topics {
title
}
}
}
# Поиск по авторам
query SearchAuthors($text: String!, $limit: Int, $offset: Int) {
load_authors_search(text: $text, limit: $limit, offset: $offset) {
id
name
email
}
}
```
### Параметры поиска
```python
options = {
"limit": 10, # Количество результатов
"offset": 0, # Смещение для пагинации
"filters": { # Дополнительные фильтры
"community": 1,
"status": "published"
}
}
```
## 🛠️ Техническая архитектура
### Компоненты системы
```
📦 Search System
├── 🧠 SentenceTransformer # Генерация эмбедингов
├── 🗜️ Muvera FDE # Сжатие векторов
├── 🗃️ MuveraWrapper # Хранение и поиск
├── 💾 File Persistence # Сохранение в /dump папку
└── 🔍 SearchService # API интерфейс
```
### Модель эмбедингов
**Основная модель**: `paraphrase-multilingual-MiniLM-L12-v2`
- Поддержка 50+ языков включая русский
- Размерность: 384D
- Fallback: `all-MiniLM-L6-v2`
### Процесс индексации
```python
# 1. Извлечение текста
doc_content = f"{title} {subtitle} {lead} {body}".strip()
# 2. Генерация эмбединга
embedding = encoder.encode(doc_content)
# 3. FDE кодирование
compressed = muvera.encode_fde(embedding, buckets=128, method="avg")
# 4. Сохранение в индекс
embeddings[doc_id] = compressed
# 5. Автосохранение в файл
await self.save_index_to_file("/dump")
```
### Алгоритм поиска
```python
# 1. Эмбединг запроса
query_embedding = encoder.encode(query_text)
query_fde = muvera.encode_fde(query_embedding, buckets=128, method="avg")
# 2. Косинусное сходство
for doc_id, doc_embedding in embeddings.items():
similarity = cosine_similarity(query_fde, doc_embedding)
results.append({"id": doc_id, "score": similarity})
# 3. Ранжирование
results.sort(key=lambda x: x["score"], reverse=True)
```
## ⚙️ Конфигурация
### Переменные окружения
```bash
# Поиск
MUVERA_INDEX_NAME=discours_search
SEARCH_MAX_BATCH_SIZE=100
SEARCH_PREFETCH_SIZE=200
SEARCH_CACHE_ENABLED=true
SEARCH_CACHE_TTL_SECONDS=600
```
### Настройки производительности
```python
# Batch размеры
SINGLE_DOC_THRESHOLD = 10 # Меньше = одиночная обработка
BATCH_SIZE = 32 # Размер batch для SentenceTransformers
FDE_BUCKETS = 128 # Количество bucket для сжатия
# Logging
SILENT_BATCH_MODE = True # Тихий режим для batch операций
DEBUG_SINGLE_DOCS = True # Подробные логи для одиночных документов
```
## 🔧 Использование
### Индексация новых документов
```python
from services.search import search_service
# Одиночный документ
search_service.index(shout)
# Batch индексация (тихий режим)
await search_service.bulk_index(shouts_list)
```
### Поиск
```python
# Поиск публикаций
results = await search_service.search("машинное обучение", limit=10, offset=0)
# Поиск авторов
authors = await search_service.search_authors("Иван Петров", limit=5)
```
### Проверка статуса
```python
# Информация о сервисе
info = await search_service.info()
# Статус индекса
status = await search_service.check_index_status()
# Проверка документов
verification = await search_service.verify_docs(["1", "2", "3"])
```
## 🐛 Отладка
### Логирование
```python
# Включить debug логи
import logging
logging.getLogger("services.search").setLevel(logging.DEBUG)
# Проверить загрузку модели
logger.info("🔍 SentenceTransformer model loaded successfully")
```
### Диагностика
```python
# Проверить количество проиндексированных документов
info = await search_service.info()
print(f"Documents: {info['muvera_info']['documents_count']}")
# Найти отсутствующие документы
missing = await search_service.verify_docs(expected_doc_ids)
print(f"Missing: {missing['missing']}")
```
## 📈 Метрики производительности
### Типичные показатели
```
📊 Производительность поиска:
├── Поиск по 1000 документов: ~50ms
├── Индексация 1 документа: ~100ms
├── Batch индексация 100 документов: ~2s
└── Память на 1000 документов: ~50MB
```
### Оптимизация
1. **Batch обработка** - для массовых операций используйте `bulk_index()`
2. **Тихий режим** - отключает детальное логирование
3. **Кеширование** - результаты поиска кешируются в Redis
4. **FDE сжатие** - уменьшает размер векторов в 2-3 раза
## 💾 Персистентность и восстановление
### Автоматическое сохранение в Redis
Система автоматически сохраняет индекс в Redis после каждой успешной индексации:
```python
# Автосохранение после индексации
if indexed_count > 0:
await self.save_index_to_redis()
logger.debug("💾 Индекс автоматически сохранен в Redis")
```
### Структура Redis ключей
```
Redis:
├── search_index:discours_search:data # Основной индекс (pickle)
└── search_index:discours_search:metadata # Метаданные (JSON)
```
### Восстановление при запуске
При запуске сервиса система автоматически восстанавливает индекс из Redis:
```python
# В initialize_search_index()
await search_service.async_init() # Восстанавливает из Redis
```
## 🆕 Преимущества Redis хранения
### По сравнению с файлами/БД
- **⚡ Скорость**: Мгновенный доступ к векторному индексу
- **🔄 Надежность**: Нет проблем с правами доступа к файловой системе
- **💾 Эффективность**: Pickle сериализация для быстрого сохранения/загрузки
- **🔒 Целостность**: Атомарные операции записи в Redis
- **📊 Метаданные**: Отдельный JSON ключ для быстрого доступа к статистике
### Производительность
```
📊 Сравнение методов хранения:
├── Redis: ~50MB RAM, мгновенное восстановление ✅
├── БД: ~75MB RAM, медленное восстановление
└── Файл: ~25MB RAM, проблемы с правами ❌
```
## 🔄 Миграция и обновления
### Переиндексация
```python
# Полная переиндексация
from main import initialize_search_index_with_data
await initialize_search_index_with_data()
```
### Обновление модели
1. Остановить сервис
2. Обновить `sentence-transformers`
3. Изменить модель в `MuveraWrapper.__init__()`
4. Запустить переиндексацию
### Резервное копирование
```bash
# Создание бэкапа Redis ключей
redis-cli --rdb backup.rdb
# Или экспорт конкретных ключей
redis-cli GET "search_index:discours_search:data" > backup_data.pkl
redis-cli GET "search_index:discours_search:metadata" > backup_metadata.json
# Восстановление из бэкапа
redis-cli SET "search_index:discours_search:data" < backup_data.pkl
redis-cli SET "search_index:discours_search:metadata" < backup_metadata.json
```
## 🔗 Связанные документы
- [API Documentation](api.md) - GraphQL эндпоинты
- [Testing](testing.md) - Тестирование поиска
- [Performance](performance.md) - Оптимизация производительности