244 lines
7.5 KiB
Markdown
244 lines
7.5 KiB
Markdown
|
|
# 🔍 Система поиска 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 # Хранение и поиск
|
|||
|
|
└── 🔍 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
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Алгоритм поиска
|
|||
|
|
|
|||
|
|
```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 раза
|
|||
|
|
|
|||
|
|
## 🔄 Миграция и обновления
|
|||
|
|
|
|||
|
|
### Переиндексация
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# Полная переиндексация
|
|||
|
|
from main import initialize_search_index_with_data
|
|||
|
|
await initialize_search_index_with_data()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Обновление модели
|
|||
|
|
|
|||
|
|
1. Остановить сервис
|
|||
|
|
2. Обновить `sentence-transformers`
|
|||
|
|
3. Изменить модель в `MuveraWrapper.__init__()`
|
|||
|
|
4. Запустить переиндексацию
|
|||
|
|
|
|||
|
|
## 🔗 Связанные документы
|
|||
|
|
|
|||
|
|
- [API Documentation](api.md) - GraphQL эндпоинты
|
|||
|
|
- [Testing](testing.md) - Тестирование поиска
|
|||
|
|
- [Performance](performance.md) - Оптимизация производительности
|