mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-25 08:26:21 +02:00
Native CLI i18n: The TrustGraph CLI has built-in translation support that dynamically loads language strings. You can test and use different languages by simply passing the --lang flag (e.g., --lang es for Spanish, --lang ru for Russian) or by configuring your environment's LANG variable. Automated Docs Translations: This PR introduces autonomously translated Markdown documentation into several target languages, including Spanish, Swahili, Portuguese, Turkish, Hindi, Hebrew, Arabic, Simplified Chinese, and Russian.
780 lines
42 KiB
Markdown
780 lines
42 KiB
Markdown
---
|
||
layout: default
|
||
title: "Техническое описание: Поддержка многопользовательской среды"
|
||
parent: "Russian (Beta)"
|
||
---
|
||
|
||
# Техническое описание: Поддержка многопользовательской среды
|
||
|
||
> **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.
|
||
|
||
## Обзор
|
||
|
||
Обеспечьте поддержку многопользовательской среды, устранив несоответствия в именах параметров, которые препятствуют настройке очередей, и добавив параметризацию пространства ключей Cassandra.
|
||
|
||
## Контекст архитектуры
|
||
|
||
### Разрешение очередей на основе потоков
|
||
|
||
Система TrustGraph использует **архитектуру на основе потоков** для динамического разрешения очередей, что изначально поддерживает многопользовательскую среду:
|
||
|
||
**Определения потоков** хранятся в Cassandra и указывают имена очередей через определения интерфейсов.
|
||
**Имена очередей используют шаблоны** с переменными `{id}`, которые заменяются идентификаторами экземпляров потоков.
|
||
**Сервисы динамически разрешают очереди**, получая конфигурации потоков в момент запроса.
|
||
**Каждый пользователь может иметь уникальные потоки** с разными именами очередей, что обеспечивает изоляцию.
|
||
|
||
Пример определения интерфейса потока:
|
||
```json
|
||
{
|
||
"interfaces": {
|
||
"triples-store": "persistent://tg/flow/triples-store:{id}",
|
||
"graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}"
|
||
}
|
||
}
|
||
```
|
||
|
||
Когда арендатор A запускает поток `tenant-a-prod`, а арендатор B запускает поток `tenant-b-prod`, они автоматически получают изолированные очереди:
|
||
`persistent://tg/flow/triples-store:tenant-a-prod`
|
||
`persistent://tg/flow/triples-store:tenant-b-prod`
|
||
|
||
**Сервисы, правильно разработанные для многоарендности:**
|
||
✅ **Knowledge Management (основные компоненты)** - Динамически определяет очереди из конфигурации потока, передаваемой в запросах
|
||
|
||
**Сервисы, требующие исправления:**
|
||
🔴 **Config Service** - Несоответствие имен параметров препятствует настройке очереди
|
||
🔴 **Librarian Service** - Жестко заданные темы управления хранилищем (описано ниже)
|
||
🔴 **Все сервисы** - Невозможно настроить пространство ключей Cassandra
|
||
|
||
## Описание проблемы
|
||
|
||
### Проблема #1: Несоответствие имен параметров в AsyncProcessor
|
||
**CLI определяет:** `--config-queue` (неясное наименование)
|
||
**Argparse преобразует в:** `config_queue` (в словаре параметров)
|
||
**Код ищет:** `config_push_queue`
|
||
**Результат:** Параметр игнорируется, используется значение по умолчанию `persistent://tg/config/config`
|
||
**Влияние:** Затрагивает все 32+ сервиса, наследующие от AsyncProcessor
|
||
**Препятствует:** Многоарендные развертывания не могут использовать очереди, специфичные для арендатора
|
||
**Решение:** Переименовать параметр CLI в `--config-push-queue` для ясности (разрыв обратной совместимости допустим, так как функция в настоящее время не работает)
|
||
|
||
### Проблема #2: Несоответствие имен параметров в Config Service
|
||
**CLI определяет:** `--push-queue` (двусмысленное наименование)
|
||
**Argparse преобразует в:** `push_queue` (в словаре параметров)
|
||
**Код ищет:** `config_push_queue`
|
||
**Результат:** Параметр игнорируется
|
||
**Влияние:** Сервис Config не может использовать пользовательскую очередь отправки
|
||
**Решение:** Переименовать параметр CLI в `--config-push-queue` для согласованности и ясности (разрыв обратной совместимости допустим)
|
||
|
||
### Проблема #3: Жестко заданное пространство ключей Cassandra
|
||
**Текущее состояние:** Пространство ключей жестко задано как `"config"`, `"knowledge"`, `"librarian"` в различных сервисах
|
||
**Результат:** Невозможно настроить пространство ключей для многоарендных развертываний
|
||
**Влияние:** Сервисы Config, основные компоненты и Librarian
|
||
**Препятствует:** Несколько арендаторов не могут использовать отдельные пространства ключей Cassandra
|
||
|
||
### Проблема #4: Архитектура управления коллекциями ✅ ВЫПОЛНЕНО
|
||
**Предыдущее состояние:** Коллекции хранились в пространстве ключей Cassandra Librarian через отдельную таблицу коллекций
|
||
**Предыдущее состояние:** Librarian использовал 4 жестко заданные темы управления хранилищем для координации создания/удаления коллекций:
|
||
`vector_storage_management_topic`
|
||
`object_storage_management_topic`
|
||
`triples_storage_management_topic`
|
||
`storage_management_response_topic`
|
||
**Проблемы (решены):**
|
||
Жестко заданные темы не могли быть настроены для многоарендных развертываний
|
||
Сложная асинхронная координация между Librarian и 4+ сервисами хранения
|
||
Отдельная таблица Cassandra и инфраструктура управления
|
||
Непостоянные очереди запросов/ответов для критических операций
|
||
**Решение реализовано:** Коллекции были перенесены в хранилище сервиса Config, используется отправка Config для распространения
|
||
**Статус:** Все хранилища были перенесены на шаблон `CollectionConfigHandler`
|
||
|
||
## Решение
|
||
|
||
Эта спецификация решает проблемы #1, #2, #3 и #4.
|
||
|
||
### Часть 1: Исправление несоответствий имен параметров
|
||
|
||
#### Изменение 1: Базовый класс AsyncProcessor - Переименование параметра CLI
|
||
**Файл:** `trustgraph-base/trustgraph/base/async_processor.py`
|
||
**Строка:** 260-264
|
||
|
||
**Текущее состояние:**
|
||
```python
|
||
parser.add_argument(
|
||
'--config-queue',
|
||
default=default_config_queue,
|
||
help=f'Config push queue {default_config_queue}',
|
||
)
|
||
```
|
||
|
||
**Исправлено:**
|
||
```python
|
||
parser.add_argument(
|
||
'--config-push-queue',
|
||
default=default_config_queue,
|
||
help=f'Config push queue (default: {default_config_queue})',
|
||
)
|
||
```
|
||
|
||
**Обоснование:**
|
||
Более понятное и явное наименование
|
||
Соответствует внутреннему имени переменной `config_push_queue`
|
||
Изменение, нарушающее обратную совместимость, допустимо, поскольку функция в настоящее время не функционирует
|
||
Не требуется изменение кода в params.get() - он уже ищет правильное имя
|
||
|
||
#### Изменение 2: Сервис конфигурации - Переименование параметра командной строки
|
||
**Файл:** `trustgraph-flow/trustgraph/config/service/service.py`
|
||
**Строка:** 276-279
|
||
|
||
**Текущее:**
|
||
```python
|
||
parser.add_argument(
|
||
'--push-queue',
|
||
default=default_config_push_queue,
|
||
help=f'Config push queue (default: {default_config_push_queue})'
|
||
)
|
||
```
|
||
|
||
**Исправлено:**
|
||
```python
|
||
parser.add_argument(
|
||
'--config-push-queue',
|
||
default=default_config_push_queue,
|
||
help=f'Config push queue (default: {default_config_push_queue})'
|
||
)
|
||
```
|
||
|
||
**Обоснование:**
|
||
Более понятное наименование - "config-push-queue" более явно, чем просто "push-queue".
|
||
Соответствует внутреннему имени переменной `config_push_queue`.
|
||
Соответствует параметру `--config-push-queue` класса AsyncProcessor.
|
||
Изменение, нарушающее обратную совместимость, допустимо, поскольку функция в настоящее время не работает.
|
||
Не требуется изменение кода в params.get() - он уже ищет правильное имя.
|
||
|
||
### Часть 2: Добавление параметризации пространства ключей Cassandra
|
||
|
||
#### Изменение 3: Добавление параметра пространства ключей в модуль cassandra_config
|
||
**Файл:** `trustgraph-base/trustgraph/base/cassandra_config.py`
|
||
|
||
**Добавление аргумента командной строки** (в функции `add_cassandra_args()`):
|
||
```python
|
||
parser.add_argument(
|
||
'--cassandra-keyspace',
|
||
default=None,
|
||
help='Cassandra keyspace (default: service-specific)'
|
||
)
|
||
```
|
||
|
||
**Добавить поддержку переменных окружения** (в функции `resolve_cassandra_config()`):
|
||
```python
|
||
keyspace = params.get(
|
||
"cassandra_keyspace",
|
||
os.environ.get("CASSANDRA_KEYSPACE")
|
||
)
|
||
```
|
||
|
||
**Обновить возвращаемое значение** `resolve_cassandra_config()`:
|
||
В настоящее время возвращает: `(hosts, username, password)`
|
||
Изменить, чтобы возвращалось: `(hosts, username, password, keyspace)`
|
||
|
||
**Обоснование:**
|
||
Соответствует существующей схеме конфигурации Cassandra
|
||
Доступно всем сервисам через `add_cassandra_args()`
|
||
Поддерживает конфигурацию как через командную строку, так и через переменные окружения
|
||
|
||
#### Изменение 4: Сервис конфигурации - Использование параметризованных пространств ключей
|
||
**Файл:** `trustgraph-flow/trustgraph/config/service/service.py`
|
||
|
||
**Строка 30** - Удалить жестко закодированное пространство ключей:
|
||
```python
|
||
# DELETE THIS LINE:
|
||
keyspace = "config"
|
||
```
|
||
|
||
**Строки 69-73** - Обновление разрешения конфигурации Cassandra:
|
||
|
||
**Текущая версия:**
|
||
```python
|
||
cassandra_host, cassandra_username, cassandra_password = \
|
||
resolve_cassandra_config(params)
|
||
```
|
||
|
||
**Исправлено:**
|
||
```python
|
||
cassandra_host, cassandra_username, cassandra_password, keyspace = \
|
||
resolve_cassandra_config(params, default_keyspace="config")
|
||
```
|
||
|
||
**Обоснование:**
|
||
Обеспечивает обратную совместимость с "config" в качестве значения по умолчанию.
|
||
Позволяет переопределить значение с помощью `--cassandra-keyspace` или `CASSANDRA_KEYSPACE`.
|
||
|
||
#### Изменение 5: Основные компоненты/Сервис знаний - Использование параметризованных пространств ключей.
|
||
**Файл:** `trustgraph-flow/trustgraph/cores/service.py`
|
||
|
||
**Строка 37** - Удалить жестко закодированное пространство ключей:
|
||
```python
|
||
# DELETE THIS LINE:
|
||
keyspace = "knowledge"
|
||
```
|
||
|
||
**Обновление разрешения конфигурации Cassandra** (в том же месте, что и служба конфигурации):
|
||
```python
|
||
cassandra_host, cassandra_username, cassandra_password, keyspace = \
|
||
resolve_cassandra_config(params, default_keyspace="knowledge")
|
||
```
|
||
|
||
#### Изменение 6: Сервис библиотекаря - Использование параметризованных пространств ключей.
|
||
**Файл:** `trustgraph-flow/trustgraph/librarian/service.py`
|
||
|
||
**Строка 51** - Удалить жестко закодированное пространство ключей:
|
||
```python
|
||
# DELETE THIS LINE:
|
||
keyspace = "librarian"
|
||
```
|
||
|
||
**Обновление разрешения конфигурации Cassandra** (в том же месте, что и служба конфигурации):
|
||
```python
|
||
cassandra_host, cassandra_username, cassandra_password, keyspace = \
|
||
resolve_cassandra_config(params, default_keyspace="librarian")
|
||
```
|
||
|
||
### Часть 3: Перенос управления коллекциями в службу конфигураций
|
||
|
||
#### Обзор
|
||
Перенесите коллекции из пространства ключей Cassandra librarian в хранилище службы конфигураций. Это устраняет жестко закодированные темы управления хранилищем и упрощает архитектуру, используя существующий механизм распространения конфигураций.
|
||
|
||
#### Текущая архитектура
|
||
```
|
||
API Request → Gateway → Librarian Service
|
||
↓
|
||
CollectionManager
|
||
↓
|
||
Cassandra Collections Table (librarian keyspace)
|
||
↓
|
||
Broadcast to 4 Storage Management Topics (hardcoded)
|
||
↓
|
||
Wait for 4+ Storage Service Responses
|
||
↓
|
||
Response to Gateway
|
||
```
|
||
|
||
#### Новая архитектура
|
||
```
|
||
API Request → Gateway → Librarian Service
|
||
↓
|
||
CollectionManager
|
||
↓
|
||
Config Service API (put/delete/getvalues)
|
||
↓
|
||
Cassandra Config Table (class='collections', key='user:collection')
|
||
↓
|
||
Config Push (to all subscribers on config-push-queue)
|
||
↓
|
||
All Storage Services receive config update independently
|
||
```
|
||
|
||
#### Изменение 7: Менеджер коллекций - Использование API сервиса конфигурации
|
||
**Файл:** `trustgraph-flow/trustgraph/librarian/collection_manager.py`
|
||
|
||
**Удалить:**
|
||
Использование `LibraryTableStore` (строки 33, 40-41)
|
||
Инициализация производителей управления хранилищем (строки 86-140)
|
||
Метод `on_storage_response` (строки 400-430)
|
||
Отслеживание `pending_deletions` (строки 57, 90-96 и использование во всем коде)
|
||
|
||
**Добавить:**
|
||
Клиент сервиса конфигурации для вызовов API (шаблон запрос/ответ)
|
||
|
||
**Настройка клиента конфигурации:**
|
||
```python
|
||
# In __init__, add config request/response producers/consumers
|
||
from trustgraph.schema.services.config import ConfigRequest, ConfigResponse
|
||
|
||
# Producer for config requests
|
||
self.config_request_producer = Producer(
|
||
client=pulsar_client,
|
||
topic=config_request_queue,
|
||
schema=ConfigRequest,
|
||
)
|
||
|
||
# Consumer for config responses (with correlation ID)
|
||
self.config_response_consumer = Consumer(
|
||
taskgroup=taskgroup,
|
||
client=pulsar_client,
|
||
flow=None,
|
||
topic=config_response_queue,
|
||
subscriber=f"{id}-config",
|
||
schema=ConfigResponse,
|
||
handler=self.on_config_response,
|
||
)
|
||
|
||
# Tracking for pending config requests
|
||
self.pending_config_requests = {} # request_id -> asyncio.Event
|
||
```
|
||
|
||
**Изменить `list_collections` (строки 145-180):**
|
||
```python
|
||
async def list_collections(self, user, tag_filter=None, limit=None):
|
||
"""List collections from config service"""
|
||
# Send getvalues request to config service
|
||
request = ConfigRequest(
|
||
id=str(uuid.uuid4()),
|
||
operation='getvalues',
|
||
type='collections',
|
||
)
|
||
|
||
# Send request and wait for response
|
||
response = await self.send_config_request(request)
|
||
|
||
# Parse collections from response
|
||
collections = []
|
||
for key, value_json in response.values.items():
|
||
if ":" in key:
|
||
coll_user, collection = key.split(":", 1)
|
||
if coll_user == user:
|
||
metadata = json.loads(value_json)
|
||
collections.append(CollectionMetadata(**metadata))
|
||
|
||
# Apply tag filtering in-memory (as before)
|
||
if tag_filter:
|
||
collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)]
|
||
|
||
# Apply limit
|
||
if limit:
|
||
collections = collections[:limit]
|
||
|
||
return collections
|
||
|
||
async def send_config_request(self, request):
|
||
"""Send config request and wait for response"""
|
||
event = asyncio.Event()
|
||
self.pending_config_requests[request.id] = event
|
||
|
||
await self.config_request_producer.send(request)
|
||
await event.wait()
|
||
|
||
return self.pending_config_requests.pop(request.id + "_response")
|
||
|
||
async def on_config_response(self, message, consumer, flow):
|
||
"""Handle config response"""
|
||
response = message.value()
|
||
if response.id in self.pending_config_requests:
|
||
self.pending_config_requests[response.id + "_response"] = response
|
||
self.pending_config_requests[response.id].set()
|
||
```
|
||
|
||
**Изменить `update_collection` (строки 182-312):**
|
||
```python
|
||
async def update_collection(self, user, collection, name, description, tags):
|
||
"""Update collection via config service"""
|
||
# Create metadata
|
||
metadata = CollectionMetadata(
|
||
user=user,
|
||
collection=collection,
|
||
name=name,
|
||
description=description,
|
||
tags=tags,
|
||
)
|
||
|
||
# Send put request to config service
|
||
request = ConfigRequest(
|
||
id=str(uuid.uuid4()),
|
||
operation='put',
|
||
type='collections',
|
||
key=f'{user}:{collection}',
|
||
value=json.dumps(metadata.to_dict()),
|
||
)
|
||
|
||
response = await self.send_config_request(request)
|
||
|
||
if response.error:
|
||
raise RuntimeError(f"Config update failed: {response.error.message}")
|
||
|
||
# Config service will trigger config push automatically
|
||
# Storage services will receive update and create collections
|
||
```
|
||
|
||
**Изменить `delete_collection` (строки 314-398):**
|
||
```python
|
||
async def delete_collection(self, user, collection):
|
||
"""Delete collection via config service"""
|
||
# Send delete request to config service
|
||
request = ConfigRequest(
|
||
id=str(uuid.uuid4()),
|
||
operation='delete',
|
||
type='collections',
|
||
key=f'{user}:{collection}',
|
||
)
|
||
|
||
response = await self.send_config_request(request)
|
||
|
||
if response.error:
|
||
raise RuntimeError(f"Config delete failed: {response.error.message}")
|
||
|
||
# Config service will trigger config push automatically
|
||
# Storage services will receive update and delete collections
|
||
```
|
||
|
||
**Формат метаданных коллекции:**
|
||
Хранится в таблице конфигурации как: `class='collections', key='user:collection'`
|
||
Значение является JSON-сериализованным объектом CollectionMetadata (без полей времени).
|
||
Поля: `user`, `collection`, `name`, `description`, `tags`
|
||
Пример: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'`
|
||
|
||
#### Изменение 8: Сервис Librarian - Удаление инфраструктуры управления хранилищем
|
||
**Файл:** `trustgraph-flow/trustgraph/librarian/service.py`
|
||
|
||
**Удалить:**
|
||
Модули-производители управления хранилищем (строки 173-190):
|
||
`vector_storage_management_producer`
|
||
`object_storage_management_producer`
|
||
`triples_storage_management_producer`
|
||
Потребитель ответов хранилища (строки 192-201)
|
||
Обработчик `on_storage_response` (строки 467-473)
|
||
|
||
**Изменить:**
|
||
Инициализация CollectionManager (строки 215-224) - удалить параметры модуля-производителя хранилища
|
||
|
||
**Примечание:** Внешний API для коллекций остается неизменным:
|
||
`list-collections`
|
||
`update-collection`
|
||
`delete-collection`
|
||
|
||
#### Изменение 9: Удаление таблицы Collections из LibraryTableStore
|
||
**Файл:** `trustgraph-flow/trustgraph/tables/library.py`
|
||
|
||
**Удалить:**
|
||
Оператор CREATE для таблицы Collections (строки 114-127)
|
||
Подготовленные операторы для Collections (строки 205-240)
|
||
Все методы для работы с коллекциями (строки 578-717):
|
||
`ensure_collection_exists`
|
||
`list_collections`
|
||
`update_collection`
|
||
`delete_collection`
|
||
`get_collection`
|
||
`create_collection`
|
||
|
||
**Обоснование:**
|
||
Коллекции теперь хранятся в таблице конфигурации.
|
||
Изменение, требующее обновления, приемлемо - миграция данных не требуется.
|
||
Значительно упрощает сервис Librarian.
|
||
|
||
#### Изменение 10: Сервисы хранения - Управление коллекциями на основе конфигурации ✅ ВЫПОЛНЕНО
|
||
|
||
**Статус:** Все 11 хранилищ были перенесены на использование `CollectionConfigHandler`.
|
||
|
||
**Затронутые сервисы (всего 11):**
|
||
Векторные представления документов: milvus, pinecone, qdrant
|
||
Векторные представления графов: milvus, pinecone, qdrant
|
||
Объектное хранилище: cassandra
|
||
Хранилище троек: cassandra, falkordb, memgraph, neo4j
|
||
|
||
**Файлы:**
|
||
`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py`
|
||
`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py`
|
||
`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py`
|
||
`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py`
|
||
`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py`
|
||
`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py`
|
||
`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py`
|
||
`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`
|
||
`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py`
|
||
`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py`
|
||
`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py`
|
||
|
||
**Шаблон реализации (для всех сервисов):**
|
||
|
||
1. **Зарегистрировать обработчик конфигурации в `__init__`:**
|
||
```python
|
||
# Add after AsyncProcessor initialization
|
||
self.register_config_handler(self.on_collection_config)
|
||
self.known_collections = set() # Track (user, collection) tuples
|
||
```
|
||
|
||
2. **Реализовать обработчик конфигурации:**
|
||
```python
|
||
async def on_collection_config(self, config, version):
|
||
"""Handle collection configuration updates"""
|
||
logger.info(f"Collection config version: {version}")
|
||
|
||
if "collections" not in config:
|
||
return
|
||
|
||
# Parse collections from config
|
||
# Key format: "user:collection" in config["collections"]
|
||
config_collections = set()
|
||
for key in config["collections"].keys():
|
||
if ":" in key:
|
||
user, collection = key.split(":", 1)
|
||
config_collections.add((user, collection))
|
||
|
||
# Determine changes
|
||
to_create = config_collections - self.known_collections
|
||
to_delete = self.known_collections - config_collections
|
||
|
||
# Create new collections (idempotent)
|
||
for user, collection in to_create:
|
||
try:
|
||
await self.create_collection_internal(user, collection)
|
||
self.known_collections.add((user, collection))
|
||
logger.info(f"Created collection: {user}/{collection}")
|
||
except Exception as e:
|
||
logger.error(f"Failed to create {user}/{collection}: {e}")
|
||
|
||
# Delete removed collections (idempotent)
|
||
for user, collection in to_delete:
|
||
try:
|
||
await self.delete_collection_internal(user, collection)
|
||
self.known_collections.discard((user, collection))
|
||
logger.info(f"Deleted collection: {user}/{collection}")
|
||
except Exception as e:
|
||
logger.error(f"Failed to delete {user}/{collection}: {e}")
|
||
```
|
||
|
||
3. **Инициализация известных коллекций при запуске:**
|
||
```python
|
||
async def start(self):
|
||
"""Start the processor"""
|
||
await super().start()
|
||
await self.sync_known_collections()
|
||
|
||
async def sync_known_collections(self):
|
||
"""Query backend to populate known_collections set"""
|
||
# Backend-specific implementation:
|
||
# - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern
|
||
# - Cassandra: Query keyspaces or collection metadata
|
||
# - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes
|
||
pass
|
||
```
|
||
|
||
4. **Рефакторинг существующих методов обработчиков:**
|
||
```python
|
||
# Rename and remove response sending:
|
||
# handle_create_collection → create_collection_internal
|
||
# handle_delete_collection → delete_collection_internal
|
||
|
||
async def create_collection_internal(self, user, collection):
|
||
"""Create collection (idempotent)"""
|
||
# Same logic as current handle_create_collection
|
||
# But remove response producer calls
|
||
# Handle "already exists" gracefully
|
||
pass
|
||
|
||
async def delete_collection_internal(self, user, collection):
|
||
"""Delete collection (idempotent)"""
|
||
# Same logic as current handle_delete_collection
|
||
# But remove response producer calls
|
||
# Handle "not found" gracefully
|
||
pass
|
||
```
|
||
|
||
5. **Удаление инфраструктуры управления хранилищем:**
|
||
Удалить настройку и запуск `self.storage_request_consumer`
|
||
Удалить настройку `self.storage_response_producer`
|
||
Удалить метод диспетчера `on_storage_management`
|
||
Удалить метрики для управления хранилищем
|
||
Удалить импорты: `StorageManagementRequest`, `StorageManagementResponse`
|
||
|
||
**Особенности, специфичные для бэкенда:**
|
||
|
||
**Векторные хранилища (Milvus, Pinecone, Qdrant):** Отслеживать логическую `(user, collection)` в `known_collections`, но может создавать несколько бэкенд-коллекций для каждой размерности. Продолжить использование ленивой схемы создания. Операции удаления должны удалять все варианты размерностей.
|
||
|
||
**Объекты Cassandra:** Коллекции являются свойствами строк, а не структурами. Отслеживать информацию на уровне пространства ключей.
|
||
|
||
**Графовые хранилища (Neo4j, Memgraph, FalkorDB):** Запрашивать узлы `CollectionMetadata` при запуске. Создавать/удалять метаданные узлов при синхронизации.
|
||
|
||
**Тройки Cassandra:** Использовать API `KnowledgeGraph` для операций с коллекциями.
|
||
|
||
**Основные принципы проектирования:**
|
||
|
||
**Итоговая согласованность:** Отсутствует механизм запрос/ответ, конфигурация распространяется широковещанием.
|
||
**Идемпотентность:** Все операции создания/удаления должны быть безопасными для повторной попытки.
|
||
**Обработка ошибок:** Регистрировать ошибки, но не блокировать обновления конфигурации.
|
||
**Самовосстановление:** Неудачные операции будут повторены при следующем распространении конфигурации.
|
||
**Формат ключа коллекции:** `"user:collection"` в `config["collections"]`
|
||
|
||
#### Изменение 11: Обновление схемы коллекции - Удаление временных меток
|
||
**Файл:** `trustgraph-base/trustgraph/schema/services/collection.py`
|
||
|
||
**Изменить CollectionMetadata (строки 13-21):**
|
||
Удалить поля `created_at` и `updated_at`:
|
||
```python
|
||
class CollectionMetadata(Record):
|
||
user = String()
|
||
collection = String()
|
||
name = String()
|
||
description = String()
|
||
tags = Array(String())
|
||
# Remove: created_at = String()
|
||
# Remove: updated_at = String()
|
||
```
|
||
|
||
**Изменить класс CollectionManagementRequest (строки 25-47):**
|
||
Удалить поля временной метки:
|
||
```python
|
||
class CollectionManagementRequest(Record):
|
||
operation = String()
|
||
user = String()
|
||
collection = String()
|
||
timestamp = String()
|
||
name = String()
|
||
description = String()
|
||
tags = Array(String())
|
||
# Remove: created_at = String()
|
||
# Remove: updated_at = String()
|
||
tag_filter = Array(String())
|
||
limit = Integer()
|
||
```
|
||
|
||
**Обоснование:**
|
||
Временные метки не добавляют ценности для коллекций.
|
||
Сервис конфигурации самостоятельно отслеживает версии.
|
||
Упрощает схему и уменьшает объем хранения.
|
||
|
||
#### Преимущества миграции на сервис конфигурации
|
||
|
||
1. ✅ **Устраняет жестко закодированные темы управления хранилищем** - Решает проблему многопользовательской среды.
|
||
2. ✅ **Более простая координация** - Нет сложного асинхронного ожидания ответов от 4+ хранилищ.
|
||
3. ✅ **В конечном итоге согласованность** - Сервисы хранения обновляются независимо с помощью push-конфигурации.
|
||
4. ✅ **Более высокая надежность** - Постоянная push-конфигурация против неперсистентного запроса/ответа.
|
||
5. ✅ **Унифицированная модель конфигурации** - Коллекции рассматриваются как конфигурация.
|
||
6. ✅ **Уменьшает сложность** - Удаляет около 300 строк кода для координации.
|
||
7. ✅ **Готовность к многопользовательской среде** - Конфигурация уже поддерживает изоляцию пользователей с помощью пространств ключей.
|
||
8. ✅ **Отслеживание версий** - Механизм версионирования сервиса конфигурации обеспечивает аудит.
|
||
|
||
## Замечания по реализации
|
||
|
||
### Обратная совместимость
|
||
|
||
**Изменения параметров:**
|
||
Переименование параметров командной строки является серьезным изменением, но допустимо (функция в настоящее время не работает).
|
||
Сервисы работают без параметров (используются значения по умолчанию).
|
||
Значения по умолчанию для пространств ключей сохранены: "config", "knowledge", "librarian".
|
||
Значение по умолчанию для очереди: `persistent://tg/config/config`
|
||
|
||
**Управление коллекциями:**
|
||
**Серьезное изменение:** Таблица коллекций удалена из пространства ключей librarian.
|
||
**Миграция данных не предусмотрена** - приемлемо для этой фазы.
|
||
Внешний API для коллекций не изменен (операции list/update/delete).
|
||
Формат метаданных коллекций упрощен (временные метки удалены).
|
||
|
||
### Требования к тестированию
|
||
|
||
**Тестирование параметров:**
|
||
1. Проверить, работает ли параметр `--config-push-queue` для сервиса graph-embeddings.
|
||
2. Проверить, работает ли параметр `--config-push-queue` для сервиса text-completion.
|
||
3. Проверить, работает ли параметр `--config-push-queue` для сервиса конфигурации.
|
||
4. Проверить, работает ли параметр `--cassandra-keyspace` для сервиса конфигурации.
|
||
5. Проверить, работает ли параметр `--cassandra-keyspace` для сервиса cores.
|
||
6. Проверить, работает ли параметр `--cassandra-keyspace` для сервиса librarian.
|
||
7. Проверить, работают ли сервисы без параметров (используются значения по умолчанию).
|
||
8. Проверить развертывание в многопользовательской среде с использованием пользовательских имен очередей и пространств ключей.
|
||
|
||
**Тестирование управления коллекциями:**
|
||
9. Проверить операцию `list-collections` через сервис конфигурации.
|
||
10. Проверить, создает ли `update-collection` записи/обновления в таблице конфигурации.
|
||
11. Проверить, удаляет ли `delete-collection` записи из таблицы конфигурации.
|
||
12. Проверить, запускается ли push-конфигурации при обновлениях коллекций.
|
||
13. Проверить, работает ли фильтрация по тегам с использованием хранилища на основе конфигурации.
|
||
14. Проверить, работают ли операции с коллекциями без полей временных меток.
|
||
|
||
### Пример развертывания в многопользовательской среде
|
||
```bash
|
||
# Tenant: tg-dev
|
||
graph-embeddings \
|
||
-p pulsar+ssl://broker:6651 \
|
||
--pulsar-api-key <KEY> \
|
||
--config-push-queue persistent://tg-dev/config/config
|
||
|
||
config-service \
|
||
-p pulsar+ssl://broker:6651 \
|
||
--pulsar-api-key <KEY> \
|
||
--config-push-queue persistent://tg-dev/config/config \
|
||
--cassandra-keyspace tg_dev_config
|
||
```
|
||
|
||
## Анализ влияния
|
||
|
||
### Сервисы, затронутые изменением 1-2 (Переименование параметра CLI)
|
||
Все сервисы, наследующие AsyncProcessor или FlowProcessor:
|
||
config-service
|
||
cores-service
|
||
librarian-service
|
||
graph-embeddings
|
||
document-embeddings
|
||
text-completion-* (все провайдеры)
|
||
extract-* (все экстракторы)
|
||
query-* (все сервисы запросов)
|
||
retrieval-* (все сервисы RAG)
|
||
storage-* (все сервисы хранения)
|
||
И еще 20+ сервисов
|
||
|
||
### Сервисы, затронутые изменениями 3-6 (Keyspace Cassandra)
|
||
config-service
|
||
cores-service
|
||
librarian-service
|
||
|
||
### Сервисы, затронутые изменениями 7-11 (Управление коллекциями)
|
||
|
||
**Немедленные изменения:**
|
||
librarian-service (collection_manager.py, service.py)
|
||
tables/library.py (удаление таблицы collections)
|
||
schema/services/collection.py (удаление метки времени)
|
||
|
||
**Выполненные изменения (изменение 10):** ✅
|
||
Все сервисы хранения (всего 11) - перенесены на push-конфигурацию для обновлений коллекций через `CollectionConfigHandler`
|
||
Схема управления хранилищем удалена из `storage.py`
|
||
|
||
## Будущие соображения
|
||
|
||
### Модель keyspace на уровне пользователя
|
||
|
||
Некоторые сервисы динамически используют **keyspace на уровне пользователя**, когда каждый пользователь получает свой собственный keyspace Cassandra:
|
||
|
||
**Сервисы с keyspace на уровне пользователя:**
|
||
1. **Сервис запросов Triple** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`)
|
||
Использует `keyspace=query.user`
|
||
2. **Сервис запросов объектов** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`)
|
||
Использует `keyspace=self.sanitize_name(user)`
|
||
3. **Прямой доступ к графу знаний** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`)
|
||
Параметр по умолчанию `keyspace="trustgraph"`
|
||
|
||
**Статус:** Эти параметры **не изменяются** в этой спецификации.
|
||
|
||
**Требуется дальнейший анализ:**
|
||
Оценить, создает ли модель keyspace на уровне пользователя проблемы изоляции арендаторов
|
||
Рассмотреть, нужны ли многопользовательским развертываниям префиксы keyspace (например, `tenant_a_user1`)
|
||
Проверить на потенциальные конфликты идентификаторов пользователей между арендаторами
|
||
Оценить, является ли единый общий keyspace на арендатора с изоляцией строк на уровне пользователя более предпочтительным
|
||
|
||
**Примечание:** Это не блокирует текущую многопользовательскую реализацию, но должно быть рассмотрено перед производственными многопользовательскими развертываниями.
|
||
|
||
## Этапы реализации
|
||
|
||
### Этап 1: Исправление параметров (изменения 1-6)
|
||
Исправить именование параметра `--config-push-queue`
|
||
Добавить поддержку параметра `--cassandra-keyspace`
|
||
**Результат:** Многопользовательская очередь и конфигурация keyspace включены
|
||
|
||
### Этап 2: Миграция управления коллекциями (изменения 7-9, 11)
|
||
Перенести хранение коллекций в сервис конфигурации
|
||
Удалить таблицу collections из librarian
|
||
Обновить схему коллекций (удалить метки времени)
|
||
**Результат:** Устраняет жестко закодированные темы управления хранилищем, упрощает librarian
|
||
|
||
### Этап 3: Обновления сервисов хранения (изменение 10) ✅ ВЫПОЛНЕНО
|
||
Обновлены все сервисы хранения для использования push-конфигурации для коллекций через `CollectionConfigHandler`
|
||
Удалена инфраструктура запросов/ответов управления хранилищем
|
||
Удалены устаревшие определения схемы
|
||
**Результат:** Достигнуто полное управление коллекциями на основе конфигурации
|
||
|
||
## Ссылки
|
||
GitHub Issue: https://github.com/trustgraph-ai/trustgraph/issues/582
|
||
Связанные файлы:
|
||
`trustgraph-base/trustgraph/base/async_processor.py`
|
||
`trustgraph-base/trustgraph/base/cassandra_config.py`
|
||
`trustgraph-base/trustgraph/schema/core/topic.py`
|
||
`trustgraph-base/trustgraph/schema/services/collection.py`
|
||
`trustgraph-flow/trustgraph/config/service/service.py`
|
||
`trustgraph-flow/trustgraph/cores/service.py`
|
||
`trustgraph-flow/trustgraph/librarian/service.py`
|
||
`trustgraph-flow/trustgraph/librarian/collection_manager.py`
|
||
`trustgraph-flow/trustgraph/tables/library.py`
|