mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-26 00:46:22 +02:00
Structure the tech specs directory (#836)
Tech spec some subdirectories for different languages
This commit is contained in:
parent
48da6c5f8b
commit
e7efb673ef
423 changed files with 0 additions and 0 deletions
745
docs/tech-specs/ru/graphrag-performance-optimization.ru.md
Normal file
745
docs/tech-specs/ru/graphrag-performance-optimization.ru.md
Normal file
|
|
@ -0,0 +1,745 @@
|
|||
---
|
||||
layout: default
|
||||
title: "Техническая спецификация оптимизации производительности GraphRAG"
|
||||
parent: "Russian (Beta)"
|
||||
---
|
||||
|
||||
# Техническая спецификация оптимизации производительности GraphRAG
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## Обзор
|
||||
|
||||
Эта спецификация описывает комплексные оптимизации производительности для алгоритма GraphRAG (Graph Retrieval-Augmented Generation) в TrustGraph. Текущая реализация страдает от значительных узких мест в производительности, которые ограничивают масштабируемость и время отклика. Эта спецификация охватывает четыре основные области оптимизации:
|
||||
|
||||
1. **Оптимизация обхода графа**: Исключение неэффективных рекурсивных запросов к базе данных и реализация пакетной обработки графа.
|
||||
2. **Оптимизация разрешения меток**: Замена последовательной загрузки меток параллельными/пакетными операциями.
|
||||
3. **Улучшение стратегии кэширования**: Реализация интеллектуального кэширования с вытеснением по принципу LRU и предварительной загрузкой.
|
||||
4. **Оптимизация запросов**: Добавление мемоизации результатов и кэширования вложений для повышения скорости отклика.
|
||||
|
||||
## Цели
|
||||
|
||||
**Сокращение объема запросов к базе данных**: Достижение снижения общего количества запросов к базе данных на 50-80% за счет пакетной обработки и кэширования.
|
||||
**Улучшение времени отклика**: Целевое увеличение скорости построения подграфов в 3-5 раз и ускорение разрешения меток в 2-3 раза.
|
||||
**Повышение масштабируемости**: Поддержка более крупных графов знаний с улучшением управления памятью.
|
||||
**Сохранение точности**: Сохранение существующей функциональности GraphRAG и качества результатов.
|
||||
**Обеспечение параллельности**: Улучшение возможностей параллельной обработки для нескольких одновременных запросов.
|
||||
<<<<<<< HEAD
|
||||
**Уменьшение объема памяти**: Реализация эффективных структур данных и управления памятью.
|
||||
=======
|
||||
**Уменьшение объема используемой памяти**: Реализация эффективных структур данных и управления памятью.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**Добавление возможностей мониторинга**: Включение показателей производительности и возможностей мониторинга.
|
||||
**Обеспечение надежности**: Добавление надлежащей обработки ошибок и механизмов таймаута.
|
||||
|
||||
## Предыстория
|
||||
|
||||
Текущая реализация GraphRAG в `trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py` имеет несколько критических проблем с производительностью, которые серьезно влияют на масштабируемость системы:
|
||||
|
||||
### Текущие проблемы с производительностью
|
||||
|
||||
**1. Неэффективный обход графа (функция `follow_edges`, строки 79-127)**
|
||||
Выполняет 3 отдельных запроса к базе данных для каждой сущности на каждом уровне глубины.
|
||||
Шаблон запроса: запросы на основе субъекта, запросы на основе предиката и запросы на основе объекта для каждой сущности.
|
||||
Без пакетной обработки: Каждый запрос обрабатывает только одну сущность за раз.
|
||||
Без обнаружения циклов: Может повторно посещать одни и те же узлы несколько раз.
|
||||
Рекурсивная реализация без мемоизации приводит к экспоненциальной сложности.
|
||||
Временная сложность: O(entities × max_path_length × triple_limit³)
|
||||
|
||||
**2. Последовательное разрешение меток (функция `get_labelgraph`, строки 144-171)**
|
||||
Обрабатывает каждый компонент тройки (субъект, предикат, объект) последовательно.
|
||||
Каждый вызов `maybe_label` потенциально вызывает запрос к базе данных.
|
||||
Без параллельного выполнения или пакетной обработки запросов меток.
|
||||
<<<<<<< HEAD
|
||||
В результате получается до 3 × subgraph_size отдельных вызовов базы данных.
|
||||
=======
|
||||
Приводит до 3 × subgraph_size отдельных вызовов базы данных.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
**3. Примитивная стратегия кэширования (функция `maybe_label`, строки 62-77)**
|
||||
Простой кэш в виде словаря без ограничений размера или TTL.
|
||||
Отсутствие политики вытеснения кэша приводит к неограниченному росту памяти.
|
||||
Пропуски кэша вызывают отдельные запросы к базе данных.
|
||||
Без предварительной загрузки или интеллектуального подогрева кэша.
|
||||
|
||||
**4. Субоптимальные шаблоны запросов**
|
||||
Запросы на сравнение векторного сходства сущностей не кэшируются между похожими запросами.
|
||||
Без мемоизации результатов для повторяющихся шаблонов запросов.
|
||||
<<<<<<< HEAD
|
||||
Отсутствие оптимизации запросов для распространенных шаблонов доступа.
|
||||
=======
|
||||
Отсутствует оптимизация запросов для распространенных шаблонов доступа.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
**5. Критические проблемы с жизненным циклом объектов (`rag.py:96-102`)**
|
||||
**Объект GraphRag создается для каждого запроса**: Новый экземпляр создается для каждого запроса, что приводит к потере всех преимуществ кэша.
|
||||
**Объект запроса имеет очень короткий срок службы**: Создается и уничтожается в течение выполнения одного запроса (строки 201-207).
|
||||
**Кэш меток сбрасывается для каждого запроса**: Подогрев кэша и накопленные знания теряются между запросами.
|
||||
<<<<<<< HEAD
|
||||
**Накладные расходы на повторное создание клиента**: Клиенты базы данных потенциально повторно устанавливаются для каждого запроса.
|
||||
**Без оптимизации между запросами**: Невозможно извлечь выгоду из шаблонов запросов или совместного использования результатов.
|
||||
=======
|
||||
**Накладные расходы на повторное создание клиента**: Клиенты базы данных потенциально пересоздаются для каждого запроса.
|
||||
**Отсутствие оптимизации между запросами**: Невозможно извлечь выгоду из шаблонов запросов или обмена результатами.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### Анализ влияния на производительность
|
||||
|
||||
Текущий наихудший сценарий для типичного запроса:
|
||||
**Извлечение сущности**: 1 запрос на сравнение векторного сходства.
|
||||
**Обход графа**: entities × max_path_length × 3 × triple_limit запросов.
|
||||
**Разрешение меток**: subgraph_size × 3 отдельных запросов на разрешение меток.
|
||||
|
||||
<<<<<<< HEAD
|
||||
Для параметров по умолчанию (50 сущностей, длина пути 2, ограничение в 30 тройки, размер подграфа 150):
|
||||
**Минимальное количество запросов**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9451 запрос к базе данных**
|
||||
**Время отклика**: 15-30 секунд для графов среднего размера
|
||||
**Использование памяти**: Неограниваемый рост кэша со временем
|
||||
=======
|
||||
Для параметров по умолчанию (50 сущностей, длина пути 2, ограничение в 30 троек, размер подграфа 150):
|
||||
**Минимальное количество запросов**: 1 + (50 × 2 × 3 × 30) + (150 × 3) = **9451 запрос к базе данных**
|
||||
**Время отклика**: 15-30 секунд для графов среднего размера
|
||||
**Использование памяти**: Неограниченный рост кэша со временем
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**Эффективность кэша**: 0% - кэши сбрасываются при каждом запросе
|
||||
**Накладные расходы на создание объектов**: Объекты GraphRag + Query создаются/удаляются для каждого запроса
|
||||
|
||||
Эта спецификация решает эти проблемы, реализуя пакетные запросы, интеллектуальное кэширование и параллельную обработку. Оптимизируя шаблоны запросов и доступ к данным, TrustGraph может:
|
||||
Поддерживать графы знаний корпоративного уровня с миллионами сущностей
|
||||
Обеспечивать время отклика менее 1 секунды для типичных запросов
|
||||
Обрабатывать сотни одновременных запросов GraphRAG
|
||||
<<<<<<< HEAD
|
||||
Эффективно масштабироваться в зависимости от размера и сложности графа
|
||||
=======
|
||||
Эффективно масштабироваться с увеличением размера и сложности графа
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## Технический дизайн
|
||||
|
||||
### Архитектура
|
||||
|
||||
Оптимизация производительности GraphRAG требует следующих технических компонентов:
|
||||
|
||||
#### 1. **Архитектурная реорганизация жизненного цикла объектов**
|
||||
<<<<<<< HEAD
|
||||
**Сделать GraphRag долгоживущим**: Переместить экземпляр GraphRag на уровень Processor для сохранения между запросами
|
||||
**Сохранять кэши**: Поддерживать кэш меток, кэш вложений и кэш результатов запросов между запросами
|
||||
**Оптимизировать объект Query**: Переработать Query как легковесный контекст выполнения, а не контейнер данных
|
||||
**Сохранять подключения к базе данных**: Поддерживать подключения к базе данных между запросами
|
||||
=======
|
||||
**Сделать GraphRag долгоживущим**: Переместить экземпляр GraphRag на уровень Processor для сохранения данных между запросами
|
||||
**Сохранять кэши**: Поддерживать кэш меток, кэш вложений и кэш результатов запросов между запросами
|
||||
**Оптимизировать объект Query**: Переработать Query как легковесный контекст выполнения, а не контейнер данных
|
||||
**Сохранять соединения с базой данных**: Поддерживать соединения с базой данных между запросами
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/rag.py` (изменен)
|
||||
|
||||
#### 2. **Оптимизированный движок обхода графа**
|
||||
<<<<<<< HEAD
|
||||
Заменить рекурсивную `follow_edges` на итеративный поиск в ширину
|
||||
Реализовать пакетную обработку сущностей на каждом уровне обхода
|
||||
Добавить обнаружение циклов с помощью отслеживания посещенных узлов
|
||||
=======
|
||||
Заменить рекурсивную функцию `follow_edges` на итеративный поиск в ширину
|
||||
Реализовать пакетную обработку сущностей на каждом уровне обхода
|
||||
Добавить обнаружение циклов с использованием отслеживания посещенных узлов
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
Включить раннее завершение при достижении лимитов
|
||||
|
||||
Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/optimized_traversal.py`
|
||||
|
||||
#### 3. **Параллельная система разрешения меток**
|
||||
Пакетные запросы меток для нескольких сущностей одновременно
|
||||
Реализовать шаблоны async/await для параллельного доступа к базе данных
|
||||
Добавить интеллектуальную предварительную загрузку для распространенных шаблонов меток
|
||||
Включить стратегии предварительного заполнения кэша меток
|
||||
|
||||
Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/label_resolver.py`
|
||||
|
||||
#### 4. **Консервативный слой кэширования меток**
|
||||
Кэш LRU с коротким TTL только для меток (5 минут) для баланса между производительностью и согласованностью
|
||||
<<<<<<< HEAD
|
||||
Мониторинг метрик кэша и коэффициента попадания
|
||||
**Без кэширования вложений**: Уже кэшируются для каждого запроса, нет преимуществ для межзапросных данных
|
||||
=======
|
||||
Мониторинг метрик кэша и коэффициента попаданий
|
||||
**Без кэширования вложений**: Уже кэшируются для каждого запроса, нет преимуществ для межзапросных операций
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**Без кэширования результатов запросов**: Из-за проблем согласованности изменений графа
|
||||
|
||||
Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/cache_manager.py`
|
||||
|
||||
#### 5. **Фреймворк оптимизации запросов**
|
||||
Анализ шаблонов запросов и предложения по оптимизации
|
||||
Пакетный координатор запросов для доступа к базе данных
|
||||
<<<<<<< HEAD
|
||||
Управление пулами соединений и временем ожидания запросов
|
||||
=======
|
||||
Управление пулом соединений и временем ожидания запросов
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
Мониторинг производительности и сбор метрик
|
||||
|
||||
Модуль: `trustgraph-flow/trustgraph/retrieval/graph_rag/query_optimizer.py`
|
||||
|
||||
### Модели данных
|
||||
|
||||
#### Оптимизированное состояние обхода графа
|
||||
|
||||
Движок обхода поддерживает состояние для предотвращения избыточных операций:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TraversalState:
|
||||
visited_entities: Set[str]
|
||||
current_level_entities: Set[str]
|
||||
next_level_entities: Set[str]
|
||||
subgraph: Set[Tuple[str, str, str]]
|
||||
depth: int
|
||||
query_batch: List[TripleQuery]
|
||||
```
|
||||
|
||||
Этот подход позволяет:
|
||||
Эффективное обнаружение циклов за счет отслеживания посещенных сущностей.
|
||||
Подготовку запросов пакетами на каждом уровне обхода.
|
||||
Экономичное использование памяти для управления состоянием.
|
||||
Раннее завершение, когда достигнуты ограничения по размеру.
|
||||
|
||||
#### Улучшенная структура кэша
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class CacheEntry:
|
||||
value: Any
|
||||
timestamp: float
|
||||
access_count: int
|
||||
ttl: Optional[float]
|
||||
|
||||
class CacheManager:
|
||||
label_cache: LRUCache[str, CacheEntry]
|
||||
embedding_cache: LRUCache[str, CacheEntry]
|
||||
query_result_cache: LRUCache[str, CacheEntry]
|
||||
cache_stats: CacheStatistics
|
||||
```
|
||||
|
||||
#### Структуры пакетных запросов
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class BatchTripleQuery:
|
||||
entities: List[str]
|
||||
query_type: QueryType # SUBJECT, PREDICATE, OBJECT
|
||||
limit_per_entity: int
|
||||
|
||||
@dataclass
|
||||
class BatchLabelQuery:
|
||||
entities: List[str]
|
||||
predicate: str = LABEL
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
#### Новые API:
|
||||
|
||||
**API GraphTraversal**
|
||||
```python
|
||||
async def optimized_follow_edges_batch(
|
||||
entities: List[str],
|
||||
max_depth: int,
|
||||
triple_limit: int,
|
||||
max_subgraph_size: int
|
||||
) -> Set[Tuple[str, str, str]]
|
||||
```
|
||||
|
||||
**API для разрешения меток пакетов**
|
||||
```python
|
||||
async def resolve_labels_batch(
|
||||
entities: List[str],
|
||||
cache_manager: CacheManager
|
||||
) -> Dict[str, str]
|
||||
```
|
||||
|
||||
**API управления кэшем**
|
||||
```python
|
||||
class CacheManager:
|
||||
async def get_or_fetch_label(self, entity: str) -> str
|
||||
async def get_or_fetch_embeddings(self, query: str) -> List[float]
|
||||
async def cache_query_result(self, query_hash: str, result: Any, ttl: int)
|
||||
def get_cache_statistics(self) -> CacheStatistics
|
||||
```
|
||||
|
||||
#### Измененные API:
|
||||
|
||||
**GraphRag.query()** - Улучшено с оптимизациями производительности:
|
||||
Добавлен параметр cache_manager для управления кэшем.
|
||||
Добавлено возвращаемое значение performance_metrics.
|
||||
Добавлен параметр query_timeout для повышения надежности.
|
||||
|
||||
**Класс Query** - Рефакторинг для пакетной обработки:
|
||||
Замена обработки отдельных сущностей на пакетные операции.
|
||||
Добавлены асинхронные контекстные менеджеры для очистки ресурсов.
|
||||
Добавлены обратные вызовы для отслеживания прогресса длительных операций.
|
||||
|
||||
### Детали реализации
|
||||
|
||||
#### Фаза 0: Критическая архитектурная реорганизация жизненного цикла
|
||||
|
||||
**Текущая проблемная реализация:**
|
||||
```python
|
||||
# INEFFICIENT: GraphRag recreated every request
|
||||
class Processor(FlowProcessor):
|
||||
async def on_request(self, msg, consumer, flow):
|
||||
# PROBLEM: New GraphRag instance per request!
|
||||
self.rag = GraphRag(
|
||||
embeddings_client = flow("embeddings-request"),
|
||||
graph_embeddings_client = flow("graph-embeddings-request"),
|
||||
triples_client = flow("triples-request"),
|
||||
prompt_client = flow("prompt-request"),
|
||||
verbose=True,
|
||||
)
|
||||
# Cache starts empty every time - no benefit from previous requests
|
||||
response = await self.rag.query(...)
|
||||
|
||||
# VERY SHORT-LIVED: Query object created/destroyed per request
|
||||
class GraphRag:
|
||||
async def query(self, query, user="trustgraph", collection="default", ...):
|
||||
q = Query(rag=self, user=user, collection=collection, ...) # Created
|
||||
kg = await q.get_labelgraph(query) # Used briefly
|
||||
# q automatically destroyed when function exits
|
||||
```
|
||||
|
||||
**Оптимизированная архитектура с длительным сроком службы:**
|
||||
```python
|
||||
class Processor(FlowProcessor):
|
||||
def __init__(self, **params):
|
||||
super().__init__(**params)
|
||||
self.rag_instance = None # Will be initialized once
|
||||
self.client_connections = {}
|
||||
|
||||
async def initialize_rag(self, flow):
|
||||
"""Initialize GraphRag once, reuse for all requests"""
|
||||
if self.rag_instance is None:
|
||||
self.rag_instance = LongLivedGraphRag(
|
||||
embeddings_client=flow("embeddings-request"),
|
||||
graph_embeddings_client=flow("graph-embeddings-request"),
|
||||
triples_client=flow("triples-request"),
|
||||
prompt_client=flow("prompt-request"),
|
||||
verbose=True,
|
||||
)
|
||||
return self.rag_instance
|
||||
|
||||
async def on_request(self, msg, consumer, flow):
|
||||
# REUSE the same GraphRag instance - caches persist!
|
||||
rag = await self.initialize_rag(flow)
|
||||
|
||||
# Query object becomes lightweight execution context
|
||||
response = await rag.query_with_context(
|
||||
query=v.query,
|
||||
execution_context=QueryContext(
|
||||
user=v.user,
|
||||
collection=v.collection,
|
||||
entity_limit=entity_limit,
|
||||
# ... other params
|
||||
)
|
||||
)
|
||||
|
||||
class LongLivedGraphRag:
|
||||
def __init__(self, ...):
|
||||
# CONSERVATIVE caches - balance performance vs consistency
|
||||
self.label_cache = LRUCacheWithTTL(max_size=5000, ttl=300) # 5min TTL for freshness
|
||||
# Note: No embedding cache - already cached per-query, no cross-query benefit
|
||||
# Note: No query result cache due to consistency concerns
|
||||
self.performance_metrics = PerformanceTracker()
|
||||
|
||||
async def query_with_context(self, query: str, context: QueryContext):
|
||||
# Use lightweight QueryExecutor instead of heavyweight Query object
|
||||
executor = QueryExecutor(self, context) # Minimal object
|
||||
return await executor.execute(query)
|
||||
|
||||
@dataclass
|
||||
class QueryContext:
|
||||
"""Lightweight execution context - no heavy operations"""
|
||||
user: str
|
||||
collection: str
|
||||
entity_limit: int
|
||||
triple_limit: int
|
||||
max_subgraph_size: int
|
||||
max_path_length: int
|
||||
|
||||
class QueryExecutor:
|
||||
"""Lightweight execution context - replaces old Query class"""
|
||||
def __init__(self, rag: LongLivedGraphRag, context: QueryContext):
|
||||
self.rag = rag
|
||||
self.context = context
|
||||
# No heavy initialization - just references
|
||||
|
||||
async def execute(self, query: str):
|
||||
# All heavy lifting uses persistent rag caches
|
||||
return await self.rag.execute_optimized_query(query, self.context)
|
||||
```
|
||||
|
||||
Это архитектурное изменение обеспечивает:
|
||||
**Сокращение количества запросов к базе данных на 10-20%** для графов с общими связями (по сравнению с текущими 0%)
|
||||
**Устранение накладных расходов на создание объектов** для каждого запроса
|
||||
**Постоянное использование пула соединений и повторное использование клиентов**
|
||||
**Оптимизация между запросами** в пределах временных окон TTL кэша
|
||||
|
||||
**Важное ограничение согласованности кэша:**
|
||||
Долгосрочное кэширование создает риск устаревания данных, когда сущности/метки удаляются или изменяются в базовом графе. Кэш LRU с TTL обеспечивает баланс между повышением производительности и актуальностью данных, но не может обнаруживать изменения в графе в режиме реального времени.
|
||||
|
||||
#### Фаза 1: Оптимизация обхода графа
|
||||
|
||||
**Проблемы текущей реализации:**
|
||||
```python
|
||||
# INEFFICIENT: 3 queries per entity per level
|
||||
async def follow_edges(self, ent, subgraph, path_length):
|
||||
# Query 1: s=ent, p=None, o=None
|
||||
res = await self.rag.triples_client.query(s=ent, p=None, o=None, limit=self.triple_limit)
|
||||
# Query 2: s=None, p=ent, o=None
|
||||
res = await self.rag.triples_client.query(s=None, p=ent, o=None, limit=self.triple_limit)
|
||||
# Query 3: s=None, p=None, o=ent
|
||||
res = await self.rag.triples_client.query(s=None, p=None, o=ent, limit=self.triple_limit)
|
||||
```
|
||||
|
||||
**Оптимизированная реализация:**
|
||||
```python
|
||||
async def optimized_traversal(self, entities: List[str], max_depth: int) -> Set[Triple]:
|
||||
visited = set()
|
||||
current_level = set(entities)
|
||||
subgraph = set()
|
||||
|
||||
for depth in range(max_depth):
|
||||
if not current_level or len(subgraph) >= self.max_subgraph_size:
|
||||
break
|
||||
|
||||
# Batch all queries for current level
|
||||
batch_queries = []
|
||||
for entity in current_level:
|
||||
if entity not in visited:
|
||||
batch_queries.extend([
|
||||
TripleQuery(s=entity, p=None, o=None),
|
||||
TripleQuery(s=None, p=entity, o=None),
|
||||
TripleQuery(s=None, p=None, o=entity)
|
||||
])
|
||||
|
||||
# Execute all queries concurrently
|
||||
results = await self.execute_batch_queries(batch_queries)
|
||||
|
||||
# Process results and prepare next level
|
||||
next_level = set()
|
||||
for result in results:
|
||||
subgraph.update(result.triples)
|
||||
next_level.update(result.new_entities)
|
||||
|
||||
visited.update(current_level)
|
||||
current_level = next_level - visited
|
||||
|
||||
return subgraph
|
||||
```
|
||||
|
||||
#### Фаза 2: Параллельное разрешение меток
|
||||
|
||||
**Текущая последовательная реализация:**
|
||||
```python
|
||||
# INEFFICIENT: Sequential processing
|
||||
for edge in subgraph:
|
||||
s = await self.maybe_label(edge[0]) # Individual query
|
||||
p = await self.maybe_label(edge[1]) # Individual query
|
||||
o = await self.maybe_label(edge[2]) # Individual query
|
||||
```
|
||||
|
||||
**Оптимизированная параллельная реализация:**
|
||||
```python
|
||||
async def resolve_labels_parallel(self, subgraph: List[Triple]) -> List[Triple]:
|
||||
# Collect all unique entities needing labels
|
||||
entities_to_resolve = set()
|
||||
for s, p, o in subgraph:
|
||||
entities_to_resolve.update([s, p, o])
|
||||
|
||||
# Remove already cached entities
|
||||
uncached_entities = [e for e in entities_to_resolve if e not in self.label_cache]
|
||||
|
||||
# Batch query for all uncached labels
|
||||
if uncached_entities:
|
||||
label_results = await self.batch_label_query(uncached_entities)
|
||||
self.label_cache.update(label_results)
|
||||
|
||||
# Apply labels to subgraph
|
||||
return [
|
||||
(self.label_cache.get(s, s), self.label_cache.get(p, p), self.label_cache.get(o, o))
|
||||
for s, p, o in subgraph
|
||||
]
|
||||
```
|
||||
|
||||
#### Фаза 3: Продвинутая стратегия кэширования
|
||||
|
||||
**Кэш LRU с TTL:**
|
||||
```python
|
||||
class LRUCacheWithTTL:
|
||||
def __init__(self, max_size: int, default_ttl: int = 3600):
|
||||
self.cache = OrderedDict()
|
||||
self.max_size = max_size
|
||||
self.default_ttl = default_ttl
|
||||
self.access_times = {}
|
||||
|
||||
async def get(self, key: str) -> Optional[Any]:
|
||||
if key in self.cache:
|
||||
# Check TTL expiration
|
||||
if time.time() - self.access_times[key] > self.default_ttl:
|
||||
del self.cache[key]
|
||||
del self.access_times[key]
|
||||
return None
|
||||
|
||||
# Move to end (most recently used)
|
||||
self.cache.move_to_end(key)
|
||||
return self.cache[key]
|
||||
return None
|
||||
|
||||
async def put(self, key: str, value: Any):
|
||||
if key in self.cache:
|
||||
self.cache.move_to_end(key)
|
||||
else:
|
||||
if len(self.cache) >= self.max_size:
|
||||
# Remove least recently used
|
||||
oldest_key = next(iter(self.cache))
|
||||
del self.cache[oldest_key]
|
||||
del self.access_times[oldest_key]
|
||||
|
||||
self.cache[key] = value
|
||||
self.access_times[key] = time.time()
|
||||
```
|
||||
|
||||
#### Фаза 4: Оптимизация запросов и мониторинг
|
||||
|
||||
**Сбор показателей производительности:**
|
||||
```python
|
||||
@dataclass
|
||||
class PerformanceMetrics:
|
||||
total_queries: int
|
||||
cache_hits: int
|
||||
cache_misses: int
|
||||
avg_response_time: float
|
||||
subgraph_construction_time: float
|
||||
label_resolution_time: float
|
||||
total_entities_processed: int
|
||||
memory_usage_mb: float
|
||||
```
|
||||
|
||||
**Тайм-аут запроса и предохранитель:**
|
||||
```python
|
||||
async def execute_with_timeout(self, query_func, timeout: int = 30):
|
||||
try:
|
||||
return await asyncio.wait_for(query_func(), timeout=timeout)
|
||||
except asyncio.TimeoutError:
|
||||
logger.error(f"Query timeout after {timeout}s")
|
||||
raise GraphRagTimeoutError(f"Query exceeded timeout of {timeout}s")
|
||||
```
|
||||
|
||||
## Соображения по обеспечению согласованности кэша
|
||||
|
||||
**Компромиссы между актуальностью данных:**
|
||||
**Кэш меток (TTL 5 минут):** Риск предоставления устаревших меток сущностей (удаленных или переименованных).
|
||||
<<<<<<< HEAD
|
||||
**Отсутствие кэширования вложений:** Не требуется, так как вложения уже кэшируются для каждого запроса.
|
||||
=======
|
||||
**Отсутствие кэширования вложений:** Не требуется - вложения уже кэшируются для каждого запроса.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**Отсутствие кэширования результатов:** Предотвращает получение устаревших результатов подграфов из-за удаленных сущностей/связей.
|
||||
|
||||
**Стратегии смягчения:**
|
||||
**Консервативные значения TTL:** Баланс между приростом производительности (10-20%) и актуальностью данных.
|
||||
<<<<<<< HEAD
|
||||
**Хуки для аннулирования кэша:** Необязательная интеграция с событиями изменения графа.
|
||||
**Панели мониторинга:** Отслеживание показателей попадания в кэш по сравнению с инцидентами устаревания данных.
|
||||
**Настраиваемые политики кэширования:** Возможность тонкой настройки для каждого развертывания в зависимости от частоты изменений.
|
||||
|
||||
**Рекомендуемая конфигурация кэша в зависимости от частоты изменений графа:**
|
||||
**Высокая частота изменений (>100 изменений/час):** TTL=60 секунд, меньшие размеры кэша.
|
||||
**Средняя частота изменений (10-100 изменений/час):** TTL=300 секунд (по умолчанию).
|
||||
**Низкая частота изменений (<10 изменений/час):** TTL=600 секунд, большие размеры кэша.
|
||||
=======
|
||||
**Механизмы аннулирования кэша:** Необязательная интеграция с событиями изменения графа.
|
||||
**Информационные панели мониторинга:** Отслеживание показателей попадания в кэш по сравнению с инцидентами устаревания данных.
|
||||
**Настраиваемые политики кэширования:** Возможность тонкой настройки для каждого развертывания в зависимости от частоты изменений.
|
||||
|
||||
**Рекомендуемая конфигурация кэша в зависимости от скорости изменений графа:**
|
||||
**Высокая скорость изменений (>100 изменений/час):** TTL=60 секунд, меньшие размеры кэша.
|
||||
**Средняя скорость изменений (10-100 изменений/час):** TTL=300 секунд (по умолчанию).
|
||||
**Низкая скорость изменений (<10 изменений/час):** TTL=600 секунд, большие размеры кэша.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## Соображения безопасности
|
||||
|
||||
**Предотвращение внедрения запросов:**
|
||||
Проверка всех идентификаторов сущностей и параметров запроса.
|
||||
Использование параметризованных запросов для всех взаимодействий с базой данных.
|
||||
Реализация ограничений на сложность запросов для предотвращения атак типа "отказ в обслуживании" (DoS).
|
||||
|
||||
**Защита ресурсов:**
|
||||
Применение ограничений на максимальный размер подграфа.
|
||||
Реализация таймаутов запросов для предотвращения исчерпания ресурсов.
|
||||
Добавление мониторинга и ограничений использования памяти.
|
||||
|
||||
**Контроль доступа:**
|
||||
Поддержание существующей изоляции пользователей и коллекций.
|
||||
Добавление ведения журнала аудита для операций, влияющих на производительность.
|
||||
Реализация ограничения скорости для дорогостоящих операций.
|
||||
|
||||
## Соображения производительности
|
||||
|
||||
<<<<<<< HEAD
|
||||
### Ожидаемые улучшения производительности
|
||||
|
||||
**Сокращение количества запросов:**
|
||||
Сейчас: ~9000+ запросов для типичного запроса.
|
||||
Оптимизировано: ~50-100 пакетных запросов (снижение на 98%).
|
||||
=======
|
||||
### Ожидаемое повышение производительности
|
||||
|
||||
**Сокращение количества запросов:**
|
||||
Текущее: ~9000+ запросов для типичного запроса.
|
||||
Оптимизированное: ~50-100 пакетных запросов (снижение на 98%).
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
**Улучшение времени отклика:**
|
||||
Обход графа: 15-20 секунд → 3-5 секунд (в 4-5 раза быстрее).
|
||||
Разрешение меток: 8-12 секунд → 2-4 секунды (в 3 раза быстрее).
|
||||
Общий запрос: 25-35 секунд → 6-10 секунд (улучшение в 3-4 раза).
|
||||
|
||||
**Эффективность использования памяти:**
|
||||
Ограниченные размеры кэша предотвращают утечки памяти.
|
||||
Эффективные структуры данных уменьшают объем используемой памяти примерно на 40%.
|
||||
<<<<<<< HEAD
|
||||
Улучшен сбор мусора благодаря правильной очистке ресурсов.
|
||||
=======
|
||||
Улучшенная сборка мусора благодаря правильной очистке ресурсов.
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
**Реалистичные ожидания производительности:**
|
||||
**Кэш меток:** Уменьшение количества запросов на 10-20% для графов с общими связями.
|
||||
**Оптимизация пакетной обработки:** Уменьшение количества запросов на 50-80% (основная оптимизация).
|
||||
**Оптимизация времени жизни объектов:** Исключение накладных расходов на создание объектов для каждого запроса.
|
||||
**Общее улучшение:** Улучшение времени отклика в 3-4 раза, в основном за счет пакетной обработки.
|
||||
|
||||
**Улучшения масштабируемости:**
|
||||
Поддержка графов знаний в 3-5 раза большего размера (ограничено потребностями согласованности кэша).
|
||||
Увеличение количества одновременных запросов в 3-5 раза.
|
||||
Лучшее использование ресурсов благодаря повторному использованию соединений.
|
||||
|
||||
### Мониторинг производительности
|
||||
|
||||
**Метрики в реальном времени:**
|
||||
Время выполнения запросов по типу операции.
|
||||
Показатели попадания в кэш и его эффективность.
|
||||
Использование пула соединений с базой данных.
|
||||
Использование памяти и влияние сборки мусора.
|
||||
|
||||
**Бенчмаркинг производительности:**
|
||||
Автоматизированное регрессионное тестирование производительности
|
||||
Тестирование нагрузки с использованием реалистичных объемов данных
|
||||
Сравнительные тесты с текущей реализацией
|
||||
|
||||
## Стратегия тестирования
|
||||
|
||||
### Модульное тестирование
|
||||
Тестирование отдельных компонентов для обхода графа, кэширования и разрешения меток
|
||||
Эмуляция взаимодействия с базой данных для тестирования производительности
|
||||
Тестирование вытеснения из кэша и истечения срока действия TTL
|
||||
Обработка ошибок и сценарии таймаутов
|
||||
|
||||
### Интеграционное тестирование
|
||||
Комплексное тестирование запросов GraphRAG с оптимизациями
|
||||
Тестирование взаимодействия с базой данных с использованием реальных данных
|
||||
Обработка одновременных запросов и управление ресурсами
|
||||
Обнаружение утечек памяти и проверка очистки ресурсов
|
||||
|
||||
### Тестирование производительности
|
||||
Тестирование производительности по сравнению с текущей реализацией
|
||||
<<<<<<< HEAD
|
||||
Тестирование нагрузки с различными размерами и сложностью графов
|
||||
=======
|
||||
Тестирование нагрузки с графами различного размера и сложности
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
Стресс-тестирование для проверки лимитов памяти и соединений
|
||||
Регрессионное тестирование для проверки улучшений производительности
|
||||
|
||||
### Тестирование совместимости
|
||||
Проверка совместимости существующего API GraphRAG
|
||||
Тестирование с различными бэкендами графовых баз данных
|
||||
Проверка точности результатов по сравнению с текущей реализацией
|
||||
|
||||
## План реализации
|
||||
|
||||
### Прямой подход к реализации
|
||||
Поскольку API могут изменяться, реализуйте оптимизации напрямую без сложности миграции:
|
||||
|
||||
1. **Замените метод `follow_edges`**: Перепишите с использованием пакетного итеративного обхода
|
||||
2. **Оптимизируйте `get_labelgraph`**: Реализуйте параллельное разрешение меток
|
||||
3. **Добавьте долгоживущий GraphRag**: Измените Processor для поддержания постоянной инстанции
|
||||
<<<<<<< HEAD
|
||||
4. **Реализуйте кэширование меток**: Добавьте кэш LRU с TTL в класс GraphRag
|
||||
=======
|
||||
4. **Реализуйте кэширование меток**: Добавьте кэш LRU со сроком действия TTL в класс GraphRag
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
### Область изменений
|
||||
**Класс запроса**: Замените ~50 строк в `follow_edges`, добавьте ~30 строк для обработки пакетов
|
||||
**Класс GraphRag**: Добавьте слой кэширования (~40 строк)
|
||||
**Класс Processor**: Измените для использования постоянной инстанции GraphRag (~20 строк)
|
||||
<<<<<<< HEAD
|
||||
**Всего**: ~140 строк целенаправленных изменений, в основном в существующих классах
|
||||
=======
|
||||
**Всего**: ~140 строк изменений, в основном в существующих классах
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
|
||||
## Временная шкала
|
||||
|
||||
**Неделя 1: Основная реализация**
|
||||
Замените `follow_edges` пакетным итеративным обходом
|
||||
Реализуйте параллельное разрешение меток в `get_labelgraph`
|
||||
Добавьте долгоживущую инстанцию GraphRag в Processor
|
||||
Реализуйте слой кэширования меток
|
||||
|
||||
**Неделя 2: Тестирование и интеграция**
|
||||
Модульные тесты для новой логики обхода и кэширования
|
||||
Бенчмаркинг производительности по сравнению с текущей реализацией
|
||||
<<<<<<< HEAD
|
||||
Интеграционное тестирование с реальными данными графа
|
||||
=======
|
||||
Интеграционное тестирование с реальными графовыми данными
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
Проверка кода и оптимизация
|
||||
|
||||
**Неделя 3: Развертывание**
|
||||
Разверните оптимизированную реализацию
|
||||
Отслеживайте улучшения производительности
|
||||
<<<<<<< HEAD
|
||||
Тонкая настройка TTL кэша и размеров пакетов на основе реального использования
|
||||
|
||||
## Открытые вопросы
|
||||
|
||||
**Пул соединений с базой данных**: Следует ли нам реализовать собственный пул соединений или использовать существующий пул соединений от клиента базы данных?
|
||||
**Постоянство кэша**: Должны ли кэши меток и внедрений сохраняться после перезапуска службы?
|
||||
**Распределенное кэширование**: Для развернутых в нескольких экземплярах систем следует ли нам реализовать распределенное кэширование с использованием Redis/Memcached?
|
||||
**Формат результата запроса**: Следует ли нам оптимизировать внутреннее представление тройки для повышения эффективности использования памяти?
|
||||
=======
|
||||
Тонкая настройка срока действия TTL кэша и размеров пакетов на основе реального использования
|
||||
|
||||
## Открытые вопросы
|
||||
|
||||
**Пул соединений с базой данных**: Следует ли нам реализовывать собственный пул соединений или использовать существующий пул соединений от клиента базы данных?
|
||||
**Постоянство кэша**: Должны ли кэши меток и вложений сохраняться после перезапуска сервиса?
|
||||
**Распределенное кэширование**: Для развернутых в нескольких инстанциях систем следует ли реализовывать распределенное кэширование с использованием Redis/Memcached?
|
||||
**Формат результата запроса**: Следует ли оптимизировать внутреннее представление тройки для повышения эффективности использования памяти?
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
**Интеграция мониторинга**: Какие метрики следует предоставлять существующим системам мониторинга (Prometheus и т. д.)?
|
||||
|
||||
## Ссылки
|
||||
|
||||
<<<<<<< HEAD
|
||||
[Оригинальная реализация GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py)
|
||||
=======
|
||||
[Исходная реализация GraphRAG](trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py)
|
||||
>>>>>>> 82edf2d (New md files from RunPod)
|
||||
[Принципы архитектуры TrustGraph](architecture-principles.md)
|
||||
[Спецификация управления коллекциями](collection-management.md)
|
||||
Loading…
Add table
Add a link
Reference in a new issue