mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-26 00:46:22 +02:00
745 lines
48 KiB
Markdown
745 lines
48 KiB
Markdown
---
|
||
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)
|